aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp85
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h2
2 files changed, 64 insertions, 23 deletions
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp
index 07a877cc13..cc5889d87a 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp
@@ -332,7 +332,7 @@ void RegisterDeviceChangedCB(bool bRegister, void *ref)
////////////////////////////////////////////////////////////////////////////////////////////
CAESinkDARWINOSX::CAESinkDARWINOSX()
-: m_latentFrames(0), m_outputBitstream(false), m_outputBuffer(NULL), m_buffer(NULL)
+: m_latentFrames(0), m_outputBitstream(false), m_outputBuffer(NULL), m_planar(false), m_planarBuffer(NULL), m_buffer(NULL)
{
// By default, kAudioHardwarePropertyRunLoop points at the process's main thread on SnowLeopard,
// If your process lacks such a run loop, you can set kAudioHardwarePropertyRunLoop to NULL which
@@ -352,6 +352,7 @@ CAESinkDARWINOSX::CAESinkDARWINOSX()
}
RegisterDeviceChangedCB(true, this);
m_started = false;
+ m_planar = false;
}
CAESinkDARWINOSX::~CAESinkDARWINOSX()
@@ -501,6 +502,14 @@ bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device)
index++;
}
+ m_planar = false;
+ if (streams.size() > 1 && outputFormat.mChannelsPerFrame == 1)
+ {
+ CLog::Log(LOGDEBUG, "%s Found planar audio with %u channels?", __FUNCTION__, streams.size());
+ outputFormat.mChannelsPerFrame = std::min((size_t)format.m_channelLayout.Count(), streams.size());
+ m_planar = true;
+ }
+
if (!outputFormat.mFormatID)
{
CLog::Log(LOGERROR, "%s, Unable to find suitable stream", __FUNCTION__);
@@ -553,6 +562,9 @@ bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device)
m_device.SetNominalSampleRate(format.m_sampleRate);
}
+ if (m_planar)
+ m_planarBuffer = new float[format.m_frameSamples];
+
unsigned int num_buffers = 4;
m_buffer = new AERingBuffer(num_buffers * format.m_frames * format.m_frameSize);
CLog::Log(LOGDEBUG, "%s: using buffer size: %u (%f ms)", __FUNCTION__, m_buffer->GetMaxSize(), (float)m_buffer->GetMaxSize() / (format.m_sampleRate * format.m_frameSize));
@@ -611,6 +623,10 @@ void CAESinkDARWINOSX::Deinitialize()
delete[] m_outputBuffer;
m_outputBuffer = NULL;
+ m_planar = false;
+ delete[] m_planarBuffer;
+ m_planarBuffer = NULL;
+
m_started = false;
}
@@ -718,35 +734,58 @@ OSStatus CAESinkDARWINOSX::renderCallback(AudioDeviceID inDevice, const AudioTim
CAESinkDARWINOSX *sink = (CAESinkDARWINOSX*)inClientData;
sink->m_started = true;
- for (unsigned int i = 0; i < outOutputData->mNumberBuffers; i++)
+ if (sink->m_planar)
{
- if (sink->m_outputBitstream)
+ unsigned int channels = std::min((unsigned int)outOutputData->mNumberBuffers, sink->m_format.m_channelLayout.Count());
+ unsigned int wanted = outOutputData->mBuffers[0].mDataByteSize;
+ unsigned int bytes = std::min(sink->m_buffer->GetReadSize() / channels, wanted);
+ sink->m_buffer->Read((unsigned char *)sink->m_planarBuffer, bytes * channels);
+ // transform from interleaved to planar
+ const float *src = sink->m_planarBuffer;
+ for (unsigned int i = 0; i < bytes / sizeof(float); i++)
{
- /* HACK for bitstreaming AC3/DTS via PCM.
- We reverse the float->S16LE conversion done in the stream or device */
- static const float mul = 1.0f / (INT16_MAX + 1);
-
- unsigned int wanted = std::min(outOutputData->mBuffers[i].mDataByteSize / sizeof(float), (size_t)sink->m_format.m_frameSamples) * sizeof(int16_t);
- if (wanted <= sink->m_buffer->GetReadSize())
+ for (unsigned int j = 0; j < channels; j++)
{
- sink->m_buffer->Read((unsigned char *)sink->m_outputBuffer, wanted);
- int16_t *src = sink->m_outputBuffer;
- float *dest = (float*)outOutputData->mBuffers[i].mData;
- for (unsigned int i = 0; i < wanted / 2; i++)
- *dest++ = *src++ * mul;
+ float *dst = (float *)outOutputData->mBuffers[j].mData;
+ dst[i] = *src++;
}
}
- else
- {
- /* buffers appear to come from CA already zero'd, so just copy what is wanted */
- unsigned int wanted = outOutputData->mBuffers[i].mDataByteSize;
- unsigned int bytes = std::min(sink->m_buffer->GetReadSize(), wanted);
- sink->m_buffer->Read((unsigned char*)outOutputData->mBuffers[i].mData, bytes);
- LogLevel(bytes, wanted);
- }
-
+ LogLevel(bytes, wanted);
// tell the sink we're good for more data
condVar.notifyAll();
}
+ else
+ {
+ for (unsigned int i = 0; i < outOutputData->mNumberBuffers; i++)
+ {
+ if (sink->m_outputBitstream)
+ {
+ /* HACK for bitstreaming AC3/DTS via PCM.
+ We reverse the float->S16LE conversion done in the stream or device */
+ static const float mul = 1.0f / (INT16_MAX + 1);
+
+ unsigned int wanted = std::min(outOutputData->mBuffers[i].mDataByteSize / sizeof(float), (size_t)sink->m_format.m_frameSamples) * sizeof(int16_t);
+ if (wanted <= sink->m_buffer->GetReadSize())
+ {
+ sink->m_buffer->Read((unsigned char *)sink->m_outputBuffer, wanted);
+ int16_t *src = sink->m_outputBuffer;
+ float *dest = (float*)outOutputData->mBuffers[i].mData;
+ for (unsigned int i = 0; i < wanted / 2; i++)
+ *dest++ = *src++ * mul;
+ }
+ }
+ else
+ {
+ /* buffers appear to come from CA already zero'd, so just copy what is wanted */
+ unsigned int wanted = outOutputData->mBuffers[i].mDataByteSize;
+ unsigned int bytes = std::min(sink->m_buffer->GetReadSize(), wanted);
+ sink->m_buffer->Read((unsigned char*)outOutputData->mBuffers[i].mData, bytes);
+ LogLevel(bytes, wanted);
+ }
+
+ // tell the sink we're good for more data
+ condVar.notifyAll();
+ }
+ }
return noErr;
}
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h
index 5872c17c0d..c85a32bdc8 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h
@@ -59,6 +59,8 @@ private:
bool m_outputBitstream; ///< true if we're bistreaming into a LinearPCM stream rather than AC3 stream.
int16_t *m_outputBuffer; ///< buffer for bitstreaming
+ bool m_planar;
+ float *m_planarBuffer; ///< buffer for planar conversion
AERingBuffer *m_buffer;
volatile bool m_started; // set once we get a callback from CoreAudio, which can take a little while.