Merge pull request #4794 from ossman/curlssl
[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 "cores/AudioEngine/Sinks/osx/CoreAudioChannelLayout.h"
28 #include "osx/DarwinUtils.h"
29 #include "utils/log.h"
30 #include "utils/StringUtils.h"
31 #include "threads/Condition.h"
32 #include "threads/CriticalSection.h"
33
34 #include <sstream>
35
36 #define CA_MAX_CHANNELS 16
37 // default channel map - in case it can't be fetched from the device
38 static enum AEChannel CAChannelMap[CA_MAX_CHANNELS + 1] = {
39   AE_CH_FL , AE_CH_FR , AE_CH_BL , AE_CH_BR , AE_CH_FC , AE_CH_LFE , AE_CH_SL , AE_CH_SR ,
40   AE_CH_UNKNOWN1 ,
41   AE_CH_UNKNOWN2 ,
42   AE_CH_UNKNOWN3 ,
43   AE_CH_UNKNOWN4 ,
44   AE_CH_UNKNOWN5 ,
45   AE_CH_UNKNOWN6 ,
46   AE_CH_UNKNOWN7 ,
47   AE_CH_UNKNOWN8 ,
48   AE_CH_NULL
49 };
50
51 // map coraudio channel labels to activeae channel labels
52 static enum AEChannel CAChannelToAEChannel(AudioChannelLabel CAChannelLabel)
53 {
54   enum AEChannel ret = AE_CH_NULL;
55   static unsigned int unknownChannel = AE_CH_UNKNOWN1;
56   switch(CAChannelLabel)
57   {
58     case kAudioChannelLabel_Left:
59       ret = AE_CH_FL;
60       break;
61     case kAudioChannelLabel_Right:
62       ret = AE_CH_FR;
63       break;
64     case kAudioChannelLabel_Center:
65       ret = AE_CH_FC;
66       break;
67     case kAudioChannelLabel_LFEScreen:
68       ret = AE_CH_LFE;
69       break;
70     case kAudioChannelLabel_LeftSurroundDirect:
71       ret = AE_CH_SL;
72       break;
73     case kAudioChannelLabel_RightSurroundDirect:
74       ret = AE_CH_SR;
75       break;
76     case kAudioChannelLabel_LeftCenter:
77       ret = AE_CH_FLOC;
78       break;
79     case kAudioChannelLabel_RightCenter:
80       ret = AE_CH_FROC;
81       break;
82     case kAudioChannelLabel_CenterSurround:
83       ret = AE_CH_TC;
84       break;
85     case kAudioChannelLabel_LeftSurround:
86       ret = AE_CH_SL;
87       break;
88     case kAudioChannelLabel_RightSurround:
89       ret = AE_CH_SR;
90       break;
91     case kAudioChannelLabel_VerticalHeightLeft:
92       ret = AE_CH_TFL;
93       break;
94     case kAudioChannelLabel_VerticalHeightRight:
95       ret = AE_CH_TFR;
96       break;
97     case kAudioChannelLabel_VerticalHeightCenter:
98       ret = AE_CH_TFC;
99       break;
100     case kAudioChannelLabel_TopCenterSurround:
101       ret = AE_CH_TC;
102       break;
103     case kAudioChannelLabel_TopBackLeft:
104       ret = AE_CH_TBL;
105       break;
106     case kAudioChannelLabel_TopBackRight:
107       ret = AE_CH_TBR;
108       break;
109     case kAudioChannelLabel_TopBackCenter:
110       ret = AE_CH_TBC;
111       break;
112     case kAudioChannelLabel_RearSurroundLeft:
113       ret = AE_CH_BL;
114       break;
115     case kAudioChannelLabel_RearSurroundRight:
116       ret = AE_CH_BR;
117       break;
118     case kAudioChannelLabel_LeftWide:
119       ret = AE_CH_BLOC;
120       break;
121     case kAudioChannelLabel_RightWide:
122       ret = AE_CH_BROC;
123       break;
124     case kAudioChannelLabel_LFE2:
125       ret = AE_CH_LFE;
126       break;
127     case kAudioChannelLabel_LeftTotal:
128       ret = AE_CH_FL;
129       break;
130     case kAudioChannelLabel_RightTotal:
131       ret = AE_CH_FR;
132       break;
133     case kAudioChannelLabel_HearingImpaired:
134       ret = AE_CH_FC;
135       break;
136     case kAudioChannelLabel_Narration:
137       ret = AE_CH_FC;
138       break;
139     case kAudioChannelLabel_Mono:
140       ret = AE_CH_FC;
141       break;
142     case kAudioChannelLabel_DialogCentricMix:
143       ret = AE_CH_FC;
144       break;
145     case kAudioChannelLabel_CenterSurroundDirect:
146       ret = AE_CH_TC;
147       break;
148     case kAudioChannelLabel_Haptic:
149       ret = AE_CH_FC;
150       break;
151     default:
152       ret = (enum AEChannel)unknownChannel++;
153   }
154   if (unknownChannel > AE_CH_UNKNOWN8)
155     unknownChannel = AE_CH_UNKNOWN1;
156     
157   return ret;
158 }
159
160 //Note: in multichannel mode CA will either pull 2 channels of data (stereo) or 6/8 channels of data
161 //(every speaker setup with more then 2 speakers). The difference between the number of real speakers
162 //and 6/8 channels needs to be padded with unknown channels so that the sample size fits 6/8 channels
163 //
164 //device [in] - the device whose channel layout should be used
165 //channelMap [in/out] - if filled it will it indicates that we are called from initialize and we log the requested map, out returns the channelMap for device
166 //channelsPerFrame [in] - the number of channels this device is configured to (e.x. 2 or 6/8)
167 static void GetAEChannelMap(CCoreAudioDevice &device, CAEChannelInfo &channelMap, unsigned int channelsPerFrame)
168 {
169   CCoreAudioChannelLayout calayout;
170   bool logMapping = channelMap.Count() > 0; // only log if the engine requests a layout during init
171   bool mapAvailable = false;
172   unsigned int numberChannelsInDeviceLayout = CA_MAX_CHANNELS; // default 8 channels from CAChannelMap
173   AudioChannelLayout *layout = NULL;
174
175   // try to fetch either the multichannel or the stereo channel layout from the device
176   if (channelsPerFrame == 2 || channelMap.Count() == 2)
177     mapAvailable = device.GetPreferredChannelLayoutForStereo(calayout);
178   else
179     mapAvailable = device.GetPreferredChannelLayout(calayout);
180
181   // if a map was fetched - check if it is usable
182   if (mapAvailable)
183   {
184     layout = calayout;
185     if (layout == NULL || layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions)
186       mapAvailable = false;// wrong map format
187     else
188       numberChannelsInDeviceLayout = layout->mNumberChannelDescriptions;
189   }
190
191   // start the mapping action
192   // the number of channels to be added to the outgoing channelmap
193   // this is CA_MAX_CHANNELS at max and might be lower for some output devices (channelsPerFrame)
194   unsigned int numChannelsToMap = std::min((unsigned int)CA_MAX_CHANNELS, (unsigned int)channelsPerFrame);
195
196   // if there was a map fetched we force the number of
197   // channels to map to channelsPerFrame (this allows mapping
198   // of more then CA_MAX_CHANNELS if needed)
199   if (mapAvailable)
200     numChannelsToMap = channelsPerFrame;
201
202   std::string layoutStr;
203
204   if (logMapping)
205   {
206     CLog::Log(LOGDEBUG, "%s Engine requests layout %s", __FUNCTION__, ((std::string)channelMap).c_str());
207
208     if (mapAvailable)
209       CLog::Log(LOGDEBUG, "%s trying to map to %s layout: %s", __FUNCTION__, channelsPerFrame == 2 ? "stereo" : "multichannel", calayout.ChannelLayoutToString(*layout, layoutStr));
210     else
211       CLog::Log(LOGDEBUG, "%s no map available - using static multichannel map layout", __FUNCTION__);
212   }
213     
214   channelMap.Reset();// start with an empty map
215
216   for (unsigned int channel = 0; channel < numChannelsToMap; channel++)
217   {
218     // we only try to map channels which are defined in the device layout
219     enum AEChannel currentChannel;
220     if (channel < numberChannelsInDeviceLayout)
221     {
222       // get the channel from the fetched map
223       if (mapAvailable)
224         currentChannel = CAChannelToAEChannel(layout->mChannelDescriptions[channel].mChannelLabel);
225       else// get the channel from the default map
226         currentChannel = CAChannelMap[channel];
227
228     }
229     else// fill with unknown channels
230       currentChannel = CAChannelToAEChannel(kAudioChannelLabel_Unknown);
231
232     if(!channelMap.HasChannel(currentChannel))// only add if not already added
233       channelMap += currentChannel;
234   }
235
236   if (logMapping)
237     CLog::Log(LOGDEBUG, "%s mapped channels to layout %s", __FUNCTION__, ((std::string)channelMap).c_str());
238 }
239
240 static bool HasSampleRate(const AESampleRateList &list, const unsigned int samplerate)
241 {
242   for (size_t i = 0; i < list.size(); ++i)
243   {
244     if (list[i] == samplerate)
245       return true;
246   }
247   return false;
248 }
249
250 static bool HasDataFormat(const AEDataFormatList &list, const enum AEDataFormat format)
251 {
252   for (size_t i = 0; i < list.size(); ++i)
253   {
254     if (list[i] == format)
255       return true;
256   }
257   return false;
258 }
259
260 typedef std::vector< std::pair<AudioDeviceID, CAEDeviceInfo> > CADeviceList;
261
262 static void EnumerateDevices(CADeviceList &list)
263 {
264   CAEDeviceInfo device;
265
266   std::string defaultDeviceName;
267   CCoreAudioHardware::GetOutputDeviceName(defaultDeviceName);
268
269   CoreAudioDeviceList deviceIDList;
270   CCoreAudioHardware::GetOutputDevices(&deviceIDList);
271   while (!deviceIDList.empty())
272   {
273     AudioDeviceID deviceID = deviceIDList.front();
274     CCoreAudioDevice caDevice(deviceID);
275
276     device.m_channels.Reset();
277     device.m_dataFormats.clear();
278     device.m_sampleRates.clear();
279
280     device.m_deviceType = AE_DEVTYPE_PCM;
281     device.m_deviceName = caDevice.GetName();
282     device.m_displayName = device.m_deviceName;
283     device.m_displayNameExtra = "";
284
285     // flag indicating that passthroughformats where added throughout the stream enumeration
286     bool hasPassthroughFormats = false;
287     // the maximum number of channels found in the streams
288     UInt32 numMaxChannels = 0;
289     // the terminal type as reported by ca
290     UInt32 caTerminalType = 0;
291       
292     bool isDigital = caDevice.IsDigital(caTerminalType);
293
294
295     CLog::Log(LOGDEBUG, "EnumerateDevices:Device(%s)" , device.m_deviceName.c_str());
296     AudioStreamIdList streams;
297     if (caDevice.GetStreams(&streams))
298     {
299       for (AudioStreamIdList::iterator j = streams.begin(); j != streams.end(); ++j)
300       {
301         StreamFormatList streamFormats;
302         if (CCoreAudioStream::GetAvailablePhysicalFormats(*j, &streamFormats))
303         {
304           for (StreamFormatList::iterator i = streamFormats.begin(); i != streamFormats.end(); ++i)
305           {
306             AudioStreamBasicDescription desc = i->mFormat;
307             std::string formatString;
308             CLog::Log(LOGDEBUG, "EnumerateDevices:Format(%s)" ,
309                                 StreamDescriptionToString(desc, formatString));
310
311             // add stream format info
312             switch (desc.mFormatID)
313             {
314               case kAudioFormatAC3:
315               case kAudioFormat60958AC3:
316                 if (!HasDataFormat(device.m_dataFormats, AE_FMT_AC3))
317                   device.m_dataFormats.push_back(AE_FMT_AC3);
318                 if (!HasDataFormat(device.m_dataFormats, AE_FMT_DTS))
319                   device.m_dataFormats.push_back(AE_FMT_DTS);
320                 hasPassthroughFormats = true;
321                 isDigital = true;// sanity - those are always digital devices!
322                 break;
323               default:
324                 AEDataFormat format = AE_FMT_INVALID;
325                 switch(desc.mBitsPerChannel)
326                 {
327                   case 16:
328                     if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian)
329                       format = AE_FMT_S16BE;
330                     else
331                     {
332                       // if it is no digital stream per definition
333                       // check if the device name suggests that it is digital
334                       // (some hackintonshs are not so smart in announcing correct
335                       // ca devices ...
336                       if (!isDigital)
337                       {
338                         std::string devNameLower = device.m_deviceName;
339                         StringUtils::ToLower(devNameLower);                       
340                         isDigital = devNameLower.find("digital") != std::string::npos;
341                       }
342
343                       /* Passthrough is possible with a 2ch digital output */
344                       if (desc.mChannelsPerFrame == 2 && isDigital)
345                       {
346                         if (desc.mSampleRate == 48000)
347                         {
348                           if (!HasDataFormat(device.m_dataFormats, AE_FMT_AC3))
349                             device.m_dataFormats.push_back(AE_FMT_AC3);
350                           if (!HasDataFormat(device.m_dataFormats, AE_FMT_DTS))
351                             device.m_dataFormats.push_back(AE_FMT_DTS);
352                           hasPassthroughFormats = true;
353                         }
354                         else if (desc.mSampleRate == 192000)
355                         {
356                           if (!HasDataFormat(device.m_dataFormats, AE_FMT_EAC3))
357                             device.m_dataFormats.push_back(AE_FMT_EAC3);
358                           hasPassthroughFormats = true;
359                         }
360                       }
361                       format = AE_FMT_S16LE;
362                     }
363                     break;
364                   case 24:
365                     if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian)
366                       format = AE_FMT_S24BE3;
367                     else
368                       format = AE_FMT_S24LE3;
369                     break;
370                   case 32:
371                     if (desc.mFormatFlags & kAudioFormatFlagIsFloat)
372                       format = AE_FMT_FLOAT;
373                     else
374                     {
375                       if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian)
376                         format = AE_FMT_S32BE;
377                       else
378                         format = AE_FMT_S32LE;
379                     }
380                     break;
381                 }
382                 
383                 if (numMaxChannels < desc.mChannelsPerFrame)
384                   numMaxChannels = desc.mChannelsPerFrame;
385                 
386                 if (format != AE_FMT_INVALID && !HasDataFormat(device.m_dataFormats, format))
387                   device.m_dataFormats.push_back(format);
388                 break;
389             }
390
391             // add sample rate info
392             // for devices which return kAudioStreamAnyRatee
393             // we add 44.1khz and 48khz - user can use
394             // the "fixed" audio config to force one of them
395             if (desc.mSampleRate == kAudioStreamAnyRate)
396             {
397               CLog::Log(LOGINFO, "%s reported samplerate is kAudioStreamAnyRate adding 44.1khz and 48khz", __FUNCTION__);
398               desc.mSampleRate = 44100;
399               if (!HasSampleRate(device.m_sampleRates, desc.mSampleRate))
400                 device.m_sampleRates.push_back(desc.mSampleRate);
401               desc.mSampleRate = 48000;
402             }
403
404             if (!HasSampleRate(device.m_sampleRates, desc.mSampleRate))
405               device.m_sampleRates.push_back(desc.mSampleRate);
406           }
407         }
408       }
409     }
410
411     
412     // flag indicating that the device name "sounds" like HDMI
413     bool hasHdmiName = device.m_deviceName.find("HDMI") != std::string::npos;
414     // flag indicating that the device name "sounds" like DisplayPort
415     bool hasDisplayPortName = device.m_deviceName.find("DisplayPort") != std::string::npos;
416     
417     // decide the type of the device based on the discovered information
418     // in the streams
419     // device defaults to PCM (see start of the while loop)
420     // it can be HDMI, DisplayPort or Optical
421     // for all of those types it needs to support
422     // passthroughformats and needs to be a digital port
423     if (hasPassthroughFormats && isDigital)
424     {
425       // if the max number of channels was more then 2
426       // this can be HDMI or DisplayPort or Thunderbolt
427       if (numMaxChannels > 2)
428       {
429         // either the devicename suggests its HDMI
430         // or CA reported the terminalType as HDMI
431         if (hasHdmiName || caTerminalType == kIOAudioDeviceTransportTypeHdmi)
432           device.m_deviceType = AE_DEVTYPE_HDMI;
433
434         // either the devicename suggests its DisplayPort
435         // or CA reported the terminalType as DisplayPort or Thunderbolt
436         if (hasDisplayPortName || caTerminalType == kIOAudioDeviceTransportTypeDisplayPort || caTerminalType == kIOAudioDeviceTransportTypeThunderbolt)
437           device.m_deviceType = AE_DEVTYPE_DP;
438       }
439       else// treat all other digital passthrough devices as optical
440         device.m_deviceType = AE_DEVTYPE_IEC958;
441     }
442
443     // devicename based overwrites from former code - maybe FIXME at some point when we
444     // are sure that the upper detection does its job in all[tm] use cases
445     if (hasHdmiName)
446       device.m_deviceType = AE_DEVTYPE_HDMI;
447     if (hasDisplayPortName)
448       device.m_deviceType = AE_DEVTYPE_DP;
449       
450     //get channel map to match the devices channel layout as set in audio-midi-setup
451     GetAEChannelMap(caDevice, device.m_channels, caDevice.GetTotalOutputChannels());
452     
453     list.push_back(std::make_pair(deviceID, device));
454     //in the first place of the list add the default device
455     //with name "default" - if this is selected
456     //we will output to whatever osx claims to be default
457     //(allows transition from headphones to speaker and stuff
458     //like that
459     if(defaultDeviceName == device.m_deviceName)
460     {
461       device.m_deviceName = "default";
462       device.m_displayName = "Default";
463       list.insert(list.begin(), std::make_pair(deviceID, device));
464     }
465
466     deviceIDList.pop_front();
467   }
468 }
469
470 /* static, threadsafe access to the device list */
471 static CADeviceList     s_devices;
472 static CCriticalSection s_devicesLock;
473
474 static void EnumerateDevices()
475 {
476   CADeviceList devices;
477   EnumerateDevices(devices);
478   {
479     CSingleLock lock(s_devicesLock);
480     s_devices = devices;
481   }
482 }
483
484 static CADeviceList GetDevices()
485 {
486   CADeviceList list;
487   {
488     CSingleLock lock(s_devicesLock);
489     list = s_devices;
490   }
491   return list;
492 }
493
494 OSStatus deviceChangedCB(AudioObjectID                       inObjectID,
495                          UInt32                              inNumberAddresses,
496                          const AudioObjectPropertyAddress    inAddresses[],
497                          void*                               inClientData)
498 {
499   bool deviceChanged = false;
500   static AudioDeviceID oldDefaultDevice = 0;
501   AudioDeviceID currentDefaultOutputDevice = 0;
502
503   for (unsigned int i = 0; i < inNumberAddresses; i++)
504   {
505     switch (inAddresses[i].mSelector)
506     {
507       case kAudioHardwarePropertyDefaultOutputDevice:
508         currentDefaultOutputDevice = CCoreAudioHardware::GetDefaultOutputDevice();
509         // This listener is called on every change of the hardware
510         // device. So check if the default device has really changed.
511         if (oldDefaultDevice != currentDefaultOutputDevice)
512         {
513           deviceChanged = true;
514           oldDefaultDevice = currentDefaultOutputDevice;
515         }
516         break;
517       default:
518         deviceChanged = true;
519         break;
520     }
521     if (deviceChanged)
522       break;
523   }
524
525   if  (deviceChanged)
526   {
527     CLog::Log(LOGDEBUG, "CoreAudio: audiodevicelist changed - reenumerating");
528     CAEFactory::DeviceChange();
529     CLog::Log(LOGDEBUG, "CoreAudio: audiodevicelist changed - done");
530   }
531   return noErr;
532 }
533
534 void RegisterDeviceChangedCB(bool bRegister, void *ref)
535 {
536   OSStatus ret = noErr;
537   AudioObjectPropertyAddress inAdr =
538   {
539     kAudioHardwarePropertyDevices,
540     kAudioObjectPropertyScopeGlobal,
541     kAudioObjectPropertyElementMaster
542   };
543
544   if (bRegister)
545   {
546     ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
547     inAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
548     ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
549   }
550   else
551   {
552     ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
553     inAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
554     ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
555   }
556
557   if (ret != noErr)
558     CLog::Log(LOGERROR, "CCoreAudioAE::Deinitialize - error %s a listener callback for device changes!", bRegister?"attaching":"removing");
559 }
560
561
562 ////////////////////////////////////////////////////////////////////////////////////////////
563 CAESinkDARWINOSX::CAESinkDARWINOSX()
564 : m_latentFrames(0), m_outputBitstream(false), m_outputBuffer(NULL), m_planar(false), m_planarBuffer(NULL), m_buffer(NULL)
565 {
566   // By default, kAudioHardwarePropertyRunLoop points at the process's main thread on SnowLeopard,
567   // If your process lacks such a run loop, you can set kAudioHardwarePropertyRunLoop to NULL which
568   // tells the HAL to run it's own thread for notifications (which was the default prior to SnowLeopard).
569   // So tell the HAL to use its own thread for similar behavior under all supported versions of OSX.
570   CFRunLoopRef theRunLoop = NULL;
571   AudioObjectPropertyAddress theAddress = {
572     kAudioHardwarePropertyRunLoop,
573     kAudioObjectPropertyScopeGlobal,
574     kAudioObjectPropertyElementMaster
575   };
576   OSStatus theError = AudioObjectSetPropertyData(kAudioObjectSystemObject,
577                                                  &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
578   if (theError != noErr)
579   {
580     CLog::Log(LOGERROR, "CCoreAudioAE::constructor: kAudioHardwarePropertyRunLoop error.");
581   }
582   RegisterDeviceChangedCB(true, this);
583   m_started = false;
584   m_planar = false;
585 }
586
587 CAESinkDARWINOSX::~CAESinkDARWINOSX()
588 {
589   RegisterDeviceChangedCB(false, this);
590 }
591
592 float ScoreStream(const AudioStreamBasicDescription &desc, const AEAudioFormat &format)
593 {
594   float score = 0;
595   if (format.m_dataFormat == AE_FMT_AC3 ||
596       format.m_dataFormat == AE_FMT_DTS)
597   {
598     if (desc.mFormatID == kAudioFormat60958AC3 ||
599         desc.mFormatID == 'IAC3' ||
600         desc.mFormatID == kAudioFormatAC3)
601     {
602       if (desc.mSampleRate == format.m_sampleRate &&
603           desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat) &&
604           desc.mChannelsPerFrame == format.m_channelLayout.Count())
605       {
606         // perfect match
607         score = FLT_MAX;
608       }
609     }
610   }
611   if (format.m_dataFormat == AE_FMT_AC3 ||
612       format.m_dataFormat == AE_FMT_DTS ||
613       format.m_dataFormat == AE_FMT_EAC3)
614   { // we should be able to bistreaming in PCM if the samplerate, bitdepth and channels match
615     if (desc.mSampleRate       == format.m_sampleRate                            &&
616         desc.mBitsPerChannel   == CAEUtil::DataFormatToBits(format.m_dataFormat) &&
617         desc.mChannelsPerFrame == format.m_channelLayout.Count()                 &&
618         desc.mFormatID         == kAudioFormatLinearPCM)
619     {
620       score = FLT_MAX / 2;
621     }
622   }
623   else
624   { // non-passthrough, whatever works is fine
625     if (desc.mFormatID == kAudioFormatLinearPCM)
626     {
627       if (desc.mSampleRate == format.m_sampleRate)
628         score += 10;
629       else if (desc.mSampleRate > format.m_sampleRate)
630         score += 1;
631       if (desc.mChannelsPerFrame == format.m_channelLayout.Count())
632         score += 5;
633       else if (desc.mChannelsPerFrame > format.m_channelLayout.Count())
634         score += 1;
635       if (format.m_dataFormat == AE_FMT_FLOAT)
636       { // for float, prefer the highest bitdepth we have
637         if (desc.mBitsPerChannel >= 16)
638           score += (desc.mBitsPerChannel / 8);
639       }
640       else
641       {
642         if (desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat))
643           score += 5;
644         else if (desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat))
645           score += 1;
646       }
647     }
648   }
649   return score;
650 }
651
652 bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device)
653 {
654   AudioDeviceID deviceID = 0;
655   CADeviceList devices = GetDevices();
656   if (StringUtils::EqualsNoCase(device, "default"))
657   {
658     CCoreAudioHardware::GetOutputDeviceName(device);
659     deviceID = CCoreAudioHardware::GetDefaultOutputDevice();
660     CLog::Log(LOGNOTICE, "%s: Opening default device %s", __PRETTY_FUNCTION__, device.c_str());
661   }
662   else
663   {
664     for (size_t i = 0; i < devices.size(); i++)
665     {
666       if (device.find(devices[i].second.m_deviceName) != std::string::npos)
667       {
668         deviceID = devices[i].first;
669         break;
670       }
671     }
672   }
673
674   if (!deviceID)
675   {
676     CLog::Log(LOGERROR, "%s: Unable to find device %s", __FUNCTION__, device.c_str());
677     return false;
678   }
679
680   m_device.Open(deviceID);
681
682   // Fetch a list of the streams defined by the output device
683   AudioStreamIdList streams;
684   m_device.GetStreams(&streams);
685
686   CLog::Log(LOGDEBUG, "%s: Finding stream for format %s", __FUNCTION__, CAEUtil::DataFormatToStr(format.m_dataFormat));
687
688   bool                        passthrough  = false;
689   UInt32                      outputIndex  = 0;
690   float                       outputScore  = 0;
691   AudioStreamBasicDescription outputFormat = {0};
692   AudioStreamID               outputStream = 0;
693
694   /* The theory is to score based on
695    1. Matching passthrough characteristics (i.e. passthrough flag)
696    2. Matching sample rate.
697    3. Matching bits per channel (or higher).
698    4. Matching number of channels (or higher).
699    */
700   UInt32 index = 0;
701   for (AudioStreamIdList::const_iterator i = streams.begin(); i != streams.end(); ++i)
702   {
703     // Probe physical formats
704     StreamFormatList formats;
705     CCoreAudioStream::GetAvailablePhysicalFormats(*i, &formats);
706     for (StreamFormatList::const_iterator j = formats.begin(); j != formats.end(); ++j)
707     {
708       AudioStreamBasicDescription desc = j->mFormat;
709
710       // for devices with kAudioStreamAnyRate
711       // assume that the user uses a fixed config
712       // and knows what he is doing - so we use
713       // the requested samplerate here
714       if (desc.mSampleRate == kAudioStreamAnyRate)
715         desc.mSampleRate = format.m_sampleRate;
716
717       float score = ScoreStream(desc, format);
718
719       std::string formatString;
720       CLog::Log(LOGDEBUG, "%s: Physical Format: %s rated %f", __FUNCTION__, StreamDescriptionToString(desc, formatString), score);
721
722       if (score > outputScore)
723       {
724         passthrough  = score > 1000;
725         outputScore  = score;
726         outputFormat = desc;
727         outputStream = *i;
728         outputIndex  = index;
729       }
730     }
731     index++;
732   }
733
734   m_planar = false;
735   if (streams.size() > 1 && outputFormat.mChannelsPerFrame == 1)
736   {
737     CLog::Log(LOGDEBUG, "%s Found planar audio with %u channels?", __FUNCTION__, streams.size());
738     outputFormat.mChannelsPerFrame = std::min((size_t)format.m_channelLayout.Count(), streams.size());
739     m_planar = true;
740   }
741
742   if (!outputFormat.mFormatID)
743   {
744     CLog::Log(LOGERROR, "%s, Unable to find suitable stream", __FUNCTION__);
745     return false;
746   }
747
748   /* Update our AE format */
749   format.m_sampleRate    = outputFormat.mSampleRate;
750   
751   m_outputBitstream   = passthrough && outputFormat.mFormatID == kAudioFormatLinearPCM;
752
753   std::string formatString;
754   CLog::Log(LOGDEBUG, "%s: Selected stream[%u] - id: 0x%04X, Physical Format: %s %s", __FUNCTION__, (unsigned int)outputIndex, (unsigned int)outputStream, StreamDescriptionToString(outputFormat, formatString), m_outputBitstream ? "bitstreamed passthrough" : "");
755
756   SetHogMode(passthrough);
757
758   // Configure the output stream object
759   m_outputStream.Open(outputStream);
760
761   AudioStreamBasicDescription virtualFormat, previousPhysicalFormat;
762   m_outputStream.GetVirtualFormat(&virtualFormat);
763   m_outputStream.GetPhysicalFormat(&previousPhysicalFormat);
764   CLog::Log(LOGDEBUG, "%s: Previous Virtual Format: %s", __FUNCTION__, StreamDescriptionToString(virtualFormat, formatString));
765   CLog::Log(LOGDEBUG, "%s: Previous Physical Format: %s", __FUNCTION__, StreamDescriptionToString(previousPhysicalFormat, formatString));
766
767   m_outputStream.SetPhysicalFormat(&outputFormat); // Set the active format (the old one will be reverted when we close)
768   m_outputStream.GetVirtualFormat(&virtualFormat);
769   CLog::Log(LOGDEBUG, "%s: New Virtual Format: %s", __FUNCTION__, StreamDescriptionToString(virtualFormat, formatString));
770   CLog::Log(LOGDEBUG, "%s: New Physical Format: %s", __FUNCTION__, StreamDescriptionToString(outputFormat, formatString));
771
772   // update the channel map based on the new stream format
773   GetAEChannelMap(m_device, format.m_channelLayout, outputFormat.mChannelsPerFrame);
774
775
776   m_latentFrames = m_device.GetNumLatencyFrames();
777   m_latentFrames += m_outputStream.GetNumLatencyFrames();
778
779   /* TODO: Should we use the virtual format to determine our data format? */
780   format.m_frameSize     = format.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
781   format.m_frames        = m_device.GetBufferSize();
782   format.m_frameSamples  = format.m_frames * format.m_channelLayout.Count();
783
784   if (m_outputBitstream)
785   {
786     m_outputBuffer = new int16_t[format.m_frameSamples];
787     /* TODO: Do we need this? */
788     m_device.SetNominalSampleRate(format.m_sampleRate);
789   }
790
791   if (m_planar)
792     m_planarBuffer = new float[format.m_frameSamples];
793
794   unsigned int num_buffers = 4;
795   m_buffer = new AERingBuffer(num_buffers * format.m_frames * format.m_frameSize);
796   CLog::Log(LOGDEBUG, "%s: using buffer size: %u (%f ms)", __FUNCTION__, m_buffer->GetMaxSize(), (float)m_buffer->GetMaxSize() / (format.m_sampleRate * format.m_frameSize));
797
798   m_format = format;
799   if (passthrough)
800     format.m_dataFormat = AE_FMT_S16NE;
801   else
802     format.m_dataFormat = AE_FMT_FLOAT;
803
804   // Register for data request callbacks from the driver and start
805   m_device.AddIOProc(renderCallback, this);
806   m_device.Start();
807   return true;
808 }
809
810 void CAESinkDARWINOSX::SetHogMode(bool on)
811 {
812   // TODO: Auto hogging sets this for us. Figure out how/when to turn it off or use it
813   // It appears that leaving this set will aslo restore the previous stream format when the
814   // Application exits. If auto hogging is set and we try to set hog mode, we will deadlock
815   // 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."
816
817   // Lock down the device.  This MUST be done PRIOR to switching to a non-mixable format, if it is done at all
818   // If it is attempted after the format change, there is a high likelihood of a deadlock
819   // We may need to do this sooner to enable mix-disable (i.e. before setting the stream format)
820   if (on)
821   {
822     // Auto-Hog does not always un-hog the device when changing back to a mixable mode.
823     // Handle this on our own until it is fixed.
824     CCoreAudioHardware::SetAutoHogMode(false);
825     bool autoHog = CCoreAudioHardware::GetAutoHogMode();
826     CLog::Log(LOGDEBUG, " CoreAudioRenderer::InitializeEncoded: "
827               "Auto 'hog' mode is set to '%s'.", autoHog ? "On" : "Off");
828     if (autoHog)
829       return;
830   }
831   m_device.SetHogStatus(on);
832   m_device.SetMixingSupport(!on);
833 }
834
835 void CAESinkDARWINOSX::Deinitialize()
836 {
837   m_device.Stop();
838   m_device.RemoveIOProc();
839
840   m_outputStream.Close();
841   m_device.Close();
842   if (m_buffer)
843   {
844     delete m_buffer;
845     m_buffer = NULL;
846   }
847   m_outputBitstream = false;
848
849   delete[] m_outputBuffer;
850   m_outputBuffer = NULL;
851
852   m_planar = false;
853   delete[] m_planarBuffer;
854   m_planarBuffer = NULL;
855
856   m_started = false;
857 }
858
859 bool CAESinkDARWINOSX::IsCompatible(const AEAudioFormat &format, const std::string &device)
860 {
861   return ((m_format.m_sampleRate    == format.m_sampleRate) &&
862           (m_format.m_dataFormat    == format.m_dataFormat) &&
863           (m_format.m_channelLayout == format.m_channelLayout));
864 }
865
866 double CAESinkDARWINOSX::GetDelay()
867 {
868   if (m_buffer)
869   {
870     // Calculate the duration of the data in the cache
871     double delay = (double)m_buffer->GetReadSize() / (double)m_format.m_frameSize;
872     delay += (double)m_latentFrames;
873     delay /= (double)m_format.m_sampleRate;
874     return delay;
875   }
876   return 0.0;
877 }
878
879 double CAESinkDARWINOSX::GetCacheTotal()
880 {
881   return (double)m_buffer->GetMaxSize() / (double)(m_format.m_frameSize * m_format.m_sampleRate);
882 }
883
884 CCriticalSection mutex;
885 XbmcThreads::ConditionVariable condVar;
886
887 unsigned int CAESinkDARWINOSX::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
888 {
889   if (m_buffer->GetWriteSize() < frames * m_format.m_frameSize)
890   { // no space to write - wait for a bit
891     CSingleLock lock(mutex);
892     unsigned int timeout = 900 * frames / m_format.m_sampleRate;
893     if (!m_started)
894       timeout = 4500;
895
896     // we are using a timer here for beeing sure for timeouts
897     // condvar can be woken spuriously as signaled
898     XbmcThreads::EndTime timer(timeout);
899     condVar.wait(mutex, timeout);
900     if (!m_started && timer.IsTimePast())
901     {
902       CLog::Log(LOGERROR, "%s engine didn't start in %d ms!", __FUNCTION__, timeout);
903       return INT_MAX;    
904     }
905   }
906
907   unsigned int write_frames = std::min(frames, m_buffer->GetWriteSize() / m_format.m_frameSize);
908   if (write_frames)
909     m_buffer->Write(data, write_frames * m_format.m_frameSize);
910
911   return write_frames;
912 }
913
914 void CAESinkDARWINOSX::Drain()
915 {
916   int bytes = m_buffer->GetReadSize();
917   int totalBytes = bytes;
918   int maxNumTimeouts = 3;
919   unsigned int timeout = 900 * bytes / (m_format.m_sampleRate * m_format.m_frameSize);
920   while (bytes && maxNumTimeouts > 0)
921   {
922     CSingleLock lock(mutex);
923     XbmcThreads::EndTime timer(timeout);
924     condVar.wait(mutex, timeout);
925
926     bytes = m_buffer->GetReadSize();
927     // if we timeout and don't
928     // consum bytes - decrease maxNumTimeouts
929     if (timer.IsTimePast() && bytes == totalBytes)
930       maxNumTimeouts--;
931     totalBytes = bytes;
932   }
933 }
934
935 void CAESinkDARWINOSX::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
936 {
937   EnumerateDevices();
938   list.clear();
939   for (CADeviceList::const_iterator i = s_devices.begin(); i != s_devices.end(); ++i)
940     list.push_back(i->second);
941 }
942
943 inline void LogLevel(unsigned int got, unsigned int wanted)
944 {
945   static unsigned int lastReported = INT_MAX;
946   if (got != wanted)
947   {
948     if (got != lastReported)
949     {
950       CLog::Log(LOGWARNING, "DARWINOSX: %sflow (%u vs %u bytes)", got > wanted ? "over" : "under", got, wanted);
951       lastReported = got;
952     }    
953   }
954   else
955     lastReported = INT_MAX; // indicate we were good at least once
956 }
957
958 OSStatus CAESinkDARWINOSX::renderCallback(AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* inClientData)
959 {
960   CAESinkDARWINOSX *sink = (CAESinkDARWINOSX*)inClientData;
961
962   sink->m_started = true;
963   if (sink->m_planar)
964   {
965     unsigned int channels = std::min((unsigned int)outOutputData->mNumberBuffers, sink->m_format.m_channelLayout.Count());
966     unsigned int wanted = outOutputData->mBuffers[0].mDataByteSize;
967     unsigned int bytes = std::min(sink->m_buffer->GetReadSize() / channels, wanted);
968     sink->m_buffer->Read((unsigned char *)sink->m_planarBuffer, bytes * channels);
969     // transform from interleaved to planar
970     const float *src = sink->m_planarBuffer;
971     for (unsigned int i = 0; i < bytes / sizeof(float); i++)
972     {
973       for (unsigned int j = 0; j < channels; j++)
974       {
975         float *dst = (float *)outOutputData->mBuffers[j].mData;
976         dst[i] = *src++;
977       }
978     }
979     LogLevel(bytes, wanted);
980     // tell the sink we're good for more data
981     condVar.notifyAll();
982   }
983   else
984   {
985     for (unsigned int i = 0; i < outOutputData->mNumberBuffers; i++)
986     {
987       // NULL indicates a disabled stream
988       // skip it...
989       if (outOutputData->mBuffers[i].mData == NULL)
990         continue;
991
992       if (sink->m_outputBitstream)
993       {
994         /* HACK for bitstreaming AC3/DTS via PCM.
995          We reverse the float->S16LE conversion done in the stream or device */
996         static const float mul = 1.0f / (INT16_MAX + 1);
997
998         unsigned int wanted = std::min(outOutputData->mBuffers[i].mDataByteSize / sizeof(float), (size_t)sink->m_format.m_frameSamples)  * sizeof(int16_t);
999         if (wanted <= sink->m_buffer->GetReadSize())
1000         {
1001           sink->m_buffer->Read((unsigned char *)sink->m_outputBuffer, wanted);
1002           int16_t *src = sink->m_outputBuffer;
1003           float  *dest = (float*)outOutputData->mBuffers[i].mData;
1004           for (unsigned int i = 0; i < wanted / 2; i++)
1005             *dest++ = *src++ * mul;
1006         }
1007       }
1008       else
1009       {
1010         /* buffers appear to come from CA already zero'd, so just copy what is wanted */
1011         unsigned int wanted = outOutputData->mBuffers[i].mDataByteSize;
1012         unsigned int bytes = std::min(sink->m_buffer->GetReadSize(), wanted);
1013         sink->m_buffer->Read((unsigned char*)outOutputData->mBuffers[i].mData, bytes);
1014         LogLevel(bytes, wanted);
1015       }
1016
1017       // tell the sink we're good for more data
1018       condVar.notifyAll();
1019     }
1020   }
1021   return noErr;
1022 }