#include <sys/mman.h>
#include <sys/time.h>
+#include <mach/thread_policy.h>
+#include <mach/thread_act.h>
+
#include <glibmm.h>
#include "coreaudio_backend.h"
pthread_mutex_init (&_freewheel_mutex, 0);
pthread_cond_init (&_freewheel_signal, 0);
+ _port_connection_queue.reserve (128);
+
_pcmio = new CoreAudioPCM ();
_midiio = new CoreMidiIo ();
std::vector<float> sr_in;
std::vector<float> sr_out;
- const uint32_t inp = name_to_id (input_device);
- const uint32_t out = name_to_id (output_device);
+ const uint32_t inp = name_to_id (input_device, Input);
+ const uint32_t out = name_to_id (output_device, Output);
if (inp == UINT32_MAX && out == UINT32_MAX) {
return sr;
std::vector<uint32_t> bs;
std::vector<uint32_t> bs_in;
std::vector<uint32_t> bs_out;
- const uint32_t inp = name_to_id (input_device);
- const uint32_t out = name_to_id (output_device);
+ const uint32_t inp = name_to_id (input_device, Input);
+ const uint32_t out = name_to_id (output_device, Output);
if (inp == UINT32_MAX && out == UINT32_MAX) {
return bs;
} else if (inp == UINT32_MAX) {
CoreAudioBackend::set_input_device_name (const std::string& d)
{
_input_audio_device = d;
- const float sr = _pcmio->current_sample_rate(name_to_id(_input_audio_device));
+ const float sr = _pcmio->current_sample_rate(name_to_id(_input_audio_device, Input));
if (sr > 0) { set_sample_rate(sr); }
return 0;
}
{
_output_audio_device = d;
// TODO check SR.
- const float sr = _pcmio->current_sample_rate(name_to_id(_output_audio_device));
+ const float sr = _pcmio->current_sample_rate(name_to_id(_output_audio_device, Output));
if (sr > 0) { set_sample_rate(sr); }
return 0;
}
}
_samples_per_period = bs;
_pcmio->set_samples_per_period(bs);
+ if (_run) {
+ coreaudio_set_realtime_policy (_main_thread);
+ }
+ for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i) {
+ coreaudio_set_realtime_policy (*i);
+ }
engine.buffer_size_change (bs);
return 0;
}
CoreAudioBackend::launch_control_app ()
{
if (name_to_id (_input_audio_device) != UINT32_MAX) {
- _pcmio->launch_control_app(name_to_id(_input_audio_device));
+ _pcmio->launch_control_app(name_to_id(_input_audio_device, Input));
}
if (name_to_id (_output_audio_device) != UINT32_MAX) {
- _pcmio->launch_control_app(name_to_id(_output_audio_device));
+ _pcmio->launch_control_app(name_to_id(_output_audio_device, Output));
}
}
_portmap.clear();
}
- uint32_t device1 = name_to_id(_input_audio_device);
- uint32_t device2 = name_to_id(_output_audio_device);
+ uint32_t device1 = name_to_id(_input_audio_device, Input);
+ uint32_t device2 = name_to_id(_output_audio_device, Output);
assert(_active_ca == false);
assert(_active_fw == false);
PBD::info << _("CoreAudioBackend: adjusted input channel count to match device.") << endmsg;
}
- if (_pcmio->samples_per_period() != _samples_per_period) {
- _samples_per_period = _pcmio->samples_per_period();
- PBD::warning << _("CoreAudioBackend: samples per period does not match.") << endmsg;
- }
-
if (_pcmio->sample_rate() != _samplerate) {
_samplerate = _pcmio->sample_rate();
engine.sample_rate_change (_samplerate);
}
uint32_t
-CoreAudioBackend::name_to_id(std::string device_name) const {
+CoreAudioBackend::name_to_id(std::string device_name, DeviceFilter filter) const {
uint32_t device_id = UINT32_MAX;
std::map<size_t, std::string> devices;
- _pcmio->device_list(devices);
+ switch (filter) {
+ case Input:
+ _pcmio->input_device_list (devices);
+ break;
+ case Output:
+ _pcmio->output_device_list (devices);
+ break;
+ case Duplex:
+ _pcmio->duplex_device_list (devices);
+ break;
+ case All:
+ default:
+ _pcmio->device_list (devices);
+ break;
+ }
for (std::map<size_t, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
if (i->second == device_name) {
return 0;
}
+bool
+CoreAudioBackend::coreaudio_set_realtime_policy (pthread_t thread_id) const
+{
+ thread_time_constraint_policy_data_t policy;
+#ifndef NDEBUG
+ mach_msg_type_number_t msgt = 4;
+ boolean_t dflt = false;
+ kern_return_t rv = thread_policy_get (pthread_mach_thread_np (_main_thread),
+ THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t) &policy,
+ &msgt, &dflt);
+ printf ("Coreaudio Main Thread(%p) %d %d %d %d DFLT %d OK: %d\n", _main_thread, policy.period, policy.computation, policy.constraint, policy.preemptible, dflt, rv == KERN_SUCCESS);
+#endif
+
+ double period_ns = 1e9 * _samples_per_period / _samplerate;
+ policy.period = AudioConvertNanosToHostTime (period_ns);
+ policy.computation = AudioConvertNanosToHostTime (period_ns * .9);
+ policy.constraint = AudioConvertNanosToHostTime (period_ns * .95);
+ policy.preemptible = true;
+ kern_return_t res = thread_policy_set (pthread_mach_thread_np (thread_id),
+ THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t) &policy,
+ THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+
+#ifndef NDEBUG
+ printf ("Coreaudio Proc Thread(%p) %d %d %d %d OK: %d\n", thread_id, policy.period, policy.computation, policy.constraint, policy.preemptible, res == KERN_SUCCESS);
+#endif
+ return res != KERN_SUCCESS;
+}
+
int
CoreAudioBackend::create_process_thread (boost::function<void()> func)
{
ThreadData* td = new ThreadData (this, func, stacksize);
- if (_realtime_pthread_create (SCHED_FIFO, -21, stacksize,
+ if (_realtime_pthread_create (SCHED_FIFO, -22, stacksize,
&thread_id, coreaudio_process_thread, td)) {
pthread_attr_init (&attr);
pthread_attr_setstacksize (&attr, stacksize);
pthread_attr_destroy (&attr);
}
+ if (coreaudio_set_realtime_policy (thread_id)) {
+ PBD::warning << _("AudioEngine: process thread failed to set mach realtime policy.") << endmsg;
+ }
+
_threads.push_back (thread_id);
return 0;
}
const uint32_t a_ins = _n_inputs;
const uint32_t a_out = _n_outputs;
- const uint32_t coreaudio_reported_input_latency = _pcmio->get_latency(name_to_id(_input_audio_device), true);
- const uint32_t coreaudio_reported_output_latency = _pcmio->get_latency(name_to_id(_output_audio_device), false);
+ const uint32_t coreaudio_reported_input_latency = _pcmio->get_latency(name_to_id(_input_audio_device, Input), true);
+ const uint32_t coreaudio_reported_output_latency = _pcmio->get_latency(name_to_id(_output_audio_device, Output), false);
#ifndef NDEBUG
printf("COREAUDIO LATENCY: i:%d, o:%d\n",
int
CoreAudioBackend::midi_event_get (
pframes_t& timestamp,
- size_t& size, uint8_t** buf, void* port_buffer,
+ size_t& size, uint8_t const** buf, void* port_buffer,
uint32_t event_index)
{
if (!buf || !port_buffer) return -1;
if (event_index >= source.size ()) {
return -1;
}
- CoreMidiEvent * const event = source[event_index].get ();
+ CoreMidiEvent const& event = source[event_index].get ();
- timestamp = event->timestamp ();
- size = event->size ();
- *buf = event->data ();
+ timestamp = event.timestamp ();
+ size = event.size ();
+ *buf = event.data ();
return 0;
}
const uint8_t* buffer, size_t size)
{
if (!buffer || !port_buffer) return -1;
+ if (size >= MaxCoreMidiEventSize) {
+ return -1;
+ }
CoreMidiBuffer& dst = * static_cast<CoreMidiBuffer*>(port_buffer);
- if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) {
#ifndef NDEBUG
+ if (dst.size () && (pframes_t)dst.back ().timestamp () > timestamp) {
// nevermind, ::get_buffer() sorts events
fprintf (stderr, "CoreMidiBuffer: unordered event: %d > %d\n",
- (pframes_t)dst.back ()->timestamp (), timestamp);
-#endif
+ (pframes_t)dst.back ().timestamp (), timestamp);
}
- dst.push_back (boost::shared_ptr<CoreMidiEvent>(new CoreMidiEvent (timestamp, buffer, size)));
+#endif
+ dst.push_back (CoreMidiEvent (timestamp, buffer, size));
return 0;
}
void*
CoreAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
{
- if (!port || !valid_port (port)) return NULL;
+ assert (port);
+ assert (valid_port (port));
+ if (!port || !valid_port (port)) return NULL; // XXX remove me
return static_cast<CoreBackendPort*>(port)->get_buffer (nframes);
}
AudioEngine::thread_init_callback (this);
_midiio->set_enabled(false);
reset_midi_parsers ();
+ coreaudio_set_realtime_policy (_main_thread);
}
// process port updates first in every cycle.
_reinit_thread_callback = false;
_main_thread = pthread_self();
AudioEngine::thread_init_callback (this);
+ coreaudio_set_realtime_policy (_main_thread);
}
if (pthread_mutex_trylock (&_process_callback_mutex)) {
continue;
}
uint64_t time_ns;
- uint8_t data[128]; // matches CoreMidi's MIDIPacket
+ uint8_t data[MaxCoreMidiEventSize];
size_t size = sizeof(data);
port->clear_events ();
/* queue outgoing midi */
i = 0;
for (std::vector<CoreBackendPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) {
-#if 0 // something's still b0rked with CoreMidiIo::send_events()
- const CoreMidiBuffer *src = static_cast<const CoreMidiPort*>(*it)->const_buffer();
- _midiio->send_events (i, nominal_time, (void*)src);
-#else // works..
const CoreMidiBuffer *src = static_cast<const CoreMidiPort*>(*it)->const_buffer();
for (CoreMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) {
- _midiio->send_event (i, (*mit)->timestamp() / nominal_time, (*mit)->data(), (*mit)->size());
+ _midiio->send_event (i,tamp (), mit->data (), mit->size ());
}
-#endif
}
/* write back audio */
{
_buffer[0].clear ();
_buffer[1].clear ();
+
+ _buffer[0].reserve (256);
+ _buffer[1].reserve (256);
}
CoreMidiPort::~CoreMidiPort () { }
struct MidiEventSorter {
- bool operator() (const boost::shared_ptr<CoreMidiEvent>& a, const boost::shared_ptr<CoreMidiEvent>& b) {
- return *a < *b;
+ bool operator() (CoreMidiEvent const& a, CoreMidiEvent const& b) {
+ return a < b;
}
};
++i) {
const CoreMidiBuffer * src = static_cast<const CoreMidiPort*>(*i)->const_buffer ();
for (CoreMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) {
- (_buffer[_bufperiod]).push_back (boost::shared_ptr<CoreMidiEvent>(new CoreMidiEvent (**it)));
+ (_buffer[_bufperiod]).push_back (*it);
}
}
- std::sort ((_buffer[_bufperiod]).begin (), (_buffer[_bufperiod]).end (), MidiEventSorter());
+ std::stable_sort ((_buffer[_bufperiod]).begin (), (_buffer[_bufperiod]).end (), MidiEventSorter());
}
return &(_buffer[_bufperiod]);
CoreMidiEvent::CoreMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
: _size (size)
, _timestamp (timestamp)
- , _data (0)
{
- if (size > 0) {
- _data = (uint8_t*) malloc (size);
+ if (size > 0 && size < MaxCoreMidiEventSize) {
memcpy (_data, data, size);
}
}
CoreMidiEvent::CoreMidiEvent (const CoreMidiEvent& other)
: _size (other.size ())
, _timestamp (other.timestamp ())
- , _data (0)
{
- if (other.size () && other.const_data ()) {
- _data = (uint8_t*) malloc (other.size ());
- memcpy (_data, other.const_data (), other.size ());
+ if (other._size > 0) {
+ assert (other._size < MaxCoreMidiEventSize);
+ memcpy (_data, other._data, other._size);
}
};
-
-CoreMidiEvent::~CoreMidiEvent () {
- free (_data);
-};