Merge pull request #4314 from MartijnKaijser/beta1
[vuplus_xbmc] / xbmc / cores / AudioEngine / Sinks / AESinkDARWINOSX.cpp
1 /*
2  *      Copyright (C) 2005-2014 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "cores/AudioEngine/AEFactory.h"
22 #include "cores/AudioEngine/Sinks/AESinkDARWINOSX.h"
23 #include "cores/AudioEngine/Utils/AEUtil.h"
24 #include "cores/AudioEngine/Utils/AERingBuffer.h"
25 #include "cores/AudioEngine/Sinks/osx/CoreAudioHelpers.h"
26 #include "cores/AudioEngine/Sinks/osx/CoreAudioHardware.h"
27 #include "osx/DarwinUtils.h"
28 #include "utils/log.h"
29 #include "utils/StringUtils.h"
30 #include "threads/Condition.h"
31 #include "threads/CriticalSection.h"
32
33 #include <sstream>
34
35 #define CA_MAX_CHANNELS 8
36 static enum AEChannel CAChannelMap[CA_MAX_CHANNELS + 1] = {
37   AE_CH_FL , AE_CH_FR , AE_CH_BL , AE_CH_BR , AE_CH_FC , AE_CH_LFE , AE_CH_SL , AE_CH_SR ,
38   AE_CH_NULL
39 };
40
41 static bool HasSampleRate(const AESampleRateList &list, const unsigned int samplerate)
42 {
43   for (size_t i = 0; i < list.size(); ++i)
44   {
45     if (list[i] == samplerate)
46       return true;
47   }
48   return false;
49 }
50
51 static bool HasDataFormat(const AEDataFormatList &list, const enum AEDataFormat format)
52 {
53   for (size_t i = 0; i < list.size(); ++i)
54   {
55     if (list[i] == format)
56       return true;
57   }
58   return false;
59 }
60
61 typedef std::vector< std::pair<AudioDeviceID, CAEDeviceInfo> > CADeviceList;
62
63 static void EnumerateDevices(CADeviceList &list)
64 {
65   CAEDeviceInfo device;
66
67   std::string defaultDeviceName;
68   CCoreAudioHardware::GetOutputDeviceName(defaultDeviceName);
69
70   CoreAudioDeviceList deviceIDList;
71   CCoreAudioHardware::GetOutputDevices(&deviceIDList);
72   while (!deviceIDList.empty())
73   {
74     AudioDeviceID deviceID = deviceIDList.front();
75     CCoreAudioDevice caDevice(deviceID);
76
77     device.m_channels.Reset();
78     device.m_dataFormats.clear();
79     device.m_sampleRates.clear();
80
81     device.m_deviceType = AE_DEVTYPE_PCM;
82     device.m_deviceName = caDevice.GetName();
83     device.m_displayName = device.m_deviceName;
84     device.m_displayNameExtra = "";
85
86     if (device.m_deviceName.find("HDMI") != std::string::npos)
87       device.m_deviceType = AE_DEVTYPE_HDMI;
88
89     CLog::Log(LOGDEBUG, "EnumerateDevices:Device(%s)" , device.m_deviceName.c_str());
90     AudioStreamIdList streams;
91     if (caDevice.GetStreams(&streams))
92     {
93       for (AudioStreamIdList::iterator j = streams.begin(); j != streams.end(); ++j)
94       {
95         StreamFormatList streams;
96         if (CCoreAudioStream::GetAvailablePhysicalFormats(*j, &streams))
97         {
98           for (StreamFormatList::iterator i = streams.begin(); i != streams.end(); ++i)
99           {
100             AudioStreamBasicDescription desc = i->mFormat;
101             std::string formatString;
102             CLog::Log(LOGDEBUG, "EnumerateDevices:Format(%s)" ,
103                                 StreamDescriptionToString(desc, formatString));
104             // add stream format info
105             switch (desc.mFormatID)
106             {
107               case kAudioFormatAC3:
108               case kAudioFormat60958AC3:
109                 if (!HasDataFormat(device.m_dataFormats, AE_FMT_AC3))
110                   device.m_dataFormats.push_back(AE_FMT_AC3);
111                 if (!HasDataFormat(device.m_dataFormats, AE_FMT_DTS))
112                   device.m_dataFormats.push_back(AE_FMT_DTS);
113                 // if we are not hdmi, this is an S/PDIF device
114                 if (device.m_deviceType != AE_DEVTYPE_HDMI)
115                   device.m_deviceType = AE_DEVTYPE_IEC958;
116                 break;
117               default:
118                 AEDataFormat format = AE_FMT_INVALID;
119                 switch(desc.mBitsPerChannel)
120                 {
121                   case 16:
122                     if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian)
123                       format = AE_FMT_S16BE;
124                     else
125                     {
126                       /* Passthrough is possible with a 2ch digital output */
127                       if (desc.mChannelsPerFrame == 2 && CCoreAudioStream::IsDigitalOuptut(*j))
128                       {
129                         if (desc.mSampleRate == 48000)
130                         {
131                           if (!HasDataFormat(device.m_dataFormats, AE_FMT_AC3))
132                             device.m_dataFormats.push_back(AE_FMT_AC3);
133                           if (!HasDataFormat(device.m_dataFormats, AE_FMT_DTS))
134                             device.m_dataFormats.push_back(AE_FMT_DTS);
135                         }
136                         else if (desc.mSampleRate == 192000)
137                         {
138                           if (!HasDataFormat(device.m_dataFormats, AE_FMT_EAC3))
139                             device.m_dataFormats.push_back(AE_FMT_EAC3);
140                         }
141                       }
142                       format = AE_FMT_S16LE;
143                     }
144                     break;
145                   case 24:
146                     if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian)
147                       format = AE_FMT_S24BE3;
148                     else
149                       format = AE_FMT_S24LE3;
150                     break;
151                   case 32:
152                     if (desc.mFormatFlags & kAudioFormatFlagIsFloat)
153                       format = AE_FMT_FLOAT;
154                     else
155                     {
156                       if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian)
157                         format = AE_FMT_S32BE;
158                       else
159                         format = AE_FMT_S32LE;
160                     }
161                     break;
162                 }
163                 if (format != AE_FMT_INVALID && !HasDataFormat(device.m_dataFormats, format))
164                   device.m_dataFormats.push_back(format);
165                 break;
166             }
167
168             // add channel info
169             CAEChannelInfo channel_info;
170             for (UInt32 chan = 0; chan < CA_MAX_CHANNELS && chan < desc.mChannelsPerFrame; ++chan)
171             {
172               if (!device.m_channels.HasChannel(CAChannelMap[chan]))
173                 device.m_channels += CAChannelMap[chan];
174               channel_info += CAChannelMap[chan];
175             }
176
177             // add sample rate info
178             if (!HasSampleRate(device.m_sampleRates, desc.mSampleRate))
179               device.m_sampleRates.push_back(desc.mSampleRate);
180           }
181         }
182       }
183     }
184
185     list.push_back(std::make_pair(deviceID, device));
186     //in the first place of the list add the default device
187     //with name "default" - if this is selected
188     //we will output to whatever osx claims to be default
189     //(allows transition from headphones to speaker and stuff
190     //like that
191     if(defaultDeviceName == device.m_deviceName)
192     {
193       device.m_deviceName = "default";
194       device.m_displayName = "Default";
195       list.insert(list.begin(), std::make_pair(deviceID, device));
196     }
197
198     deviceIDList.pop_front();
199   }
200 }
201
202 /* static, threadsafe access to the device list */
203 static CADeviceList     s_devices;
204 static CCriticalSection s_devicesLock;
205
206 static void EnumerateDevices()
207 {
208   CADeviceList devices;
209   EnumerateDevices(devices);
210   {
211     CSingleLock lock(s_devicesLock);
212     s_devices = devices;
213   }
214 }
215
216 static CADeviceList GetDevices()
217 {
218   CADeviceList list;
219   {
220     CSingleLock lock(s_devicesLock);
221     list = s_devices;
222   }
223   return list;
224 }
225
226 OSStatus deviceChangedCB(AudioObjectID                       inObjectID,
227                          UInt32                              inNumberAddresses,
228                          const AudioObjectPropertyAddress    inAddresses[],
229                          void*                               inClientData)
230 {
231   CLog::Log(LOGDEBUG, "CoreAudio: audiodevicelist changed - reenumerating");
232   CAEFactory::DeviceChange();
233   CLog::Log(LOGDEBUG, "CoreAudio: audiodevicelist changed - done");
234   return noErr;
235 }
236
237 void RegisterDeviceChangedCB(bool bRegister, void *ref)
238 {
239   OSStatus ret = noErr;
240   const AudioObjectPropertyAddress inAdr =
241   {
242     kAudioHardwarePropertyDevices,
243     kAudioObjectPropertyScopeGlobal,
244     kAudioObjectPropertyElementMaster
245   };
246
247   if (bRegister)
248     ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
249   else
250     ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
251
252   if (ret != noErr)
253     CLog::Log(LOGERROR, "CCoreAudioAE::Deinitialize - error %s a listener callback for device changes!", bRegister?"attaching":"removing");
254 }
255
256
257 ////////////////////////////////////////////////////////////////////////////////////////////
258 CAESinkDARWINOSX::CAESinkDARWINOSX()
259 : m_latentFrames(0), m_outputBitstream(false), m_outputBuffer(NULL), m_buffer(NULL)
260 {
261   // By default, kAudioHardwarePropertyRunLoop points at the process's main thread on SnowLeopard,
262   // If your process lacks such a run loop, you can set kAudioHardwarePropertyRunLoop to NULL which
263   // tells the HAL to run it's own thread for notifications (which was the default prior to SnowLeopard).
264   // So tell the HAL to use its own thread for similar behavior under all supported versions of OSX.
265   CFRunLoopRef theRunLoop = NULL;
266   AudioObjectPropertyAddress theAddress = {
267     kAudioHardwarePropertyRunLoop,
268     kAudioObjectPropertyScopeGlobal,
269     kAudioObjectPropertyElementMaster
270   };
271   OSStatus theError = AudioObjectSetPropertyData(kAudioObjectSystemObject,
272                                                  &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
273   if (theError != noErr)
274   {
275     CLog::Log(LOGERROR, "CCoreAudioAE::constructor: kAudioHardwarePropertyRunLoop error.");
276   }
277   RegisterDeviceChangedCB(true, this);
278   m_started = false;
279 }
280
281 CAESinkDARWINOSX::~CAESinkDARWINOSX()
282 {
283   RegisterDeviceChangedCB(false, this);
284 }
285
286 float ScoreStream(const AudioStreamBasicDescription &desc, const AEAudioFormat &format)
287 {
288   float score = 0;
289   if (format.m_dataFormat == AE_FMT_AC3 ||
290       format.m_dataFormat == AE_FMT_DTS)
291   {
292     if (desc.mFormatID == kAudioFormat60958AC3 ||
293         desc.mFormatID == 'IAC3' ||
294         desc.mFormatID == kAudioFormatAC3)
295     {
296       if (desc.mSampleRate == format.m_sampleRate &&
297           desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat) &&
298           desc.mChannelsPerFrame == format.m_channelLayout.Count())
299       {
300         // perfect match
301         score = FLT_MAX;
302       }
303     }
304   }
305   if (format.m_dataFormat == AE_FMT_AC3 ||
306       format.m_dataFormat == AE_FMT_DTS ||
307       format.m_dataFormat == AE_FMT_EAC3)
308   { // we should be able to bistreaming in PCM if the samplerate, bitdepth and channels match
309     if (desc.mSampleRate       == format.m_sampleRate                            &&
310         desc.mBitsPerChannel   == CAEUtil::DataFormatToBits(format.m_dataFormat) &&
311         desc.mChannelsPerFrame == format.m_channelLayout.Count()                 &&
312         desc.mFormatID         == kAudioFormatLinearPCM)
313     {
314       score = FLT_MAX / 2;
315     }
316   }
317   else
318   { // non-passthrough, whatever works is fine
319     if (desc.mFormatID == kAudioFormatLinearPCM)
320     {
321       if (desc.mSampleRate == format.m_sampleRate)
322         score += 10;
323       else if (desc.mSampleRate > format.m_sampleRate)
324         score += 1;
325       if (desc.mChannelsPerFrame == format.m_channelLayout.Count())
326         score += 5;
327       else if (desc.mChannelsPerFrame > format.m_channelLayout.Count())
328         score += 1;
329       if (format.m_dataFormat == AE_FMT_FLOAT)
330       { // for float, prefer the highest bitdepth we have
331         if (desc.mBitsPerChannel >= 16)
332           score += (desc.mBitsPerChannel / 8);
333       }
334       else
335       {
336         if (desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat))
337           score += 5;
338         else if (desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat))
339           score += 1;
340       }
341     }
342   }
343   return score;
344 }
345
346 bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device)
347 {
348   AudioDeviceID deviceID = 0;
349   CADeviceList devices = GetDevices();
350   if (StringUtils::EqualsNoCase(device, "default"))
351   {
352     CCoreAudioHardware::GetOutputDeviceName(device);
353     CLog::Log(LOGNOTICE, "%s: Opening default device %s", __PRETTY_FUNCTION__, device.c_str());
354   }
355       
356   for (size_t i = 0; i < devices.size(); i++)
357   {
358     if (device.find(devices[i].second.m_deviceName) != std::string::npos)
359     {
360       m_info = devices[i].second;
361       deviceID = devices[i].first;
362       break;
363     }
364   }
365   if (!deviceID)
366   {
367     CLog::Log(LOGERROR, "%s: Unable to find device %s", __FUNCTION__, device.c_str());
368     return false;
369   }
370
371   m_device.Open(deviceID);
372
373   // Fetch a list of the streams defined by the output device
374   AudioStreamIdList streams;
375   m_device.GetStreams(&streams);
376
377   CLog::Log(LOGDEBUG, "%s: Finding stream for format %s", __FUNCTION__, CAEUtil::DataFormatToStr(format.m_dataFormat));
378
379   bool                        passthrough  = false;
380   UInt32                      outputIndex  = 0;
381   float                       outputScore  = 0;
382   AudioStreamBasicDescription outputFormat = {0};
383   AudioStreamID               outputStream = 0;
384
385   /* The theory is to score based on
386    1. Matching passthrough characteristics (i.e. passthrough flag)
387    2. Matching sample rate.
388    3. Matching bits per channel (or higher).
389    4. Matching number of channels (or higher).
390    */
391   UInt32 index = 0;
392   for (AudioStreamIdList::const_iterator i = streams.begin(); i != streams.end(); ++i)
393   {
394     // Probe physical formats
395     StreamFormatList formats;
396     CCoreAudioStream::GetAvailablePhysicalFormats(*i, &formats);
397     for (StreamFormatList::const_iterator j = formats.begin(); j != formats.end(); ++j)
398     {
399       const AudioStreamBasicDescription &desc = j->mFormat;
400
401       float score = ScoreStream(desc, format);
402
403       std::string formatString;
404       CLog::Log(LOGDEBUG, "%s: Physical Format: %s rated %f", __FUNCTION__, StreamDescriptionToString(desc, formatString), score);
405
406       if (score > outputScore)
407       {
408         passthrough  = score > 1000;
409         outputScore  = score;
410         outputFormat = desc;
411         outputStream = *i;
412         outputIndex  = index;
413       }
414     }
415     index++;
416   }
417
418   if (!outputFormat.mFormatID)
419   {
420     CLog::Log(LOGERROR, "%s, Unable to find suitable stream", __FUNCTION__);
421     return false;
422   }
423
424   /* Update our AE format */
425   format.m_sampleRate    = outputFormat.mSampleRate;
426   if (outputFormat.mChannelsPerFrame != format.m_channelLayout.Count())
427   { /* update the channel count.  We assume that they're layed out as given in CAChannelMap.
428        if they're not, this is plain wrong */
429     format.m_channelLayout.Reset();
430     for (unsigned int i = 0; i < outputFormat.mChannelsPerFrame; i++)
431       format.m_channelLayout += CAChannelMap[i];
432   }
433
434   m_outputBitstream   = passthrough && outputFormat.mFormatID == kAudioFormatLinearPCM;
435
436   std::string formatString;
437   CLog::Log(LOGDEBUG, "%s: Selected stream[%u] - id: 0x%04X, Physical Format: %s %s", __FUNCTION__, outputIndex, outputStream, StreamDescriptionToString(outputFormat, formatString), m_outputBitstream ? "bitstreamed passthrough" : "");
438
439   SetHogMode(passthrough);
440
441   // Configure the output stream object
442   m_outputStream.Open(outputStream);
443
444   AudioStreamBasicDescription virtualFormat, previousPhysicalFormat;
445   m_outputStream.GetVirtualFormat(&virtualFormat);
446   m_outputStream.GetPhysicalFormat(&previousPhysicalFormat);
447   CLog::Log(LOGDEBUG, "%s: Previous Virtual Format: %s", __FUNCTION__, StreamDescriptionToString(virtualFormat, formatString));
448   CLog::Log(LOGDEBUG, "%s: Previous Physical Format: %s", __FUNCTION__, StreamDescriptionToString(previousPhysicalFormat, formatString));
449
450   m_outputStream.SetPhysicalFormat(&outputFormat); // Set the active format (the old one will be reverted when we close)
451   m_outputStream.GetVirtualFormat(&virtualFormat);
452   CLog::Log(LOGDEBUG, "%s: New Virtual Format: %s", __FUNCTION__, StreamDescriptionToString(virtualFormat, formatString));
453   CLog::Log(LOGDEBUG, "%s: New Physical Format: %s", __FUNCTION__, StreamDescriptionToString(outputFormat, formatString));
454
455   m_latentFrames = m_device.GetNumLatencyFrames();
456   m_latentFrames += m_outputStream.GetNumLatencyFrames();
457
458   /* TODO: Should we use the virtual format to determine our data format? */
459   format.m_frameSize     = format.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
460   format.m_frames        = m_device.GetBufferSize();
461   format.m_frameSamples  = format.m_frames * format.m_channelLayout.Count();
462
463   if (m_outputBitstream)
464   {
465     m_outputBuffer = new int16_t[format.m_frameSamples];
466     /* TODO: Do we need this? */
467     m_device.SetNominalSampleRate(format.m_sampleRate);
468   }
469
470   unsigned int num_buffers = 4;
471   m_buffer = new AERingBuffer(num_buffers * format.m_frames * format.m_frameSize);
472   CLog::Log(LOGDEBUG, "%s: using buffer size: %u (%f ms)", __FUNCTION__, m_buffer->GetMaxSize(), (float)m_buffer->GetMaxSize() / (format.m_sampleRate * format.m_frameSize));
473
474   m_format = format;
475   if (passthrough)
476     format.m_dataFormat = AE_FMT_S16NE;
477   else
478     format.m_dataFormat = AE_FMT_FLOAT;
479
480   // Register for data request callbacks from the driver and start
481   m_device.AddIOProc(renderCallback, this);
482   m_device.Start();
483   return true;
484 }
485
486 void CAESinkDARWINOSX::SetHogMode(bool on)
487 {
488   // TODO: Auto hogging sets this for us. Figure out how/when to turn it off or use it
489   // It appears that leaving this set will aslo restore the previous stream format when the
490   // Application exits. If auto hogging is set and we try to set hog mode, we will deadlock
491   // From the SDK docs: "If the AudioDevice is in a non-mixable mode, the HAL will automatically take hog mode on behalf of the first process to start an IOProc."
492
493   // Lock down the device.  This MUST be done PRIOR to switching to a non-mixable format, if it is done at all
494   // If it is attempted after the format change, there is a high likelihood of a deadlock
495   // We may need to do this sooner to enable mix-disable (i.e. before setting the stream format)
496   if (on)
497   {
498     // Auto-Hog does not always un-hog the device when changing back to a mixable mode.
499     // Handle this on our own until it is fixed.
500     CCoreAudioHardware::SetAutoHogMode(false);
501     bool autoHog = CCoreAudioHardware::GetAutoHogMode();
502     CLog::Log(LOGDEBUG, " CoreAudioRenderer::InitializeEncoded: "
503               "Auto 'hog' mode is set to '%s'.", autoHog ? "On" : "Off");
504     if (autoHog)
505       return;
506   }
507   m_device.SetHogStatus(on);
508   m_device.SetMixingSupport(!on);
509 }
510
511 void CAESinkDARWINOSX::Deinitialize()
512 {
513   m_device.Stop();
514   m_device.RemoveIOProc();
515
516   m_outputStream.Close();
517   m_device.Close();
518   if (m_buffer)
519   {
520     delete m_buffer;
521     m_buffer = NULL;
522   }
523   m_outputBitstream = false;
524
525   delete[] m_outputBuffer;
526   m_outputBuffer = NULL;
527
528   m_started = false;
529 }
530
531 bool CAESinkDARWINOSX::IsCompatible(const AEAudioFormat &format, const std::string &device)
532 {
533   return ((m_format.m_sampleRate    == format.m_sampleRate) &&
534           (m_format.m_dataFormat    == format.m_dataFormat) &&
535           (m_format.m_channelLayout == format.m_channelLayout));
536 }
537
538 double CAESinkDARWINOSX::GetDelay()
539 {
540   if (m_buffer)
541   {
542     // Calculate the duration of the data in the cache
543     double delay = (double)m_buffer->GetReadSize() / (double)m_format.m_frameSize;
544     delay += (double)m_latentFrames;
545     delay /= (double)m_format.m_sampleRate;
546     return delay;
547   }
548   return 0.0;
549 }
550
551 double CAESinkDARWINOSX::GetCacheTotal()
552 {
553   return (double)m_buffer->GetMaxSize() / (double)(m_format.m_frameSize * m_format.m_sampleRate);
554 }
555
556 CCriticalSection mutex;
557 XbmcThreads::ConditionVariable condVar;
558
559 unsigned int CAESinkDARWINOSX::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
560 {
561   if (m_buffer->GetWriteSize() < frames * m_format.m_frameSize)
562   { // no space to write - wait for a bit
563     CSingleLock lock(mutex);
564     if (!m_started)
565       condVar.wait(lock);
566     else
567       condVar.wait(lock, 900 * frames / m_format.m_sampleRate);
568   }
569
570   unsigned int write_frames = std::min(frames, m_buffer->GetWriteSize() / m_format.m_frameSize);
571   if (write_frames)
572     m_buffer->Write(data, write_frames * m_format.m_frameSize);
573
574   return write_frames;
575 }
576
577 void CAESinkDARWINOSX::Drain()
578 {
579   int bytes = m_buffer->GetReadSize();
580   while (bytes)
581   {
582     CSingleLock lock(mutex);
583     condVar.wait(mutex, 900 * bytes / (m_format.m_sampleRate * m_format.m_frameSize));
584     bytes = m_buffer->GetReadSize();
585   }
586 }
587
588 void CAESinkDARWINOSX::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
589 {
590   EnumerateDevices();
591   list.clear();
592   for (CADeviceList::const_iterator i = s_devices.begin(); i != s_devices.end(); ++i)
593     list.push_back(i->second);
594 }
595
596 OSStatus CAESinkDARWINOSX::renderCallback(AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* inClientData)
597 {
598   CAESinkDARWINOSX *sink = (CAESinkDARWINOSX*)inClientData;
599
600   sink->m_started = true;
601   for (unsigned int i = 0; i < outOutputData->mNumberBuffers; i++)
602   {
603     if (sink->m_outputBitstream)
604     {
605       /* HACK for bitstreaming AC3/DTS via PCM.
606        We reverse the float->S16LE conversion done in the stream or device */
607       static const float mul = 1.0f / (INT16_MAX + 1);
608
609       unsigned int wanted = std::min(outOutputData->mBuffers[i].mDataByteSize / sizeof(float), (size_t)sink->m_format.m_frameSamples)  * sizeof(int16_t);
610       if (wanted <= sink->m_buffer->GetReadSize())
611       {
612         sink->m_buffer->Read((unsigned char *)sink->m_outputBuffer, wanted);
613         int16_t *src = sink->m_outputBuffer;
614         float  *dest = (float*)outOutputData->mBuffers[i].mData;
615         for (unsigned int i = 0; i < wanted / 2; i++)
616           *dest++ = *src++ * mul;
617       }
618     }
619     else
620     {
621       /* buffers appear to come from CA already zero'd, so just copy what is wanted */
622       unsigned int wanted = outOutputData->mBuffers[i].mDataByteSize;
623       unsigned int bytes = std::min(sink->m_buffer->GetReadSize(), wanted);
624       sink->m_buffer->Read((unsigned char*)outOutputData->mBuffers[i].mData, bytes);
625       if (bytes != wanted)
626         CLog::Log(LOGERROR, "%s: %sFLOW (%i vs %i) bytes", __FUNCTION__, bytes > wanted ? "OVER" : "UNDER", bytes, wanted);
627     }
628
629     // tell the sink we're good for more data
630     condVar.notifyAll();
631   }
632   return noErr;
633 }