Merge pull request #4875 from koying/fixdroidremotekeyboard
[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       //treat all other digital devices as HDMI to let options open to the user
443       if (device.m_deviceType == AE_DEVTYPE_PCM)
444         device.m_deviceType = AE_DEVTYPE_HDMI;
445     }
446
447     // devicename based overwrites from former code - maybe FIXME at some point when we
448     // are sure that the upper detection does its job in all[tm] use cases
449     if (hasHdmiName)
450       device.m_deviceType = AE_DEVTYPE_HDMI;
451     if (hasDisplayPortName)
452       device.m_deviceType = AE_DEVTYPE_DP;
453       
454     //get channel map to match the devices channel layout as set in audio-midi-setup
455     GetAEChannelMap(caDevice, device.m_channels, caDevice.GetTotalOutputChannels());
456     
457     list.push_back(std::make_pair(deviceID, device));
458     //in the first place of the list add the default device
459     //with name "default" - if this is selected
460     //we will output to whatever osx claims to be default
461     //(allows transition from headphones to speaker and stuff
462     //like that
463     if(defaultDeviceName == device.m_deviceName)
464     {
465       device.m_deviceName = "default";
466       device.m_displayName = "Default";
467       list.insert(list.begin(), std::make_pair(deviceID, device));
468     }
469
470     deviceIDList.pop_front();
471   }
472 }
473
474 /* static, threadsafe access to the device list */
475 static CADeviceList     s_devices;
476 static CCriticalSection s_devicesLock;
477
478 static void EnumerateDevices()
479 {
480   CADeviceList devices;
481   EnumerateDevices(devices);
482   {
483     CSingleLock lock(s_devicesLock);
484     s_devices = devices;
485   }
486 }
487
488 static CADeviceList GetDevices()
489 {
490   CADeviceList list;
491   {
492     CSingleLock lock(s_devicesLock);
493     list = s_devices;
494   }
495   return list;
496 }
497
498 OSStatus deviceChangedCB(AudioObjectID                       inObjectID,
499                          UInt32                              inNumberAddresses,
500                          const AudioObjectPropertyAddress    inAddresses[],
501                          void*                               inClientData)
502 {
503   bool deviceChanged = false;
504   static AudioDeviceID oldDefaultDevice = 0;
505   AudioDeviceID currentDefaultOutputDevice = 0;
506
507   for (unsigned int i = 0; i < inNumberAddresses; i++)
508   {
509     switch (inAddresses[i].mSelector)
510     {
511       case kAudioHardwarePropertyDefaultOutputDevice:
512         currentDefaultOutputDevice = CCoreAudioHardware::GetDefaultOutputDevice();
513         // This listener is called on every change of the hardware
514         // device. So check if the default device has really changed.
515         if (oldDefaultDevice != currentDefaultOutputDevice)
516         {
517           deviceChanged = true;
518           oldDefaultDevice = currentDefaultOutputDevice;
519         }
520         break;
521       default:
522         deviceChanged = true;
523         break;
524     }
525     if (deviceChanged)
526       break;
527   }
528
529   if  (deviceChanged)
530   {
531     CLog::Log(LOGDEBUG, "CoreAudio: audiodevicelist changed - reenumerating");
532     CAEFactory::DeviceChange();
533     CLog::Log(LOGDEBUG, "CoreAudio: audiodevicelist changed - done");
534   }
535   return noErr;
536 }
537
538 void RegisterDeviceChangedCB(bool bRegister, void *ref)
539 {
540   OSStatus ret = noErr;
541   AudioObjectPropertyAddress inAdr =
542   {
543     kAudioHardwarePropertyDevices,
544     kAudioObjectPropertyScopeGlobal,
545     kAudioObjectPropertyElementMaster
546   };
547
548   if (bRegister)
549   {
550     ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
551     inAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
552     ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
553   }
554   else
555   {
556     ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
557     inAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
558     ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
559   }
560
561   if (ret != noErr)
562     CLog::Log(LOGERROR, "CCoreAudioAE::Deinitialize - error %s a listener callback for device changes!", bRegister?"attaching":"removing");
563 }
564
565
566 ////////////////////////////////////////////////////////////////////////////////////////////
567 CAESinkDARWINOSX::CAESinkDARWINOSX()
568 : m_latentFrames(0), m_outputBitstream(false), m_outputBuffer(NULL), m_planar(false), m_planarBuffer(NULL), m_buffer(NULL)
569 {
570   // By default, kAudioHardwarePropertyRunLoop points at the process's main thread on SnowLeopard,
571   // If your process lacks such a run loop, you can set kAudioHardwarePropertyRunLoop to NULL which
572   // tells the HAL to run it's own thread for notifications (which was the default prior to SnowLeopard).
573   // So tell the HAL to use its own thread for similar behavior under all supported versions of OSX.
574   CFRunLoopRef theRunLoop = NULL;
575   AudioObjectPropertyAddress theAddress = {
576     kAudioHardwarePropertyRunLoop,
577     kAudioObjectPropertyScopeGlobal,
578     kAudioObjectPropertyElementMaster
579   };
580   OSStatus theError = AudioObjectSetPropertyData(kAudioObjectSystemObject,
581                                                  &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
582   if (theError != noErr)
583   {
584     CLog::Log(LOGERROR, "CCoreAudioAE::constructor: kAudioHardwarePropertyRunLoop error.");
585   }
586   RegisterDeviceChangedCB(true, this);
587   m_started = false;
588   m_planar = false;
589 }
590
591 CAESinkDARWINOSX::~CAESinkDARWINOSX()
592 {
593   RegisterDeviceChangedCB(false, this);
594 }
595
596 float scoreSampleRate(Float64 destinationRate, unsigned int sourceRate)
597 {
598   float score = 0;
599   double intPortion;
600   double fracPortion = modf(destinationRate / sourceRate, &intPortion);
601
602   score += (1 - fracPortion) * 1000;      // prefer sample rates that are multiples of the source sample rate
603   score += (intPortion == 1.0) ? 500 : 0;   // prefer exact matches over other multiples
604   score += (intPortion > 1 && intPortion < 100) ? (100 - intPortion) / 100 * 100 : 0; // prefer smaller multiples otherwise
605
606   return score;
607 }
608
609 float ScoreStream(const AudioStreamBasicDescription &desc, const AEAudioFormat &format)
610 {
611   float score = 0;
612   if (format.m_dataFormat == AE_FMT_AC3 ||
613       format.m_dataFormat == AE_FMT_DTS)
614   {
615     if (desc.mFormatID == kAudioFormat60958AC3 ||
616         desc.mFormatID == 'IAC3' ||
617         desc.mFormatID == kAudioFormatAC3)
618     {
619       if (desc.mSampleRate == format.m_sampleRate &&
620           desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat) &&
621           desc.mChannelsPerFrame == format.m_channelLayout.Count())
622       {
623         // perfect match
624         score = FLT_MAX;
625       }
626     }
627   }
628   if (format.m_dataFormat == AE_FMT_AC3 ||
629       format.m_dataFormat == AE_FMT_DTS ||
630       format.m_dataFormat == AE_FMT_EAC3)
631   { // we should be able to bistreaming in PCM if the samplerate, bitdepth and channels match
632     if (desc.mSampleRate       == format.m_sampleRate                            &&
633         desc.mBitsPerChannel   == CAEUtil::DataFormatToBits(format.m_dataFormat) &&
634         desc.mChannelsPerFrame == format.m_channelLayout.Count()                 &&
635         desc.mFormatID         == kAudioFormatLinearPCM)
636     {
637       score = FLT_MAX / 2;
638     }
639   }
640   else
641   { // non-passthrough, whatever works is fine
642     if (desc.mFormatID == kAudioFormatLinearPCM)
643     {
644       score += scoreSampleRate(desc.mSampleRate, format.m_sampleRate);
645
646       if (desc.mChannelsPerFrame == format.m_channelLayout.Count())
647         score += 5;
648       else if (desc.mChannelsPerFrame > format.m_channelLayout.Count())
649         score += 1;
650       if (format.m_dataFormat == AE_FMT_FLOAT)
651       { // for float, prefer the highest bitdepth we have
652         if (desc.mBitsPerChannel >= 16)
653           score += (desc.mBitsPerChannel / 8);
654       }
655       else
656       {
657         if (desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat))
658           score += 5;
659         else if (desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat))
660           score += 1;
661       }
662     }
663   }
664   return score;
665 }
666
667 bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device)
668 {
669   AudioDeviceID deviceID = 0;
670   CADeviceList devices = GetDevices();
671   if (StringUtils::EqualsNoCase(device, "default"))
672   {
673     CCoreAudioHardware::GetOutputDeviceName(device);
674     deviceID = CCoreAudioHardware::GetDefaultOutputDevice();
675     CLog::Log(LOGNOTICE, "%s: Opening default device %s", __PRETTY_FUNCTION__, device.c_str());
676   }
677   else
678   {
679     for (size_t i = 0; i < devices.size(); i++)
680     {
681       if (device.find(devices[i].second.m_deviceName) != std::string::npos)
682       {
683         deviceID = devices[i].first;
684         break;
685       }
686     }
687   }
688
689   if (!deviceID)
690   {
691     CLog::Log(LOGERROR, "%s: Unable to find device %s", __FUNCTION__, device.c_str());
692     return false;
693   }
694
695   m_device.Open(deviceID);
696
697   // Fetch a list of the streams defined by the output device
698   AudioStreamIdList streams;
699   m_device.GetStreams(&streams);
700
701   CLog::Log(LOGDEBUG, "%s: Finding stream for format %s", __FUNCTION__, CAEUtil::DataFormatToStr(format.m_dataFormat));
702
703   bool                        passthrough  = false;
704   UInt32                      outputIndex  = 0;
705   UInt32                      numOutputChannels = 0;
706   float                       outputScore  = 0;
707   AudioStreamBasicDescription outputFormat = {0};
708   AudioStreamID               outputStream = 0;
709
710   /* The theory is to score based on
711    1. Matching passthrough characteristics (i.e. passthrough flag)
712    2. Matching sample rate.
713    3. Matching bits per channel (or higher).
714    4. Matching number of channels (or higher).
715    */
716   UInt32 index = 0;
717   for (AudioStreamIdList::const_iterator i = streams.begin(); i != streams.end(); ++i)
718   {
719     // Probe physical formats
720     StreamFormatList formats;
721     CCoreAudioStream::GetAvailablePhysicalFormats(*i, &formats);
722     for (StreamFormatList::const_iterator j = formats.begin(); j != formats.end(); ++j)
723     {
724       AudioStreamBasicDescription desc = j->mFormat;
725
726       // for devices with kAudioStreamAnyRate
727       // assume that the user uses a fixed config
728       // and knows what he is doing - so we use
729       // the requested samplerate here
730       if (desc.mSampleRate == kAudioStreamAnyRate)
731         desc.mSampleRate = format.m_sampleRate;
732
733       float score = ScoreStream(desc, format);
734
735       std::string formatString;
736       CLog::Log(LOGDEBUG, "%s: Physical Format: %s rated %f", __FUNCTION__, StreamDescriptionToString(desc, formatString), score);
737
738       if (score > outputScore)
739       {
740         passthrough  = score > 10000;
741         outputScore  = score;
742         outputFormat = desc;
743         outputStream = *i;
744         outputIndex  = index;
745       }
746     }
747     index++;
748   }
749
750   m_planar = false;
751   numOutputChannels = outputFormat.mChannelsPerFrame;
752   if (streams.size() > 1 && outputFormat.mChannelsPerFrame == 1)
753   {
754     numOutputChannels = std::min((size_t)format.m_channelLayout.Count(), streams.size());
755     m_planar = true;
756     CLog::Log(LOGDEBUG, "%s Found planar audio with %u channels using %u of them.", __FUNCTION__, (unsigned int)streams.size(), (unsigned int)numOutputChannels);
757   }
758
759   if (!outputFormat.mFormatID)
760   {
761     CLog::Log(LOGERROR, "%s, Unable to find suitable stream", __FUNCTION__);
762     return false;
763   }
764
765   /* Update our AE format */
766   format.m_sampleRate    = outputFormat.mSampleRate;
767   
768   m_outputBitstream   = passthrough && outputFormat.mFormatID == kAudioFormatLinearPCM;
769
770   std::string formatString;
771   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" : "");
772
773   SetHogMode(passthrough);
774
775   // Configure the output stream object
776   m_outputStream.Open(outputStream);
777
778   AudioStreamBasicDescription virtualFormat, previousPhysicalFormat;
779   m_outputStream.GetVirtualFormat(&virtualFormat);
780   m_outputStream.GetPhysicalFormat(&previousPhysicalFormat);
781   CLog::Log(LOGDEBUG, "%s: Previous Virtual Format: %s", __FUNCTION__, StreamDescriptionToString(virtualFormat, formatString));
782   CLog::Log(LOGDEBUG, "%s: Previous Physical Format: %s", __FUNCTION__, StreamDescriptionToString(previousPhysicalFormat, formatString));
783
784   m_outputStream.SetPhysicalFormat(&outputFormat); // Set the active format (the old one will be reverted when we close)
785   m_outputStream.GetVirtualFormat(&virtualFormat);
786   CLog::Log(LOGDEBUG, "%s: New Virtual Format: %s", __FUNCTION__, StreamDescriptionToString(virtualFormat, formatString));
787   CLog::Log(LOGDEBUG, "%s: New Physical Format: %s", __FUNCTION__, StreamDescriptionToString(outputFormat, formatString));
788
789   // update the channel map based on the new stream format
790   GetAEChannelMap(m_device, format.m_channelLayout, numOutputChannels);
791
792
793   m_latentFrames = m_device.GetNumLatencyFrames();
794   m_latentFrames += m_outputStream.GetNumLatencyFrames();
795
796   /* TODO: Should we use the virtual format to determine our data format? */
797   format.m_frameSize     = format.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
798   format.m_frames        = m_device.GetBufferSize();
799   format.m_frameSamples  = format.m_frames * format.m_channelLayout.Count();
800
801   if (m_outputBitstream)
802   {
803     m_outputBuffer = new int16_t[format.m_frameSamples];
804     /* TODO: Do we need this? */
805     m_device.SetNominalSampleRate(format.m_sampleRate);
806   }
807
808   if (m_planar)
809     m_planarBuffer = new float[format.m_frameSamples];
810
811   unsigned int num_buffers = 4;
812   m_buffer = new AERingBuffer(num_buffers * format.m_frames * format.m_frameSize);
813   CLog::Log(LOGDEBUG, "%s: using buffer size: %u (%f ms)", __FUNCTION__, m_buffer->GetMaxSize(), (float)m_buffer->GetMaxSize() / (format.m_sampleRate * format.m_frameSize));
814
815   m_format = format;
816   if (passthrough)
817     format.m_dataFormat = AE_FMT_S16NE;
818   else
819     format.m_dataFormat = AE_FMT_FLOAT;
820
821   // Register for data request callbacks from the driver and start
822   m_device.AddIOProc(renderCallback, this);
823   m_device.Start();
824   return true;
825 }
826
827 void CAESinkDARWINOSX::SetHogMode(bool on)
828 {
829   // TODO: Auto hogging sets this for us. Figure out how/when to turn it off or use it
830   // It appears that leaving this set will aslo restore the previous stream format when the
831   // Application exits. If auto hogging is set and we try to set hog mode, we will deadlock
832   // 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."
833
834   // Lock down the device.  This MUST be done PRIOR to switching to a non-mixable format, if it is done at all
835   // If it is attempted after the format change, there is a high likelihood of a deadlock
836   // We may need to do this sooner to enable mix-disable (i.e. before setting the stream format)
837   if (on)
838   {
839     // Auto-Hog does not always un-hog the device when changing back to a mixable mode.
840     // Handle this on our own until it is fixed.
841     CCoreAudioHardware::SetAutoHogMode(false);
842     bool autoHog = CCoreAudioHardware::GetAutoHogMode();
843     CLog::Log(LOGDEBUG, " CoreAudioRenderer::InitializeEncoded: "
844               "Auto 'hog' mode is set to '%s'.", autoHog ? "On" : "Off");
845     if (autoHog)
846       return;
847   }
848   m_device.SetHogStatus(on);
849   m_device.SetMixingSupport(!on);
850 }
851
852 void CAESinkDARWINOSX::Deinitialize()
853 {
854   m_device.Stop();
855   m_device.RemoveIOProc();
856
857   m_outputStream.Close();
858   m_device.Close();
859   if (m_buffer)
860   {
861     delete m_buffer;
862     m_buffer = NULL;
863   }
864   m_outputBitstream = false;
865
866   delete[] m_outputBuffer;
867   m_outputBuffer = NULL;
868
869   m_planar = false;
870   delete[] m_planarBuffer;
871   m_planarBuffer = NULL;
872
873   m_started = false;
874 }
875
876 bool CAESinkDARWINOSX::IsCompatible(const AEAudioFormat &format, const std::string &device)
877 {
878   return ((m_format.m_sampleRate    == format.m_sampleRate) &&
879           (m_format.m_dataFormat    == format.m_dataFormat) &&
880           (m_format.m_channelLayout == format.m_channelLayout));
881 }
882
883 double CAESinkDARWINOSX::GetDelay()
884 {
885   if (m_buffer)
886   {
887     // Calculate the duration of the data in the cache
888     double delay = (double)m_buffer->GetReadSize() / (double)m_format.m_frameSize;
889     delay += (double)m_latentFrames;
890     delay /= (double)m_format.m_sampleRate;
891     return delay;
892   }
893   return 0.0;
894 }
895
896 double CAESinkDARWINOSX::GetCacheTotal()
897 {
898   return (double)m_buffer->GetMaxSize() / (double)(m_format.m_frameSize * m_format.m_sampleRate);
899 }
900
901 CCriticalSection mutex;
902 XbmcThreads::ConditionVariable condVar;
903
904 unsigned int CAESinkDARWINOSX::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
905 {
906   if (m_buffer->GetWriteSize() < frames * m_format.m_frameSize)
907   { // no space to write - wait for a bit
908     CSingleLock lock(mutex);
909     unsigned int timeout = 900 * frames / m_format.m_sampleRate;
910     if (!m_started)
911       timeout = 4500;
912
913     // we are using a timer here for beeing sure for timeouts
914     // condvar can be woken spuriously as signaled
915     XbmcThreads::EndTime timer(timeout);
916     condVar.wait(mutex, timeout);
917     if (!m_started && timer.IsTimePast())
918     {
919       CLog::Log(LOGERROR, "%s engine didn't start in %d ms!", __FUNCTION__, timeout);
920       return INT_MAX;    
921     }
922   }
923
924   unsigned int write_frames = std::min(frames, m_buffer->GetWriteSize() / m_format.m_frameSize);
925   if (write_frames)
926     m_buffer->Write(data, write_frames * m_format.m_frameSize);
927
928   return write_frames;
929 }
930
931 void CAESinkDARWINOSX::Drain()
932 {
933   int bytes = m_buffer->GetReadSize();
934   int totalBytes = bytes;
935   int maxNumTimeouts = 3;
936   unsigned int timeout = 900 * bytes / (m_format.m_sampleRate * m_format.m_frameSize);
937   while (bytes && maxNumTimeouts > 0)
938   {
939     CSingleLock lock(mutex);
940     XbmcThreads::EndTime timer(timeout);
941     condVar.wait(mutex, timeout);
942
943     bytes = m_buffer->GetReadSize();
944     // if we timeout and don't
945     // consum bytes - decrease maxNumTimeouts
946     if (timer.IsTimePast() && bytes == totalBytes)
947       maxNumTimeouts--;
948     totalBytes = bytes;
949   }
950 }
951
952 void CAESinkDARWINOSX::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
953 {
954   EnumerateDevices();
955   list.clear();
956   for (CADeviceList::const_iterator i = s_devices.begin(); i != s_devices.end(); ++i)
957     list.push_back(i->second);
958 }
959
960 inline void LogLevel(unsigned int got, unsigned int wanted)
961 {
962   static unsigned int lastReported = INT_MAX;
963   if (got != wanted)
964   {
965     if (got != lastReported)
966     {
967       CLog::Log(LOGWARNING, "DARWINOSX: %sflow (%u vs %u bytes)", got > wanted ? "over" : "under", got, wanted);
968       lastReported = got;
969     }    
970   }
971   else
972     lastReported = INT_MAX; // indicate we were good at least once
973 }
974
975 OSStatus CAESinkDARWINOSX::renderCallback(AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* inClientData)
976 {
977   CAESinkDARWINOSX *sink = (CAESinkDARWINOSX*)inClientData;
978
979   sink->m_started = true;
980   if (sink->m_planar)
981   {
982     unsigned int channels = std::min((unsigned int)outOutputData->mNumberBuffers, sink->m_format.m_channelLayout.Count());
983     unsigned int wanted = outOutputData->mBuffers[0].mDataByteSize;
984     unsigned int bytes = std::min(sink->m_buffer->GetReadSize() / channels, wanted);
985     sink->m_buffer->Read((unsigned char *)sink->m_planarBuffer, bytes * channels);
986     // transform from interleaved to planar
987     const float *src = sink->m_planarBuffer;
988     for (unsigned int i = 0; i < bytes / sizeof(float); i++)
989     {
990       for (unsigned int j = 0; j < channels; j++)
991       {
992         float *dst = (float *)outOutputData->mBuffers[j].mData;
993         dst[i] = *src++;
994       }
995     }
996     LogLevel(bytes, wanted);
997     // tell the sink we're good for more data
998     condVar.notifyAll();
999   }
1000   else
1001   {
1002     for (unsigned int i = 0; i < outOutputData->mNumberBuffers; i++)
1003     {
1004       // NULL indicates a disabled stream
1005       // skip it...
1006       if (outOutputData->mBuffers[i].mData == NULL)
1007         continue;
1008
1009       if (sink->m_outputBitstream)
1010       {
1011         /* HACK for bitstreaming AC3/DTS via PCM.
1012          We reverse the float->S16LE conversion done in the stream or device */
1013         static const float mul = 1.0f / (INT16_MAX + 1);
1014
1015         unsigned int wanted = std::min(outOutputData->mBuffers[i].mDataByteSize / sizeof(float), (size_t)sink->m_format.m_frameSamples)  * sizeof(int16_t);
1016         if (wanted <= sink->m_buffer->GetReadSize())
1017         {
1018           sink->m_buffer->Read((unsigned char *)sink->m_outputBuffer, wanted);
1019           int16_t *src = sink->m_outputBuffer;
1020           float  *dest = (float*)outOutputData->mBuffers[i].mData;
1021           for (unsigned int i = 0; i < wanted / 2; i++)
1022             *dest++ = *src++ * mul;
1023         }
1024       }
1025       else
1026       {
1027         /* buffers appear to come from CA already zero'd, so just copy what is wanted */
1028         unsigned int wanted = outOutputData->mBuffers[i].mDataByteSize;
1029         unsigned int bytes = std::min(sink->m_buffer->GetReadSize(), wanted);
1030         sink->m_buffer->Read((unsigned char*)outOutputData->mBuffers[i].mData, bytes);
1031         LogLevel(bytes, wanted);
1032       }
1033
1034       // tell the sink we're good for more data
1035       condVar.notifyAll();
1036     }
1037   }
1038   return noErr;
1039 }