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_outputBufferIndex(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_outputBufferIndex = outputIndex;
435 m_outputBitstream = passthrough && outputFormat.mFormatID == kAudioFormatLinearPCM;
437 std::string formatString;
438 CLog::Log(LOGDEBUG, "%s: Selected stream[%u] - id: 0x%04X, Physical Format: %s %s", __FUNCTION__, m_outputBufferIndex, outputStream, StreamDescriptionToString(outputFormat, formatString), m_outputBitstream ? "bitstreamed passthrough" : "");
440 SetHogMode(passthrough);
442 // Configure the output stream object
443 m_outputStream.Open(outputStream);
445 AudioStreamBasicDescription virtualFormat, previousPhysicalFormat;
446 m_outputStream.GetVirtualFormat(&virtualFormat);
447 m_outputStream.GetPhysicalFormat(&previousPhysicalFormat);
448 CLog::Log(LOGDEBUG, "%s: Previous Virtual Format: %s", __FUNCTION__, StreamDescriptionToString(virtualFormat, formatString));
449 CLog::Log(LOGDEBUG, "%s: Previous Physical Format: %s", __FUNCTION__, StreamDescriptionToString(previousPhysicalFormat, formatString));
451 m_outputStream.SetPhysicalFormat(&outputFormat); // Set the active format (the old one will be reverted when we close)
452 m_outputStream.GetVirtualFormat(&virtualFormat);
453 CLog::Log(LOGDEBUG, "%s: New Virtual Format: %s", __FUNCTION__, StreamDescriptionToString(virtualFormat, formatString));
454 CLog::Log(LOGDEBUG, "%s: New Physical Format: %s", __FUNCTION__, StreamDescriptionToString(outputFormat, formatString));
456 m_latentFrames = m_device.GetNumLatencyFrames();
457 m_latentFrames += m_outputStream.GetNumLatencyFrames();
459 /* TODO: Should we use the virtual format to determine our data format? */
460 format.m_frameSize = format.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
461 format.m_frames = m_device.GetBufferSize();
462 format.m_frameSamples = format.m_frames * format.m_channelLayout.Count();
464 if (m_outputBitstream)
466 m_outputBuffer = new int16_t[format.m_frameSamples];
467 /* TODO: Do we need this? */
468 m_device.SetNominalSampleRate(format.m_sampleRate);
471 unsigned int num_buffers = 4;
472 m_buffer = new AERingBuffer(num_buffers * format.m_frames * format.m_frameSize);
473 CLog::Log(LOGDEBUG, "%s: using buffer size: %u (%f ms)", __FUNCTION__, m_buffer->GetMaxSize(), (float)m_buffer->GetMaxSize() / (format.m_sampleRate * format.m_frameSize));
477 format.m_dataFormat = AE_FMT_S16NE;
479 format.m_dataFormat = AE_FMT_FLOAT;
481 // Register for data request callbacks from the driver and start
482 m_device.AddIOProc(renderCallback, this);
487 void CAESinkDARWINOSX::SetHogMode(bool on)
489 // TODO: Auto hogging sets this for us. Figure out how/when to turn it off or use it
490 // It appears that leaving this set will aslo restore the previous stream format when the
491 // Application exits. If auto hogging is set and we try to set hog mode, we will deadlock
492 // 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."
494 // Lock down the device. This MUST be done PRIOR to switching to a non-mixable format, if it is done at all
495 // If it is attempted after the format change, there is a high likelihood of a deadlock
496 // We may need to do this sooner to enable mix-disable (i.e. before setting the stream format)
499 // Auto-Hog does not always un-hog the device when changing back to a mixable mode.
500 // Handle this on our own until it is fixed.
501 CCoreAudioHardware::SetAutoHogMode(false);
502 bool autoHog = CCoreAudioHardware::GetAutoHogMode();
503 CLog::Log(LOGDEBUG, " CoreAudioRenderer::InitializeEncoded: "
504 "Auto 'hog' mode is set to '%s'.", autoHog ? "On" : "Off");
508 m_device.SetHogStatus(on);
509 m_device.SetMixingSupport(!on);
512 void CAESinkDARWINOSX::Deinitialize()
515 m_device.RemoveIOProc();
517 m_outputStream.Close();
524 m_outputBufferIndex = 0;
525 m_outputBitstream = false;
527 delete[] m_outputBuffer;
528 m_outputBuffer = NULL;
533 bool CAESinkDARWINOSX::IsCompatible(const AEAudioFormat &format, const std::string &device)
535 return ((m_format.m_sampleRate == format.m_sampleRate) &&
536 (m_format.m_dataFormat == format.m_dataFormat) &&
537 (m_format.m_channelLayout == format.m_channelLayout));
540 double CAESinkDARWINOSX::GetDelay()
544 // Calculate the duration of the data in the cache
545 double delay = (double)m_buffer->GetReadSize() / (double)m_format.m_frameSize;
546 delay += (double)m_latentFrames;
547 delay /= (double)m_format.m_sampleRate;
553 double CAESinkDARWINOSX::GetCacheTotal()
555 return (double)m_buffer->GetMaxSize() / (double)(m_format.m_frameSize * m_format.m_sampleRate);
558 CCriticalSection mutex;
559 XbmcThreads::ConditionVariable condVar;
561 unsigned int CAESinkDARWINOSX::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
563 if (m_buffer->GetWriteSize() < frames * m_format.m_frameSize)
564 { // no space to write - wait for a bit
565 CSingleLock lock(mutex);
569 condVar.wait(lock, 900 * frames / m_format.m_sampleRate);
572 unsigned int write_frames = std::min(frames, m_buffer->GetWriteSize() / m_format.m_frameSize);
574 m_buffer->Write(data, write_frames * m_format.m_frameSize);
579 void CAESinkDARWINOSX::Drain()
581 CCriticalSection mutex;
582 int bytes = m_buffer->GetReadSize();
585 CSingleLock lock(mutex);
586 condVar.wait(mutex, 900 * bytes / (m_format.m_sampleRate * m_format.m_frameSize));
587 bytes = m_buffer->GetReadSize();
591 void CAESinkDARWINOSX::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
595 for (CADeviceList::const_iterator i = s_devices.begin(); i != s_devices.end(); ++i)
596 list.push_back(i->second);
599 OSStatus CAESinkDARWINOSX::renderCallback(AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* inClientData)
601 CAESinkDARWINOSX *sink = (CAESinkDARWINOSX*)inClientData;
603 sink->m_started = true;
604 if (sink->m_outputBufferIndex < outOutputData->mNumberBuffers)
606 if (sink->m_outputBitstream)
608 /* HACK for bitstreaming AC3/DTS via PCM.
609 We reverse the float->S16LE conversion done in the stream or device */
610 static const float mul = 1.0f / (INT16_MAX + 1);
612 unsigned int wanted = std::min(outOutputData->mBuffers[sink->m_outputBufferIndex].mDataByteSize / sizeof(float), (size_t)sink->m_format.m_frameSamples) * sizeof(int16_t);
613 if (wanted <= sink->m_buffer->GetReadSize())
615 sink->m_buffer->Read((unsigned char *)sink->m_outputBuffer, wanted);
616 int16_t *src = sink->m_outputBuffer;
617 float *dest = (float*)outOutputData->mBuffers[sink->m_outputBufferIndex].mData;
618 for (unsigned int i = 0; i < wanted / 2; i++)
619 *dest++ = *src++ * mul;
624 /* buffers appear to come from CA already zero'd, so just copy what is wanted */
625 unsigned int wanted = outOutputData->mBuffers[sink->m_outputBufferIndex].mDataByteSize;
626 unsigned int bytes = std::min(sink->m_buffer->GetReadSize(), wanted);
627 sink->m_buffer->Read((unsigned char*)outOutputData->mBuffers[sink->m_outputBufferIndex].mData, bytes);
629 CLog::Log(LOGERROR, "%s: %sFLOW (%i vs %i) bytes", __FUNCTION__, bytes > wanted ? "OVER" : "UNDER", bytes, wanted);
632 // tell the sink we're good for more data