aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMemphiz <memphis@machzwo.de>2014-08-03 23:01:45 +0200
committerMemphiz <memphis@machzwo.de>2014-08-03 23:01:45 +0200
commit502c7ae0c7ec1aba1a810c7cdffe7bbcf4a453d8 (patch)
tree5d3136340bfeccddc2f2ce434b253e85722a5f2e
parentb1b23a481a9905cf619ae635814cd1fc2500af39 (diff)
parent54051b5a7acc83df183434f3b8f08ce5983b4671 (diff)
Merge pull request #4768 from Memphiz/osxfixstreams
[AE/osxsink] - support multistream devices
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp49
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h1
-rw-r--r--xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.cpp48
-rw-r--r--xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.h10
-rw-r--r--xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp90
-rw-r--r--xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h10
-rw-r--r--xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp26
-rw-r--r--xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.h1
8 files changed, 206 insertions, 29 deletions
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp
index 47a9070857..37d1f1c91f 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp
@@ -53,11 +53,15 @@ static void EnumerateDevices(CADeviceList &list)
//we rather might need the concatination of all streams *sucks*
if(defaultDeviceName == devEnum.GetMasterDeviceName())
{
+ struct CADeviceInstance deviceInstance;
+ deviceInstance.audioDeviceId = deviceID;
+ deviceInstance.streamIndex = INT_MAX;//don't limit streamidx for the raw device
+ deviceInstance.sourceId = INT_MAX;
CAEDeviceInfo firstDevice = listForDevice.front().second;
firstDevice.m_deviceName = "default";
firstDevice.m_displayName = "Default";
- firstDevice.m_displayNameExtra = "";
- list.insert(list.begin(), std::make_pair(deviceID, firstDevice));
+ firstDevice.m_displayNameExtra = defaultDeviceName;
+ list.insert(list.begin(), std::make_pair(deviceInstance, firstDevice));
}
deviceIDList.pop_front();
@@ -131,6 +135,7 @@ OSStatus deviceChangedCB(AudioObjectID inObjectID,
////////////////////////////////////////////////////////////////////////////////////////////
CAESinkDARWINOSX::CAESinkDARWINOSX()
: m_latentFrames(0),
+ m_outputBufferIndex(0),
m_outputBitstream(false),
m_planes(1),
m_frameSizePerPlane(0),
@@ -169,6 +174,9 @@ CAESinkDARWINOSX::~CAESinkDARWINOSX()
bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device)
{
AudioDeviceID deviceID = 0;
+ UInt32 requestedStreamIndex = INT_MAX;
+ UInt32 requestedSourceId = INT_MAX;
+
CADeviceList devices = GetDevices();
if (StringUtils::EqualsNoCase(device, "default"))
{
@@ -180,9 +188,16 @@ bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device)
{
for (size_t i = 0; i < devices.size(); i++)
{
- if (device.find(devices[i].second.m_deviceName) != std::string::npos)
+ if (device == devices[i].second.m_deviceName)
{
- deviceID = devices[i].first;
+ const struct CADeviceInstance &deviceInstance = devices[i].first;
+ deviceID = deviceInstance.audioDeviceId;
+ requestedStreamIndex = deviceInstance.streamIndex;
+ requestedSourceId = deviceInstance.sourceId;
+ if (requestedStreamIndex != INT_MAX)
+ CLog::Log(LOGNOTICE, "%s pseudo device - requesting stream %d", __FUNCTION__, (unsigned int)requestedStreamIndex);
+ if (requestedSourceId != INT_MAX)
+ CLog::Log(LOGNOTICE, "%s device - requesting audiosource %d", __FUNCTION__, (unsigned int)requestedSourceId);
break;
}
}
@@ -197,11 +212,11 @@ bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device)
AEDeviceEnumerationOSX devEnum(deviceID);
AudioStreamBasicDescription outputFormat = { 0 };
AudioStreamID outputStream = 0;
- UInt32 streamIdx = 0;
UInt32 numOutputChannels = 0;
EPassthroughMode passthrough = PassthroughModeNone;
m_planes = 1;
- if (devEnum.FindSuitableFormatForStream(streamIdx, format, outputFormat, passthrough, outputStream))
+ // after FindSuitableFormatForStream requestedStreamIndex will have a valid index and no INT_MAX anymore ...
+ if (devEnum.FindSuitableFormatForStream(requestedStreamIndex, format, outputFormat, passthrough, outputStream))
{
numOutputChannels = outputFormat.mChannelsPerFrame;
@@ -222,10 +237,11 @@ bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device)
/* Update our AE format */
format.m_sampleRate = outputFormat.mSampleRate;
+ m_outputBufferIndex = requestedStreamIndex;
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" : "");
+ CLog::Log(LOGDEBUG, "%s: Selected stream[%u] - id: 0x%04X, Physical Format: %s %s", __FUNCTION__, (unsigned int)m_outputBufferIndex, (unsigned int)outputStream, StreamDescriptionToString(outputFormat, formatString), m_outputBitstream ? "bitstreamed passthrough" : "");
m_device.Open(deviceID);
SetHogMode(passthrough != PassthroughModeNone);
@@ -244,11 +260,15 @@ 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));
+ if (requestedSourceId != INT_MAX && !m_device.SetDataSource(requestedSourceId))
+ CLog::Log(LOGERROR, "%s: Error setting requested audio source.", __FUNCTION__);
+
m_latentFrames = m_device.GetNumLatencyFrames();
m_latentFrames += m_outputStream.GetNumLatencyFrames();
// update the channel map based on the new stream format
- devEnum.GetAEChannelMap(format.m_channelLayout, numOutputChannels);
+ if (passthrough == PassthroughModeNone)
+ devEnum.GetAEChannelMap(format.m_channelLayout, numOutputChannels);
/* TODO: Should we use the virtual format to determine our data format? */
format.m_frameSize = format.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
@@ -267,9 +287,9 @@ 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 != PassthroughModeNone)
+ if (m_outputBitstream)
format.m_dataFormat = AE_FMT_S16NE;
- else
+ else if (passthrough == PassthroughModeNone)
format.m_dataFormat = (m_planes > 1) ? AE_FMT_FLOATP : AE_FMT_FLOAT;
// Register for data request callbacks from the driver and start
@@ -315,6 +335,7 @@ void CAESinkDARWINOSX::Deinitialize()
delete m_buffer;
m_buffer = NULL;
}
+ m_outputBufferIndex = 0;
m_outputBitstream = false;
m_planes = 1;
@@ -433,6 +454,10 @@ OSStatus CAESinkDARWINOSX::renderCallback(AudioDeviceID inDevice, const AudioTim
sink->m_started = true;
if (outOutputData->mNumberBuffers)
{
+ //planar always starts at outputbuffer/streamidx 0
+ unsigned int startIdx = sink->m_buffer->NumPlanes() == 1 ? sink->m_outputBufferIndex : 0;
+ unsigned int endIdx = startIdx + sink->m_buffer->NumPlanes();
+
/* NOTE: We assume that the buffers are all the same size... */
if (sink->m_outputBitstream)
{
@@ -444,7 +469,7 @@ OSStatus CAESinkDARWINOSX::renderCallback(AudioDeviceID inDevice, const AudioTim
size_t bytes = std::min((size_t)sink->m_buffer->GetReadSize(), wanted);
for (unsigned int j = 0; j < bytes / sizeof(int16_t); j++)
{
- for (unsigned int i = 0; i < sink->m_buffer->NumPlanes(); i++)
+ for (unsigned int i = startIdx; i < endIdx; i++)
{
int16_t src;
sink->m_buffer->Read((unsigned char *)&src, sizeof(int16_t), i);
@@ -462,7 +487,7 @@ OSStatus CAESinkDARWINOSX::renderCallback(AudioDeviceID inDevice, const AudioTim
/* buffers appear to come from CA already zero'd, so just copy what is wanted */
unsigned int wanted = outOutputData->mBuffers[0].mDataByteSize;
unsigned int bytes = std::min(sink->m_buffer->GetReadSize(), wanted);
- for (unsigned int i = 0; i < sink->m_buffer->NumPlanes(); i++)
+ for (unsigned int i = startIdx; i < endIdx; i++)
{
if (i < outOutputData->mNumberBuffers && outOutputData->mBuffers[i].mData)
sink->m_buffer->Read((unsigned char *)outOutputData->mBuffers[i].mData, bytes, i);
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h
index 851e0b4aaa..9fb4b86d89 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h
@@ -52,6 +52,7 @@ private:
CCoreAudioDevice m_device;
CCoreAudioStream m_outputStream;
unsigned int m_latentFrames;
+ unsigned int m_outputBufferIndex;
bool m_outputBitstream; ///< true if we're bistreaming into a LinearPCM stream rather than AC3 stream.
unsigned int m_planes; ///< number of audio planes (1 if non-planar)
diff --git a/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.cpp b/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.cpp
index 93e98b6625..1e11f8bf75 100644
--- a/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.cpp
@@ -195,6 +195,10 @@ CADeviceList AEDeviceEnumerationOSX::GetDeviceInfoList() const
for (UInt32 streamIdx = 0; streamIdx < numDevices; streamIdx++)
{
CAEDeviceInfo deviceInfo;
+ struct CADeviceInstance devInstance;
+ devInstance.audioDeviceId = m_deviceID;
+ devInstance.streamIndex = streamIdx;
+ devInstance.sourceId = INT_MAX;//don't set audio source by default
deviceInfo.m_deviceName = getDeviceNameForStream(streamIdx);
deviceInfo.m_displayName = m_deviceName;
@@ -204,7 +208,23 @@ CADeviceList AEDeviceEnumerationOSX::GetDeviceInfoList() const
deviceInfo.m_dataFormats = getFormatListForStream(streamIdx);
deviceInfo.m_deviceType = m_caStreamInfos[streamIdx].deviceType;
- list.push_back(std::make_pair(m_deviceID, deviceInfo));
+ CoreAudioDataSourceList sourceList;
+ // if this enumerator contains multiple devices with more then 1 source we add :source suffixes to the
+ // device names and overwrite the extraname with the source name
+ if (numDevices == 1 && m_caDevice.GetDataSources(&sourceList) && sourceList.size() > 1)
+ {
+ for (unsigned sourceIdx = 0; sourceIdx < sourceList.size(); sourceIdx++)
+ {
+ std::stringstream sourceIdxStr;
+ sourceIdxStr << sourceIdx;
+ deviceInfo.m_deviceName = getDeviceNameForStream(streamIdx) + ":source" + sourceIdxStr.str();
+ deviceInfo.m_displayNameExtra = m_caDevice.GetDataSourceName(sourceList[sourceIdx]);
+ devInstance.sourceId = sourceList[sourceIdx];
+ list.push_back(std::make_pair(devInstance, deviceInfo));
+ }
+ }
+ else
+ list.push_back(std::make_pair(devInstance, deviceInfo));
}
return list;
}
@@ -272,7 +292,7 @@ CAEChannelInfo AEDeviceEnumerationOSX::getChannelInfoForStream(UInt32 streamIdx)
else
{
//get channel map to match the devices channel layout as set in audio-midi-setup
- GetAEChannelMap(channelInfo, m_caDevice.GetTotalOutputChannels());
+ GetAEChannelMap(channelInfo, m_caDevice.GetNumChannelsOfStream(streamIdx));
}
return channelInfo;
}
@@ -381,20 +401,28 @@ std::string AEDeviceEnumerationOSX::getDeviceNameForStream(UInt32 streamIdx) con
}
std::string AEDeviceEnumerationOSX::getExtraDisplayNameForStream(UInt32 streamIdx) const
-{
- std::string extraDisplayName = "";
-
+{
// for distinguishing the streams inside one device we add
- // Stream <number> to the extraDisplayName
+ // the corresponding channels to the extraDisplayName
// planar devices are ignored here as their streams are
// the channels not different subdevices
if (m_caStreamInfos.size() > 1 && !m_isPlanar)
{
- std::stringstream streamIdxStr;
- streamIdxStr << streamIdx;
- extraDisplayName = "Stream " + streamIdxStr.str();
+ // build a string with the channels for this stream
+ UInt32 startChannel = 0;
+ CCoreAudioStream::GetStartingChannelInDevice(m_caStreamInfos[streamIdx].streamID, startChannel);
+ UInt32 numChannels = m_caDevice.GetNumChannelsOfStream(streamIdx);
+ std::stringstream extraName;
+ extraName << "Channels ";
+ extraName << startChannel;
+ extraName << " - ";
+ extraName << startChannel + numChannels - 1;
+ CLog::Log(LOGNOTICE, "%s adding stream %d as pseudo device with start channel %d and %d channels total", __FUNCTION__, (unsigned int)streamIdx, (unsigned int)startChannel, (unsigned int)numChannels);
+ return extraName.str();
}
- return extraDisplayName;
+
+ //for all other devices use the datasource as extraname
+ return m_caDevice.GetCurrentDataSourceName();
}
float AEDeviceEnumerationOSX::scoreSampleRate(Float64 destinationRate, unsigned int sourceRate) const
diff --git a/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.h b/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.h
index 6e627cec3a..1f9a5c3a89 100644
--- a/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.h
+++ b/xbmc/cores/AudioEngine/Sinks/osx/AEDeviceEnumerationOSX.h
@@ -22,7 +22,13 @@
#include "cores/AudioEngine/Utils/AEDeviceInfo.h"
#include "cores/AudioEngine/Sinks/osx/CoreAudioDevice.h"
-typedef std::vector< std::pair<AudioDeviceID, CAEDeviceInfo> > CADeviceList;
+struct CADeviceInstance
+{
+ AudioDeviceID audioDeviceId;
+ unsigned int streamIndex;
+ unsigned int sourceId;
+};
+typedef std::vector< std::pair<struct CADeviceInstance, CAEDeviceInfo> > CADeviceList;
typedef enum PassthroughMode
{
@@ -30,7 +36,7 @@ typedef enum PassthroughMode
PassthroughModeNative,
PassthroughModeBitstream
} EPassthroughMode;
-
+
//Hirarchy:
// Device
// - 1..n streams
diff --git a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp
index aab29332cd..1cef8d219f 100644
--- a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp
@@ -321,7 +321,7 @@ UInt32 CCoreAudioDevice::GetTotalOutputChannels() const
return channels;
}
-UInt32 CCoreAudioDevice::GetNumChannelsOfStream(UInt32 streamIdx)
+UInt32 CCoreAudioDevice::GetNumChannelsOfStream(UInt32 streamIdx) const
{
UInt32 channels = 0;
@@ -622,7 +622,93 @@ bool CCoreAudioDevice::GetPreferredChannelLayoutForStereo(CCoreAudioChannelLayou
return (ret == noErr);
}
-bool CCoreAudioDevice::GetDataSources(CoreAudioDataSourceList* pList)
+std::string CCoreAudioDevice::GetCurrentDataSourceName() const
+{
+ UInt32 dataSourceId = 0;
+ std::string dataSourceName = "";
+ if(GetDataSource(dataSourceId))
+ {
+ dataSourceName = GetDataSourceName(dataSourceId);
+ }
+ return dataSourceName;
+}
+
+std::string CCoreAudioDevice::GetDataSourceName(UInt32 dataSourceId) const
+{
+ UInt32 propertySize = 0;
+ CFStringRef dataSourceNameCF;
+ std::string dataSourceName;
+ std::string ret = "";
+
+ if (!m_DeviceId)
+ return ret;
+
+ AudioObjectPropertyAddress propertyAddress;
+ propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
+ propertyAddress.mElement = 0;
+ propertyAddress.mSelector = kAudioDevicePropertyDataSourceNameForIDCFString;
+
+ AudioValueTranslation translation;
+ translation.mInputData = &dataSourceId;
+ translation.mInputDataSize = sizeof(UInt32);
+ translation.mOutputData = &dataSourceNameCF;
+ translation.mOutputDataSize = sizeof ( CFStringRef );
+ propertySize = sizeof(AudioValueTranslation);
+ OSStatus status = AudioObjectGetPropertyData(m_DeviceId, &propertyAddress, 0, NULL, &propertySize, &translation);
+
+ if (( status == noErr ) && dataSourceNameCF )
+ {
+ if (DarwinCFStringRefToUTF8String(dataSourceNameCF, dataSourceName))
+ {
+ ret = dataSourceName;
+ }
+ CFRelease ( dataSourceNameCF );
+ }
+
+ return ret;
+}
+
+bool CCoreAudioDevice::GetDataSource(UInt32 &dataSourceId) const
+{
+ bool ret = false;
+
+ if (!m_DeviceId)
+ return false;
+
+ AudioObjectPropertyAddress propertyAddress;
+ propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
+ propertyAddress.mElement = 0;
+ propertyAddress.mSelector = kAudioDevicePropertyDataSource;
+
+ UInt32 size = sizeof(dataSourceId);
+ OSStatus status = AudioObjectGetPropertyData(m_DeviceId, &propertyAddress, 0, NULL, &size, &dataSourceId);
+ if(status == noErr)
+ ret = true;
+
+ return ret;
+}
+
+bool CCoreAudioDevice::SetDataSource(UInt32 &dataSourceId)
+{
+ bool ret = false;
+
+ if (!m_DeviceId)
+ return false;
+
+ AudioObjectPropertyAddress propertyAddress;
+ propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
+ propertyAddress.mElement = 0;
+ propertyAddress.mSelector = kAudioDevicePropertyDataSource;
+
+ UInt32 size = sizeof(dataSourceId);
+ OSStatus status = AudioObjectSetPropertyData(m_DeviceId, &propertyAddress, 0, NULL, size, &dataSourceId);
+ if(status == noErr)
+ ret = true;
+
+ return ret;
+}
+
+bool CCoreAudioDevice::GetDataSources(CoreAudioDataSourceList* pList) const
{
if (!pList || !m_DeviceId)
return false;
diff --git a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h
index 0c3b657e25..c9e8293da9 100644
--- a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h
+++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h
@@ -29,7 +29,7 @@
#include <CoreAudio/CoreAudio.h>
-typedef std::list<UInt32> CoreAudioDataSourceList;
+typedef std::vector<UInt32> CoreAudioDataSourceList;
typedef std::list<AudioDeviceID> CoreAudioDeviceList;
class CCoreAudioChannelLayout;
@@ -54,7 +54,7 @@ public:
bool IsDigital() const;
UInt32 GetTransportType() const;
UInt32 GetTotalOutputChannels() const;
- UInt32 GetNumChannelsOfStream(UInt32 streamIdx);
+ UInt32 GetNumChannelsOfStream(UInt32 streamIdx) const;
bool GetStreams(AudioStreamIdList *pList);
bool IsRunning();
bool SetHogStatus(bool hog);
@@ -64,7 +64,11 @@ public:
bool SetCurrentVolume(Float32 vol);
bool GetPreferredChannelLayout(CCoreAudioChannelLayout &layout) const;
bool GetPreferredChannelLayoutForStereo(CCoreAudioChannelLayout &layout) const;
- bool GetDataSources(CoreAudioDataSourceList *pList);
+ bool GetDataSources(CoreAudioDataSourceList *pList) const;
+ bool GetDataSource(UInt32 &dataSourceId) const;
+ bool SetDataSource(UInt32 &dataSourceId);
+ std::string GetDataSourceName(UInt32 dataSourceId) const;
+ std::string GetCurrentDataSourceName() const;
Float64 GetNominalSampleRate();
bool SetNominalSampleRate(Float64 sampleRate);
UInt32 GetNumLatencyFrames();
diff --git a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp
index d879733303..d280e2f209 100644
--- a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp
@@ -142,6 +142,32 @@ bool CCoreAudioStream::IsDigitalOuptut(AudioStreamID id)
type == kIOAudioDeviceTransportTypeUSB);
}
+bool CCoreAudioStream::GetStartingChannelInDevice(AudioStreamID id, UInt32 &startingChannel)
+{
+ if (!id)
+ return 0;
+
+ UInt32 i_param_size = sizeof(UInt32);
+ UInt32 i_param;
+ startingChannel = 0;
+ bool ret = false;
+
+ AudioObjectPropertyAddress propertyAddress;
+ propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
+ propertyAddress.mElement = kAudioObjectPropertyElementMaster;
+ propertyAddress.mSelector = kAudioStreamPropertyStartingChannel;
+
+ // number of frames of latency in the AudioStream
+ OSStatus status = AudioObjectGetPropertyData(id, &propertyAddress, 0, NULL, &i_param_size, &i_param);
+ if (status == noErr)
+ {
+ startingChannel = i_param;
+ ret = true;
+ }
+
+ return ret;
+}
+
UInt32 CCoreAudioStream::GetTerminalType(AudioStreamID id)
{
if (!id)
diff --git a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.h b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.h
index 4f2f5b34cc..3fb01c1684 100644
--- a/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.h
+++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.h
@@ -60,6 +60,7 @@ public:
static bool GetAvailableVirtualFormats(AudioStreamID id, StreamFormatList *pList);
static bool GetAvailablePhysicalFormats(AudioStreamID id, StreamFormatList *pList);
static bool IsDigitalOuptut(AudioStreamID id);
+ static bool GetStartingChannelInDevice(AudioStreamID id, UInt32 &startingChannel);
protected:
static OSStatus HardwareStreamListener(AudioObjectID inObjectID,