2 * Copyright (C) 2005-2014 Team XBMC
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)
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.
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/>.
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"
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 ,
41 static bool HasSampleRate(const AESampleRateList &list, const unsigned int samplerate)
43 for (size_t i = 0; i < list.size(); ++i)
45 if (list[i] == samplerate)
51 static bool HasDataFormat(const AEDataFormatList &list, const enum AEDataFormat format)
53 for (size_t i = 0; i < list.size(); ++i)
55 if (list[i] == format)
61 typedef std::vector< std::pair<AudioDeviceID, CAEDeviceInfo> > CADeviceList;
63 static void EnumerateDevices(CADeviceList &list)
67 std::string defaultDeviceName;
68 CCoreAudioHardware::GetOutputDeviceName(defaultDeviceName);
70 CoreAudioDeviceList deviceIDList;
71 CCoreAudioHardware::GetOutputDevices(&deviceIDList);
72 while (!deviceIDList.empty())
74 AudioDeviceID deviceID = deviceIDList.front();
75 CCoreAudioDevice caDevice(deviceID);
77 device.m_channels.Reset();
78 device.m_dataFormats.clear();
79 device.m_sampleRates.clear();
81 device.m_deviceType = AE_DEVTYPE_PCM;
82 device.m_deviceName = caDevice.GetName();
83 device.m_displayName = device.m_deviceName;
84 device.m_displayNameExtra = "";
86 if (device.m_deviceName.find("HDMI") != std::string::npos)
87 device.m_deviceType = AE_DEVTYPE_HDMI;
89 CLog::Log(LOGDEBUG, "EnumerateDevices:Device(%s)" , device.m_deviceName.c_str());
90 AudioStreamIdList streams;
91 if (caDevice.GetStreams(&streams))
93 for (AudioStreamIdList::iterator j = streams.begin(); j != streams.end(); ++j)
95 StreamFormatList streams;
96 if (CCoreAudioStream::GetAvailablePhysicalFormats(*j, &streams))
98 for (StreamFormatList::iterator i = streams.begin(); i != streams.end(); ++i)
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)
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;
118 AEDataFormat format = AE_FMT_INVALID;
119 switch(desc.mBitsPerChannel)
122 if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian)
123 format = AE_FMT_S16BE;
126 /* Passthrough is possible with a 2ch digital output */
127 if (desc.mChannelsPerFrame == 2 && CCoreAudioStream::IsDigitalOuptut(*j))
129 if (desc.mSampleRate == 48000)
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);
136 else if (desc.mSampleRate == 192000)
138 if (!HasDataFormat(device.m_dataFormats, AE_FMT_EAC3))
139 device.m_dataFormats.push_back(AE_FMT_EAC3);
142 format = AE_FMT_S16LE;
146 if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian)
147 format = AE_FMT_S24BE3;
149 format = AE_FMT_S24LE3;
152 if (desc.mFormatFlags & kAudioFormatFlagIsFloat)
153 format = AE_FMT_FLOAT;
156 if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian)
157 format = AE_FMT_S32BE;
159 format = AE_FMT_S32LE;
163 if (format != AE_FMT_INVALID && !HasDataFormat(device.m_dataFormats, format))
164 device.m_dataFormats.push_back(format);
169 CAEChannelInfo channel_info;
170 for (UInt32 chan = 0; chan < CA_MAX_CHANNELS && chan < desc.mChannelsPerFrame; ++chan)
172 if (!device.m_channels.HasChannel(CAChannelMap[chan]))
173 device.m_channels += CAChannelMap[chan];
174 channel_info += CAChannelMap[chan];
177 // add sample rate info
178 if (!HasSampleRate(device.m_sampleRates, desc.mSampleRate))
179 device.m_sampleRates.push_back(desc.mSampleRate);
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
191 if(defaultDeviceName == device.m_deviceName)
193 device.m_deviceName = "default";
194 device.m_displayName = "Default";
195 list.insert(list.begin(), std::make_pair(deviceID, device));
198 deviceIDList.pop_front();
202 /* static, threadsafe access to the device list */
203 static CADeviceList s_devices;
204 static CCriticalSection s_devicesLock;
206 static void EnumerateDevices()
208 CADeviceList devices;
209 EnumerateDevices(devices);
211 CSingleLock lock(s_devicesLock);
216 static CADeviceList GetDevices()
220 CSingleLock lock(s_devicesLock);
226 OSStatus deviceChangedCB(AudioObjectID inObjectID,
227 UInt32 inNumberAddresses,
228 const AudioObjectPropertyAddress inAddresses[],
231 CLog::Log(LOGDEBUG, "CoreAudio: audiodevicelist changed - reenumerating");
232 CAEFactory::DeviceChange();
233 CLog::Log(LOGDEBUG, "CoreAudio: audiodevicelist changed - done");
237 void RegisterDeviceChangedCB(bool bRegister, void *ref)
239 OSStatus ret = noErr;
240 const AudioObjectPropertyAddress inAdr =
242 kAudioHardwarePropertyDevices,
243 kAudioObjectPropertyScopeGlobal,
244 kAudioObjectPropertyElementMaster
248 ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
250 ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
253 CLog::Log(LOGERROR, "CCoreAudioAE::Deinitialize - error %s a listener callback for device changes!", bRegister?"attaching":"removing");
257 ////////////////////////////////////////////////////////////////////////////////////////////
258 CAESinkDARWINOSX::CAESinkDARWINOSX()
259 : m_latentFrames(0), m_outputBitstream(false), m_outputBuffer(NULL), m_buffer(NULL)
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
271 OSStatus theError = AudioObjectSetPropertyData(kAudioObjectSystemObject,
272 &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
273 if (theError != noErr)
275 CLog::Log(LOGERROR, "CCoreAudioAE::constructor: kAudioHardwarePropertyRunLoop error.");
277 RegisterDeviceChangedCB(true, this);
281 CAESinkDARWINOSX::~CAESinkDARWINOSX()
283 RegisterDeviceChangedCB(false, this);
286 float ScoreStream(const AudioStreamBasicDescription &desc, const AEAudioFormat &format)
289 if (format.m_dataFormat == AE_FMT_AC3 ||
290 format.m_dataFormat == AE_FMT_DTS)
292 if (desc.mFormatID == kAudioFormat60958AC3 ||
293 desc.mFormatID == 'IAC3' ||
294 desc.mFormatID == kAudioFormatAC3)
296 if (desc.mSampleRate == format.m_sampleRate &&
297 desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat) &&
298 desc.mChannelsPerFrame == format.m_channelLayout.Count())
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)
318 { // non-passthrough, whatever works is fine
319 if (desc.mFormatID == kAudioFormatLinearPCM)
321 if (desc.mSampleRate == format.m_sampleRate)
323 else if (desc.mSampleRate > format.m_sampleRate)
325 if (desc.mChannelsPerFrame == format.m_channelLayout.Count())
327 else if (desc.mChannelsPerFrame > format.m_channelLayout.Count())
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);
336 if (desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat))
338 else if (desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat))
346 bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device)
348 AudioDeviceID deviceID = 0;
349 CADeviceList devices = GetDevices();
350 if (StringUtils::EqualsNoCase(device, "default"))
352 CCoreAudioHardware::GetOutputDeviceName(device);
353 CLog::Log(LOGNOTICE, "%s: Opening default device %s", __PRETTY_FUNCTION__, device.c_str());
356 for (size_t i = 0; i < devices.size(); i++)
358 if (device.find(devices[i].second.m_deviceName) != std::string::npos)
360 m_info = devices[i].second;
361 deviceID = devices[i].first;
367 CLog::Log(LOGERROR, "%s: Unable to find device %s", __FUNCTION__, device.c_str());
371 m_device.Open(deviceID);
373 // Fetch a list of the streams defined by the output device
374 AudioStreamIdList streams;
375 m_device.GetStreams(&streams);
377 CLog::Log(LOGDEBUG, "%s: Finding stream for format %s", __FUNCTION__, CAEUtil::DataFormatToStr(format.m_dataFormat));
379 bool passthrough = false;
380 UInt32 outputIndex = 0;
381 float outputScore = 0;
382 AudioStreamBasicDescription outputFormat = {0};
383 AudioStreamID outputStream = 0;
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).
392 for (AudioStreamIdList::const_iterator i = streams.begin(); i != streams.end(); ++i)
394 // Probe physical formats
395 StreamFormatList formats;
396 CCoreAudioStream::GetAvailablePhysicalFormats(*i, &formats);
397 for (StreamFormatList::const_iterator j = formats.begin(); j != formats.end(); ++j)
399 const AudioStreamBasicDescription &desc = j->mFormat;
401 float score = ScoreStream(desc, format);
403 std::string formatString;
404 CLog::Log(LOGDEBUG, "%s: Physical Format: %s rated %f", __FUNCTION__, StreamDescriptionToString(desc, formatString), score);
406 if (score > outputScore)
408 passthrough = score > 1000;
418 if (!outputFormat.mFormatID)
420 CLog::Log(LOGERROR, "%s, Unable to find suitable stream", __FUNCTION__);
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];
434 m_outputBitstream = passthrough && outputFormat.mFormatID == kAudioFormatLinearPCM;
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" : "");
439 SetHogMode(passthrough);
441 // Configure the output stream object
442 m_outputStream.Open(outputStream);
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));
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));
455 m_latentFrames = m_device.GetNumLatencyFrames();
456 m_latentFrames += m_outputStream.GetNumLatencyFrames();
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();
463 if (m_outputBitstream)
465 m_outputBuffer = new int16_t[format.m_frameSamples];
466 /* TODO: Do we need this? */
467 m_device.SetNominalSampleRate(format.m_sampleRate);
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));
476 format.m_dataFormat = AE_FMT_S16NE;
478 format.m_dataFormat = AE_FMT_FLOAT;
480 // Register for data request callbacks from the driver and start
481 m_device.AddIOProc(renderCallback, this);
486 void CAESinkDARWINOSX::SetHogMode(bool on)
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."
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)
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");
507 m_device.SetHogStatus(on);
508 m_device.SetMixingSupport(!on);
511 void CAESinkDARWINOSX::Deinitialize()
514 m_device.RemoveIOProc();
516 m_outputStream.Close();
523 m_outputBitstream = false;
525 delete[] m_outputBuffer;
526 m_outputBuffer = NULL;
531 bool CAESinkDARWINOSX::IsCompatible(const AEAudioFormat &format, const std::string &device)
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));
538 double CAESinkDARWINOSX::GetDelay()
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;
551 double CAESinkDARWINOSX::GetCacheTotal()
553 return (double)m_buffer->GetMaxSize() / (double)(m_format.m_frameSize * m_format.m_sampleRate);
556 CCriticalSection mutex;
557 XbmcThreads::ConditionVariable condVar;
559 unsigned int CAESinkDARWINOSX::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
561 if (m_buffer->GetWriteSize() < frames * m_format.m_frameSize)
562 { // no space to write - wait for a bit
563 CSingleLock lock(mutex);
567 condVar.wait(lock, 900 * frames / m_format.m_sampleRate);
570 unsigned int write_frames = std::min(frames, m_buffer->GetWriteSize() / m_format.m_frameSize);
572 m_buffer->Write(data, write_frames * m_format.m_frameSize);
577 void CAESinkDARWINOSX::Drain()
579 int bytes = m_buffer->GetReadSize();
582 CSingleLock lock(mutex);
583 condVar.wait(mutex, 900 * bytes / (m_format.m_sampleRate * m_format.m_frameSize));
584 bytes = m_buffer->GetReadSize();
588 void CAESinkDARWINOSX::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
592 for (CADeviceList::const_iterator i = s_devices.begin(); i != s_devices.end(); ++i)
593 list.push_back(i->second);
596 OSStatus CAESinkDARWINOSX::renderCallback(AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* inClientData)
598 CAESinkDARWINOSX *sink = (CAESinkDARWINOSX*)inClientData;
600 sink->m_started = true;
601 for (unsigned int i = 0; i < outOutputData->mNumberBuffers; i++)
603 if (sink->m_outputBitstream)
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);
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())
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;
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);
626 CLog::Log(LOGERROR, "%s: %sFLOW (%i vs %i) bytes", __FUNCTION__, bytes > wanted ? "OVER" : "UNDER", bytes, wanted);
629 // tell the sink we're good for more data