aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjmarshallnz <jcmarsha@gmail.com>2014-07-15 11:17:39 +1200
committerjmarshallnz <jcmarsha@gmail.com>2014-07-15 11:17:39 +1200
commit927ad96c26404d7b971b3bb7d9636ca34349a2e1 (patch)
tree47ee94f1e6a13f9e3cc232b2b47602dac4f26262
parent02eacc8982e1db45e5cd51aadc53fd26b4b17f5f (diff)
parentdb138cd4e69d3a3b3914d0b5b337a4cb52fd0271 (diff)
Merge pull request #4975 from Memphiz/osx_fix_devicechanged_recursion
[AE/osxsink] - fix possible device changed loop when using passthrough
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp44
-rw-r--r--xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.cpp11
-rw-r--r--xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.h12
-rw-r--r--xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp67
-rw-r--r--xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h13
-rw-r--r--xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp14
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