mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-23 09:40:59 +00:00
- Fixed Crossfader to adjust for time spent actually adjusting the
output's volume - Reduced lock contention in WasapiOut and DirectSoundOut by caching AddRef()'d copies of important interfaces in the ::Play() methods.
This commit is contained in:
parent
6bffe8a54d
commit
4fd664b08a
@ -187,6 +187,8 @@ void DirectSoundOut::Stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DirectSoundOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
bool DirectSoundOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
||||||
|
IDirectSoundBuffer8 *outputBuffer = nullptr;
|
||||||
|
|
||||||
{
|
{
|
||||||
Lock lock(this->stateMutex);
|
Lock lock(this->stateMutex);
|
||||||
|
|
||||||
@ -199,6 +201,12 @@ bool DirectSoundOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* reduce lock contention: cache a reference to the buffer here,
|
||||||
|
just in case someone comes along and release it */
|
||||||
|
outputBuffer = this->secondaryBuffer;
|
||||||
|
outputBuffer->AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char *dst1 = nullptr, *dst2 = nullptr;
|
unsigned char *dst1 = nullptr, *dst2 = nullptr;
|
||||||
DWORD size1 = 0, size2 = 0;
|
DWORD size1 = 0, size2 = 0;
|
||||||
DWORD availableBytes = 0;
|
DWORD availableBytes = 0;
|
||||||
@ -206,7 +214,7 @@ bool DirectSoundOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
availableBytes = getAvailableBytes(
|
availableBytes = getAvailableBytes(
|
||||||
this->secondaryBuffer,
|
outputBuffer,
|
||||||
this->writeOffset,
|
this->writeOffset,
|
||||||
this->bufferSize);
|
this->bufferSize);
|
||||||
|
|
||||||
@ -222,7 +230,7 @@ bool DirectSoundOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HRESULT result =
|
HRESULT result =
|
||||||
this->secondaryBuffer->Lock(
|
outputBuffer->Lock(
|
||||||
writeOffset,
|
writeOffset,
|
||||||
bufferBytes,
|
bufferBytes,
|
||||||
(void **) &dst1, &size1,
|
(void **) &dst1, &size1,
|
||||||
@ -230,7 +238,7 @@ bool DirectSoundOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
|||||||
0);
|
0);
|
||||||
|
|
||||||
if (result == DSERR_BUFFERLOST) {
|
if (result == DSERR_BUFFERLOST) {
|
||||||
this->secondaryBuffer->Restore();
|
outputBuffer->Restore();
|
||||||
|
|
||||||
result = this->secondaryBuffer->Lock(
|
result = this->secondaryBuffer->Lock(
|
||||||
writeOffset,
|
writeOffset,
|
||||||
@ -254,8 +262,8 @@ bool DirectSoundOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
|||||||
writeOffset += bufferBytes;
|
writeOffset += bufferBytes;
|
||||||
writeOffset %= this->bufferSize;
|
writeOffset %= this->bufferSize;
|
||||||
|
|
||||||
this->secondaryBuffer->Unlock((void *)dst1, size1, (void *)dst2, size2);
|
outputBuffer->Unlock((void *)dst1, size1, (void *)dst2, size2);
|
||||||
}
|
outputBuffer->Release();
|
||||||
|
|
||||||
provider->OnBufferProcessed(buffer);
|
provider->OnBufferProcessed(buffer);
|
||||||
|
|
||||||
|
@ -149,6 +149,12 @@ void WasapiOut::Drain() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WasapiOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
bool WasapiOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
||||||
|
IAudioRenderClient *renderClient = nullptr;
|
||||||
|
IAudioClient *audioClient = nullptr;
|
||||||
|
|
||||||
|
/* reduce lock contention by snagging the references to the
|
||||||
|
COM interfaces we care about and calling AddRef(), then operating
|
||||||
|
on the local copies. */
|
||||||
{
|
{
|
||||||
Lock lock(this->stateMutex);
|
Lock lock(this->stateMutex);
|
||||||
|
|
||||||
@ -161,6 +167,13 @@ bool WasapiOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderClient = this->renderClient;
|
||||||
|
renderClient->AddRef();
|
||||||
|
|
||||||
|
audioClient = this->audioClient;
|
||||||
|
audioClient->AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
UINT32 availableFrames = 0;
|
UINT32 availableFrames = 0;
|
||||||
UINT32 frameOffset = 0;
|
UINT32 frameOffset = 0;
|
||||||
UINT32 samples = (UINT32) buffer->Samples();
|
UINT32 samples = (UINT32) buffer->Samples();
|
||||||
@ -168,7 +181,7 @@ bool WasapiOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
|||||||
int channels = buffer->Channels();
|
int channels = buffer->Channels();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
this->audioClient->GetCurrentPadding(&frameOffset);
|
audioClient->GetCurrentPadding(&frameOffset);
|
||||||
availableFrames = (this->outputBufferFrames - frameOffset);
|
availableFrames = (this->outputBufferFrames - frameOffset);
|
||||||
|
|
||||||
if (availableFrames < framesToWrite) {
|
if (availableFrames < framesToWrite) {
|
||||||
@ -178,10 +191,7 @@ bool WasapiOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
|||||||
}
|
}
|
||||||
} while (this->state == StatePlaying && availableFrames < framesToWrite);
|
} while (this->state == StatePlaying && availableFrames < framesToWrite);
|
||||||
|
|
||||||
if (state != StatePlaying) {
|
if (state == StatePlaying) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (availableFrames >= framesToWrite) {
|
if (availableFrames >= framesToWrite) {
|
||||||
BYTE *data = 0;
|
BYTE *data = 0;
|
||||||
HRESULT result = this->renderClient->GetBuffer(framesToWrite, &data);
|
HRESULT result = this->renderClient->GetBuffer(framesToWrite, &data);
|
||||||
@ -191,10 +201,13 @@ bool WasapiOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
memcpy(data, buffer->BufferPointer(), sizeof(float) * samples);
|
memcpy(data, buffer->BufferPointer(), sizeof(float) * samples);
|
||||||
this->renderClient->ReleaseBuffer(framesToWrite, 0);
|
renderClient->ReleaseBuffer(framesToWrite, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderClient->Release();
|
||||||
|
audioClient->Release();
|
||||||
|
|
||||||
provider->OnBufferProcessed(buffer);
|
provider->OnBufferProcessed(buffer);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -38,10 +38,12 @@
|
|||||||
#include <core/runtime/Message.h>
|
#include <core/runtime/Message.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
using namespace musik::core::audio;
|
using namespace musik::core::audio;
|
||||||
using namespace musik::core::sdk;
|
using namespace musik::core::sdk;
|
||||||
using namespace musik::core::runtime;
|
using namespace musik::core::runtime;
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
#define TICKS_PER_SECOND 30
|
#define TICKS_PER_SECOND 30
|
||||||
#define TICK_TIME_MILLIS (1000 / TICKS_PER_SECOND)
|
#define TICK_TIME_MILLIS (1000 / TICKS_PER_SECOND)
|
||||||
@ -51,6 +53,10 @@ using namespace musik::core::runtime;
|
|||||||
this->messageQueue.Post(Message::Create( \
|
this->messageQueue.Post(Message::Create( \
|
||||||
this, MESSAGE_TICK, 0, 0), TICK_TIME_MILLIS)
|
this, MESSAGE_TICK, 0, 0), TICK_TIME_MILLIS)
|
||||||
|
|
||||||
|
#define ENQUEUE_ADJUSTED_TICK(delay) \
|
||||||
|
this->messageQueue.Post(Message::Create( \
|
||||||
|
this, MESSAGE_TICK, 0, 0), delay > 0 ? delay : 0)
|
||||||
|
|
||||||
#define LOCK(x) \
|
#define LOCK(x) \
|
||||||
std::unique_lock<std::recursive_mutex> lock(x);
|
std::unique_lock<std::recursive_mutex> lock(x);
|
||||||
|
|
||||||
@ -214,6 +220,8 @@ void Crossfader::ProcessMessage(IMessage &message) {
|
|||||||
case MESSAGE_TICK: {
|
case MESSAGE_TICK: {
|
||||||
bool emptied = false;
|
bool emptied = false;
|
||||||
|
|
||||||
|
auto start = system_clock::now().time_since_epoch();
|
||||||
|
|
||||||
{
|
{
|
||||||
LOCK(this->contextListLock);
|
LOCK(this->contextListLock);
|
||||||
|
|
||||||
@ -278,12 +286,7 @@ void Crossfader::ProcessMessage(IMessage &message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->contextList.size()) {
|
emptied = (this->contextList.size() == 0);
|
||||||
ENQUEUE_TICK();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
emptied = true;
|
|
||||||
}
|
|
||||||
} /* end critical section */
|
} /* end critical section */
|
||||||
|
|
||||||
/* notify outside of the critical section! */
|
/* notify outside of the critical section! */
|
||||||
@ -291,6 +294,11 @@ void Crossfader::ProcessMessage(IMessage &message) {
|
|||||||
this->Emptied();
|
this->Emptied();
|
||||||
this->drainCondition.notify_all();
|
this->drainCondition.notify_all();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
auto end = system_clock::now().time_since_epoch();
|
||||||
|
int64 duration = duration_cast<milliseconds>(end - start).count();
|
||||||
|
ENQUEUE_ADJUSTED_TICK(TICK_TIME_MILLIS - duration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user