Fixes to DirectSoundOut::Drain() and WasapiOut::Drain() -- why do the

Windows APIs make this so difficult??
This commit is contained in:
casey langen 2016-12-25 01:18:34 -08:00
parent 32fced8274
commit df339ab61f
4 changed files with 38 additions and 45 deletions

View File

@ -130,7 +130,7 @@ void DirectSoundOut::SetVolume(double volume) {
if (this->secondaryBuffer) {
double db = (volume < 0.0001f)
? DSBVOLUME_MIN
: log10f(this->volume) * 6000.f;
: (float) log10f(this->volume) * 6000.f;
if (db > DSBVOLUME_MAX) {
db = DSBVOLUME_MAX;
@ -236,20 +236,25 @@ void DirectSoundOut::Drain() {
return;
}
int samples = bufferSize / sizeof(float) / channels;
int sleepMs = ((long long)(samples * 1000) / rate) + 1;
Sleep(sleepMs);
int sleepMs = 0;
/* not sure of a better way to ensure the final buffer is
flushed other than to use this heuristic: given the buffer
size in seconds, sleep for 50 milliseconds at a time while
it's still playing. */
while (this->state != StateStopped && sleepMs > 0) {
Sleep(50);
if (this->state == StatePlaying) {
sleepMs -= 50;
if (this->state != StateStopped) {
Lock lock(this->stateMutex);
if (this->secondaryBuffer) {
int pendingBytes = this->bufferSize - getAvailableBytes(
this->secondaryBuffer, this->writeOffset, this->bufferSize);
int samples = pendingBytes / sizeof(float) / channels;
sleepMs = ((long long)(samples * 1000) / rate);
}
}
if (sleepMs > 0) {
Sleep(sleepMs);
}
this->Stop();
}
void DirectSoundOut::Reset() {
@ -296,6 +301,8 @@ bool DirectSoundOut::Configure(IBuffer *buffer) {
return true;
}
this->Stop();
HRESULT result;
if (!this->outputContext) {

View File

@ -78,7 +78,6 @@ class DirectSoundOut : public IOutput {
bool Configure(IBuffer *buffer);
void Reset();
void ResetBuffers();
void Drain(IDirectSoundBuffer *buffer);
std::atomic<State> state;

View File

@ -134,37 +134,16 @@ void WasapiOut::Stop() {
}
void WasapiOut::Drain() {
UINT32 rate = waveFormat.Format.nSamplesPerSec;
REFERENCE_TIME sleepTime = 0;
UINT32 availableFrames = 0;
UINT32 frameOffset = 0;
bool bail = false;
int sleepMs = (int) (round(this->Latency()) * 1000.0f);
while (this->state != StateStopped && !bail) {
{
Lock lock(this->stateMutex);
if (this->audioClient && rate > 0) {
this->audioClient->GetCurrentPadding(&frameOffset);
availableFrames = (this->outputBufferFrames - frameOffset);
if (availableFrames < this->outputBufferFrames) {
UINT32 pending = this->outputBufferFrames - availableFrames;
REFERENCE_TIME sleepTime = (pending * 1000 * 1000 * 10) / rate;
}
if (sleepTime <= 0) {
bail = true;
}
}
else {
bail = true;
}
}
if (sleepTime > 0) {
std::this_thread::sleep_for(
std::chrono::microseconds(sleepTime));
/* not sure of a better way to ensure the final buffer is
flushed other than to use this heuristic: given the latency
size in seconds, sleep for 50 milliseconds at a time while
it's still playing. */
while (this->state != StateStopped && sleepMs > 0) {
Sleep(50);
if (this->state == StatePlaying) {
sleepMs -= 50;
}
}
}

View File

@ -163,7 +163,6 @@ void GaplessTransport::StopInternal(
LockT lock(this->stateMutex);
RESET_NEXT_PLAYER(this);
if (this->activePlayer != exclude) {
RESET_ACTIVE_PLAYER(this);
}
@ -329,8 +328,17 @@ void GaplessTransport::OnPlayerFinished(Player* player) {
}
}
/* note we could also call this->Stop() here, but it will shut down the
output and drain any pending buffers. this is a bit of extra overhead
that isn't necessary. */
if (stopped) {
this->Stop();
{
LockT lock(this->stateMutex);
RESET_NEXT_PLAYER(this);
RESET_ACTIVE_PLAYER(this);
}
this->SetPlaybackState(PlaybackStopped);
}
}