backends: jack: display playback only devices
[ardour.git] / libs / backends / coreaudio / coreaudio_backend.cc
index 7137b1d65a4927ae9a2fb5fc79fbbb7e37a2b204..f9dd15ea8dee9d5be9878cf20abaa2a96f8c2811 100644 (file)
@@ -21,6 +21,9 @@
 #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"
@@ -111,6 +114,8 @@ CoreAudioBackend::CoreAudioBackend (AudioEngine& e, AudioBackendInfo& info)
        pthread_mutex_init (&_freewheel_mutex, 0);
        pthread_cond_init  (&_freewheel_signal, 0);
 
+       _port_connection_queue.reserve (128);
+
        _pcmio = new CoreAudioPCM ();
        _midiio = new CoreMidiIo ();
 
@@ -327,7 +332,13 @@ CoreAudioBackend::set_buffer_size (uint32_t bs)
        }
        _samples_per_period = bs;
        _pcmio->set_samples_per_period(bs);
-       engine.buffer_size_change (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;
 }
 
@@ -603,11 +614,6 @@ CoreAudioBackend::_start (bool for_latency_measurement)
                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);
@@ -816,6 +822,34 @@ CoreAudioBackend::coreaudio_process_thread (void *arg)
        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)
 {
@@ -825,7 +859,7 @@ 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);
@@ -838,6 +872,10 @@ CoreAudioBackend::create_process_thread (boost::function<void()> func)
                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;
 }
@@ -1371,7 +1409,7 @@ CoreAudioBackend::get_connections (PortEngine::PortHandle port, std::vector<std:
 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;
@@ -1379,11 +1417,11 @@ CoreAudioBackend::midi_event_get (
        if (event_index >= source.size ()) {
                return -1;
        }
-       CoreMidiEvent * const event = source[event_index].get ();
+       CoreMidiEvent const& event = source[event_index];
 
-       timestamp = event->timestamp ();
-       size = event->size ();
-       *buf = event->data ();
+       timestamp = event.timestamp ();
+       size = event.size ();
+       *buf = event.data ();
        return 0;
 }
 
@@ -1394,15 +1432,18 @@ CoreAudioBackend::_midi_event_put (
        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;
 }
 
@@ -1673,6 +1714,7 @@ CoreAudioBackend::freewheel_thread ()
                        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.
@@ -1738,6 +1780,7 @@ CoreAudioBackend::process_callback (const uint32_t n_samples, const uint64_t hos
                _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)) {
@@ -1764,7 +1807,7 @@ CoreAudioBackend::process_callback (const uint32_t n_samples, const uint64_t hos
                        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 ();
@@ -1807,15 +1850,10 @@ CoreAudioBackend::process_callback (const uint32_t n_samples, const uint64_t hos
        /* 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, mit->timestamp (), mit->data (), mit->size ());
                }
-#endif
        }
 
        /* write back audio */
@@ -2121,13 +2159,16 @@ CoreMidiPort::CoreMidiPort (CoreAudioBackend &b, const std::string& name, PortFl
 {
        _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;
        }
 };
 
@@ -2141,7 +2182,7 @@ void* CoreMidiPort::get_buffer (pframes_t /* nframes */)
                     ++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::stable_sort ((_buffer[_bufperiod]).begin (), (_buffer[_bufperiod]).end (), MidiEventSorter());
@@ -2310,10 +2351,8 @@ CoreMidiPort::process_byte(const uint64_t time, const uint8_t byte)
 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);
        }
 }
@@ -2321,14 +2360,9 @@ CoreMidiEvent::CoreMidiEvent (const pframes_t timestamp, const uint8_t* data, si
 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);
-};