aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Fedchin <anightik@gmail.com>2018-03-17 01:09:24 +0300
committerAnton Fedchin <anightik@gmail.com>2018-03-17 01:09:24 +0300
commit165f86154d2b9e970cbe727902f27b2b4a839a85 (patch)
treef05c4d99d93d4e5a2e0fe6a397eb02daa8dfe326
parenta897fc5df1b92863032615a4c489ccb08706a166 (diff)
AudioEngine: XAudio - fix audio playback for live streams.
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkXAudio.cpp39
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkXAudio.h91
2 files changed, 77 insertions, 53 deletions
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.cpp
index 029e858480..2efbaf5673 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.cpp
@@ -70,6 +70,7 @@ CAESinkXAudio::CAESinkXAudio() :
m_dwFrameSize(0),
m_dwBufferLen(0),
m_sinkFrames(0),
+ m_framesInBuffers(0),
m_running(false),
m_initialized(false),
m_isSuspended(false),
@@ -168,6 +169,7 @@ void CAESinkXAudio::Deinitialize()
m_sourceVoice->Stop();
m_sourceVoice->FlushSourceBuffers();
m_sinkFrames = 0;
+ m_framesInBuffers = 0;
}
catch (...)
{
@@ -243,13 +245,17 @@ unsigned int CAESinkXAudio::AddPackets(uint8_t **data, unsigned int frames, unsi
LARGE_INTEGER timerFreq;
#endif
size_t dataLenght = frames * m_format.m_frameSize;
- uint8_t* buff = new uint8_t[dataLenght];
- memcpy(buff, data[0] + offset * m_format.m_frameSize, dataLenght);
+
+ struct buffer_ctx *ctx = new buffer_ctx;
+ ctx->data = new uint8_t[dataLenght];
+ ctx->frames = frames;
+ ctx->sink = this;
+ memcpy(ctx->data, data[0] + offset * m_format.m_frameSize, dataLenght);
XAUDIO2_BUFFER xbuffer = { 0 };
xbuffer.AudioBytes = dataLenght;
- xbuffer.pAudioData = buff;
- xbuffer.pContext = buff;
+ xbuffer.pAudioData = ctx->data;
+ xbuffer.pContext = ctx;
if (!m_running) //first time called, pre-fill buffer then start voice
{
@@ -257,19 +263,20 @@ unsigned int CAESinkXAudio::AddPackets(uint8_t **data, unsigned int frames, unsi
hr = m_sourceVoice->SubmitSourceBuffer(&xbuffer);
if (FAILED(hr))
{
- CLog::Log(LOGERROR, __FUNCTION__ " SourceVoice submit buffer failed due to %s", WASAPIErrToStr(hr));
- delete[] buff;
+ CLog::LogF(LOGERROR, "voice submit buffer failed due to %s", WASAPIErrToStr(hr));
+ delete ctx;
return 0;
}
hr = m_sourceVoice->Start(0, XAUDIO2_COMMIT_NOW);
if (FAILED(hr))
{
- CLog::Log(LOGERROR, __FUNCTION__ " SourceVoice start failed due to %s", WASAPIErrToStr(hr));
+ CLog::LogF(LOGERROR, "voice start failed due to %s", WASAPIErrToStr(hr));
m_isDirty = true; //flag new device or re-init needed
- delete[] buff;
+ delete ctx;
return INT_MAX;
}
m_sinkFrames += frames;
+ m_framesInBuffers += frames;
m_running = true; //signal that we're processing frames
return frames;
}
@@ -281,15 +288,16 @@ unsigned int CAESinkXAudio::AddPackets(uint8_t **data, unsigned int frames, unsi
#endif
/* Wait for Audio Driver to tell us it's got a buffer available */
- XAUDIO2_VOICE_STATE state;
- while (m_sourceVoice->GetState(&state), state.BuffersQueued >= XAUDIO_BUFFERS_IN_QUEUE)
+ //XAUDIO2_VOICE_STATE state;
+ //while (m_sourceVoice->GetState(&state), state.BuffersQueued >= XAUDIO_BUFFERS_IN_QUEUE)
+ while (m_format.m_frames * XAUDIO_BUFFERS_IN_QUEUE <= m_framesInBuffers.load())
{
DWORD eventAudioCallback;
eventAudioCallback = WaitForSingleObjectEx(m_voiceCallback.mBufferEnd.get(), 1100, TRUE);
if (eventAudioCallback != WAIT_OBJECT_0)
{
- CLog::Log(LOGERROR, __FUNCTION__": Endpoint Buffer timed out");
- delete[] buff;
+ CLog::LogF(LOGERROR, "voice buffer timed out");
+ delete ctx;
return INT_MAX;
}
}
@@ -305,7 +313,7 @@ unsigned int CAESinkXAudio::AddPackets(uint8_t **data, unsigned int frames, unsi
if (m_avgTimeWaiting < 3.0)
{
- CLog::Log(LOGDEBUG, __FUNCTION__": Possible AQ Loss: Avg. Time Waiting for Audio Driver callback : %dmsec", (int)m_avgTimeWaiting);
+ CLog::LogF(LOGDEBUG, "Possible AQ Loss: Avg. Time Waiting for Audio Driver callback : %dmsec", (int)m_avgTimeWaiting);
}
#endif
@@ -313,13 +321,14 @@ unsigned int CAESinkXAudio::AddPackets(uint8_t **data, unsigned int frames, unsi
if (FAILED(hr))
{
#ifdef _DEBUG
- CLog::Log(LOGERROR, __FUNCTION__": SubmitSourceBuffer failed due to %s", WASAPIErrToStr(hr));
+ CLog::LogF(LOGERROR, "submiting buffer failed due to %s", WASAPIErrToStr(hr));
#endif
- delete[] buff;
+ delete ctx;
return INT_MAX;
}
m_sinkFrames += frames;
+ m_framesInBuffers += frames;
return frames;
}
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.h b/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.h
index 6ddabaabc5..4812a52ea9 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.h
@@ -32,44 +32,6 @@
#include <xapofx.h>
#pragma comment(lib,"xaudio2.lib")
-struct VoiceCallback : public IXAudio2VoiceCallback
-{
- VoiceCallback()
- {
- mBufferEnd.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));
- if (!mBufferEnd)
- {
- throw std::exception("CreateEvent");
- }
- }
- virtual ~VoiceCallback() { }
-
- STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) override {}
- STDMETHOD_(void, OnVoiceProcessingPassEnd)() override {}
- STDMETHOD_(void, OnStreamEnd)() override {}
- STDMETHOD_(void, OnBufferStart)(void*) override {}
- STDMETHOD_(void, OnBufferEnd)(void* context) override
- {
- SetEvent(mBufferEnd.get());
- uint8_t *buff = static_cast<uint8_t*>(context);
- delete[] buff;
- }
-
- STDMETHOD_(void, OnLoopEnd)(void*) override {}
- STDMETHOD_(void, OnVoiceError)(void*, HRESULT) override {}
-
- struct handle_closer
- {
- void operator()(HANDLE h)
- {
- assert(h != INVALID_HANDLE_VALUE);
- if (h)
- CloseHandle(h);
- }
- };
- std::unique_ptr<void, handle_closer> mBufferEnd;
-};
-
class CAESinkXAudio : public IAESink
{
public:
@@ -93,6 +55,58 @@ public:
static void EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force = false);
private:
+ struct buffer_ctx
+ {
+ uint8_t *data;
+ uint32_t frames;
+ CAESinkXAudio* sink;
+
+ ~buffer_ctx()
+ {
+ delete[] data;
+ sink->m_framesInBuffers -= frames;
+ sink = nullptr;
+ }
+ };
+
+ struct VoiceCallback : public IXAudio2VoiceCallback
+ {
+ VoiceCallback()
+ {
+ mBufferEnd.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));
+ if (!mBufferEnd)
+ {
+ throw std::exception("CreateEvent");
+ }
+ }
+ virtual ~VoiceCallback() { }
+
+ STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) override {}
+ STDMETHOD_(void, OnVoiceProcessingPassEnd)() override {}
+ STDMETHOD_(void, OnStreamEnd)() override {}
+ STDMETHOD_(void, OnBufferStart)(void*) override {}
+ STDMETHOD_(void, OnBufferEnd)(void* context) override
+ {
+ SetEvent(mBufferEnd.get());
+ struct buffer_ctx *ctx = static_cast<struct buffer_ctx*>(context);
+ delete ctx;
+ }
+
+ STDMETHOD_(void, OnLoopEnd)(void*) override {}
+ STDMETHOD_(void, OnVoiceError)(void*, HRESULT) override {}
+
+ struct handle_closer
+ {
+ void operator()(HANDLE h)
+ {
+ assert(h != INVALID_HANDLE_VALUE);
+ if (h)
+ CloseHandle(h);
+ }
+ };
+ std::unique_ptr<void, handle_closer> mBufferEnd;
+ };
+
bool InitializeInternal(std::string deviceId, AEAudioFormat &format);
bool IsUSBDevice();
@@ -116,6 +130,7 @@ private:
unsigned int m_dwFrameSize;
unsigned int m_dwBufferLen;
uint64_t m_sinkFrames;
+ std::atomic<uint16_t> m_framesInBuffers;
double m_avgTimeWaiting; /* time between next buffer of data from SoftAE and driver call for data */