diff options
author | jmarshallnz <jcmarsha@gmail.com> | 2014-07-15 11:17:39 +1200 |
---|---|---|
committer | jmarshallnz <jcmarsha@gmail.com> | 2014-07-15 11:17:39 +1200 |
commit | 927ad96c26404d7b971b3bb7d9636ca34349a2e1 (patch) | |
tree | 47ee94f1e6a13f9e3cc232b2b47602dac4f26262 | |
parent | 02eacc8982e1db45e5cd51aadc53fd26b4b17f5f (diff) | |
parent | db138cd4e69d3a3b3914d0b5b337a4cb52fd0271 (diff) |
Merge pull request #4975 from Memphiz/osx_fix_devicechanged_recursion
[AE/osxsink] - fix possible device changed loop when using passthrough
6 files changed, 122 insertions, 39 deletions
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp index 4cfddafd97..47a9070857 100644 --- a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp +++ b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp @@ -128,34 +128,6 @@ OSStatus deviceChangedCB(AudioObjectID inObjectID, return noErr; } -void RegisterDeviceChangedCB(bool bRegister, void *ref) -{ - OSStatus ret = noErr; - AudioObjectPropertyAddress inAdr = - { - kAudioHardwarePropertyDevices, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - if (bRegister) - { - ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref); - inAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref); - } - else - { - ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref); - inAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref); - } - - if (ret != noErr) - CLog::Log(LOGERROR, "CCoreAudioAE::Deinitialize - error %s a listener callback for device changes!", bRegister?"attaching":"removing"); -} - - //////////////////////////////////////////////////////////////////////////////////////////// CAESinkDARWINOSX::CAESinkDARWINOSX() : m_latentFrames(0), @@ -184,12 +156,14 @@ CAESinkDARWINOSX::CAESinkDARWINOSX() { CLog::Log(LOGERROR, "CCoreAudioAE::constructor: kAudioHardwarePropertyRunLoop error."); } - RegisterDeviceChangedCB(true, this); + CCoreAudioDevice::RegisterDeviceChangedCB(true, deviceChangedCB, this); + CCoreAudioDevice::RegisterDefaultOutputDeviceChangedCB(true, deviceChangedCB, this); } CAESinkDARWINOSX::~CAESinkDARWINOSX() { - RegisterDeviceChangedCB(false, this); + CCoreAudioDevice::RegisterDeviceChangedCB(false, deviceChangedCB, this); + CCoreAudioDevice::RegisterDefaultOutputDeviceChangedCB(false, deviceChangedCB, this); } bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device) @@ -225,7 +199,7 @@ bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device) AudioStreamID outputStream = 0; UInt32 streamIdx = 0; UInt32 numOutputChannels = 0; - bool passthrough = false; + EPassthroughMode passthrough = PassthroughModeNone; m_planes = 1; if (devEnum.FindSuitableFormatForStream(streamIdx, format, outputFormat, passthrough, outputStream)) { @@ -248,12 +222,13 @@ bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device) /* Update our AE format */ format.m_sampleRate = outputFormat.mSampleRate; - m_outputBitstream = passthrough && outputFormat.mFormatID == kAudioFormatLinearPCM; + m_outputBitstream = passthrough == PassthroughModeBitstream; std::string formatString; CLog::Log(LOGDEBUG, "%s: Selected stream[%u] - id: 0x%04X, Physical Format: %s %s", __FUNCTION__, (unsigned int)0, (unsigned int)outputStream, StreamDescriptionToString(outputFormat, formatString), m_outputBitstream ? "bitstreamed passthrough" : ""); - SetHogMode(passthrough); + m_device.Open(deviceID); + SetHogMode(passthrough != PassthroughModeNone); // Configure the output stream object m_outputStream.Open(outputStream); @@ -269,7 +244,6 @@ bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device) CLog::Log(LOGDEBUG, "%s: New Virtual Format: %s", __FUNCTION__, StreamDescriptionToString(virtualFormat, formatString)); CLog::Log(LOGDEBUG, "%s: New Physical Format: %s", __FUNCTION__, StreamDescriptionToString(outputFormat, formatString)); - m_device.Open(deviceID); m_latentFrames = m_device.GetNumLatencyFrames(); m_latentFrames += m_outputStream.GetNumLatencyFrames(); @@ -293,7 +267,7 @@ bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device) m_buffer = new AERingBuffer(num_buffers * format.m_frames * m_frameSizePerPlane, m_planes); CLog::Log(LOGDEBUG, "%s: using buffer size: %u (%f ms)", __FUNCTION__, m_buffer->GetMaxSize(), (float)m_buffer->GetMaxSize() / (m_framesPerSecond * m_frameSizePerPlane)); - if (passthrough) + if (passthrough != PassthroughModeNone) format.m_dataFormat = AE_FMT_S16NE; else format.m_dataFormat = (m_planes > 1) ? AE_FMT_FLOATP : AE_FMT_FLOAT; diff --git a/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.cpp b/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.cpp index 78d51746e0..93e98b6625 100644 --- a/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.cpp +++ b/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.cpp @@ -468,7 +468,7 @@ float AEDeviceEnumerationOSX::ScoreFormat(const AudioStreamBasicDescription &for return score; } -bool AEDeviceEnumerationOSX::FindSuitableFormatForStream(UInt32 &streamIdx, const AEAudioFormat &format, AudioStreamBasicDescription &outputFormat, bool &passthrough, AudioStreamID &outputStream) const +bool AEDeviceEnumerationOSX::FindSuitableFormatForStream(UInt32 &streamIdx, const AEAudioFormat &format, AudioStreamBasicDescription &outputFormat, EPassthroughMode &passthrough, AudioStreamID &outputStream) const { CLog::Log(LOGDEBUG, "%s: Finding stream for format %s", __FUNCTION__, CAEUtil::DataFormatToStr(format.m_dataFormat)); @@ -477,6 +477,7 @@ bool AEDeviceEnumerationOSX::FindSuitableFormatForStream(UInt32 &streamIdx, cons UInt32 streamIdxStart = streamIdx; UInt32 streamIdxEnd = streamIdx + 1; UInt32 streamIdxCurrent = streamIdx; + passthrough = PassthroughModeNone; if (streamIdx == INT_MAX) { @@ -512,7 +513,13 @@ bool AEDeviceEnumerationOSX::FindSuitableFormatForStream(UInt32 &streamIdx, cons if (score > outputScore) { - passthrough = score > 10000; + if (score > 10000) + { + if (score > FLT_MAX/2) + passthrough = PassthroughModeNative; + else + passthrough = PassthroughModeBitstream; + } outputScore = score; outputFormat = formatDesc; outputStream = m_caStreamInfos[streamIdxCurrent].streamID; diff --git a/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.h b/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.h index 66c9ef08cc..6e627cec3a 100644 --- a/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.h +++ b/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.h @@ -23,6 +23,14 @@ #include "cores/AudioEngine/Sinks/osx/CoreAudioDevice.h" typedef std::vector< std::pair<AudioDeviceID, CAEDeviceInfo> > CADeviceList; + +typedef enum PassthroughMode +{ + PassthroughModeNone = 0, + PassthroughModeNative, + PassthroughModeBitstream +} EPassthroughMode; + //Hirarchy: // Device // - 1..n streams @@ -78,12 +86,12 @@ public: * * @param format [in] - the requested AE format which should be matched to the stream formats of CA * @param outputFormat [out] - the found CA format which matches best to the requested AE format - * @param passthrough [out] - flag indicating that the found CA format is a passthrough format + * @param passthrough [out] - flag indicating that the found CA format is a native passthrough format, bitstreamed passthroughformat or no passthroughformat * @param outputStream [out] - the coreaudio streamid which contains the coreaudio format returned in outputFormat * @return true if a matching corea audio format was found - else false */ bool FindSuitableFormatForStream(UInt32 &streamIdx, const AEAudioFormat &format, - AudioStreamBasicDescription &outputFormat, bool &passthrough, + AudioStreamBasicDescription &outputFormat, EPassthroughMode &passthrough, AudioStreamID &outputStream) const; /*! diff --git a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp index dd82147215..aab29332cd 100644 --- a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp @@ -774,3 +774,70 @@ bool CCoreAudioDevice::SetBufferSize(UInt32 size) return (ret == noErr); } + +XbmcThreads::EndTime CCoreAudioDevice::m_callbackSuppressTimer; +AudioObjectPropertyListenerProc CCoreAudioDevice::m_defaultOutputDeviceChangedCB = NULL; + + +OSStatus CCoreAudioDevice::defaultOutputDeviceChanged(AudioObjectID inObjectID, + UInt32 inNumberAddresses, + const AudioObjectPropertyAddress inAddresses[], + void* inClientData) +{ + if (m_callbackSuppressTimer.IsTimePast() && m_defaultOutputDeviceChangedCB != NULL) + return m_defaultOutputDeviceChangedCB(inObjectID, inNumberAddresses, inAddresses, inClientData); + return 0; +} + +void CCoreAudioDevice::RegisterDeviceChangedCB(bool bRegister, AudioObjectPropertyListenerProc callback, void *ref) +{ + OSStatus ret = noErr; + AudioObjectPropertyAddress inAdr = + { + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + if (bRegister) + ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, callback, ref); + else + ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, callback, ref); + + if (ret != noErr) + CLog::Log(LOGERROR, "CCoreAudioAE::Deinitialize - error %s a listener callback for device changes!", bRegister?"attaching":"removing"); +} + +void CCoreAudioDevice::RegisterDefaultOutputDeviceChangedCB(bool bRegister, AudioObjectPropertyListenerProc callback, void *ref) +{ + OSStatus ret = noErr; + static int registered = -1; + + //only allow registration once + if (bRegister == (registered == 1)) + return; + + AudioObjectPropertyAddress inAdr = + { + kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + if (bRegister) + { + ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, defaultOutputDeviceChanged, ref); + m_defaultOutputDeviceChangedCB = callback; + } + else + { + ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, defaultOutputDeviceChanged, ref); + m_defaultOutputDeviceChangedCB = NULL; + } + + if (ret != noErr) + CLog::Log(LOGERROR, "CCoreAudioAE::Deinitialize - error %s a listener callback for default output device changes!", bRegister?"attaching":"removing"); + else + registered = bRegister ? 1 : 0; +} + diff --git a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h index b4596a0eed..0c3b657e25 100644 --- a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h @@ -70,6 +70,11 @@ public: UInt32 GetNumLatencyFrames(); UInt32 GetBufferSize(); bool SetBufferSize(UInt32 size); + + static void RegisterDeviceChangedCB(bool bRegister, AudioObjectPropertyListenerProc callback, void *ref); + static void RegisterDefaultOutputDeviceChangedCB(bool bRegister, AudioObjectPropertyListenerProc callback, void *ref); + // suppresses the default output device changed callback for given time in ms + static void SuppressDefaultOutputDeviceCB(unsigned int suppressTimeMs){ m_callbackSuppressTimer.Set(suppressTimeMs); } bool AddIOProc(AudioDeviceIOProc ioProc, void* pCallbackData); bool RemoveIOProc(); @@ -86,6 +91,14 @@ protected: unsigned int m_frameSize; unsigned int m_OutputBufferIndex; unsigned int m_BufferSizeRestore; + + static XbmcThreads::EndTime m_callbackSuppressTimer; + static AudioObjectPropertyListenerProc m_defaultOutputDeviceChangedCB; + static OSStatus defaultOutputDeviceChanged(AudioObjectID inObjectID, + UInt32 inNumberAddresses, + const AudioObjectPropertyAddress inAddresses[], + void* inClientData); + }; #endif diff --git a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp index 1599e683b0..d879733303 100644 --- a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp @@ -19,6 +19,7 @@ */ #include "CoreAudioStream.h" +#include "CoreAudioDevice.h" #include "CoreAudioHelpers.h" #include "utils/log.h" @@ -211,6 +212,13 @@ bool CCoreAudioStream::SetVirtualFormat(AudioStreamBasicDescription* pDesc) std::string formatString; + // suppress callbacks for the default output device change + // for the next 2 seconds because setting format + // might trigger a change (when setting/unsetting an encoded + // passthrough format) + CCoreAudioDevice::SuppressDefaultOutputDeviceCB(2000); + + if (!m_OriginalVirtualFormat.mFormatID) { // Store the original format (as we found it) so that it can be restored later @@ -291,6 +299,12 @@ bool CCoreAudioStream::SetPhysicalFormat(AudioStreamBasicDescription* pDesc) std::string formatString; + // suppress callbacks for the default output device change + // for the next 2 seconds because setting format + // might trigger a change (when setting/unsetting an encoded + // passthrough format) + CCoreAudioDevice::SuppressDefaultOutputDeviceCB(2000); + if (!m_OriginalPhysicalFormat.mFormatID) { // Store the original format (as we found it) so that it can be restored later |