mirror of
https://github.com/clangen/musikcube.git
synced 2024-10-02 04:52:32 +00:00
Fixes to DirectSoundOut::Drain() and WasapiOut::Drain() -- why do the
Windows APIs make this so difficult??
This commit is contained in:
parent
32fced8274
commit
df339ab61f
@ -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) {
|
||||
|
@ -78,7 +78,6 @@ class DirectSoundOut : public IOutput {
|
||||
bool Configure(IBuffer *buffer);
|
||||
void Reset();
|
||||
void ResetBuffers();
|
||||
void Drain(IDirectSoundBuffer *buffer);
|
||||
|
||||
std::atomic<State> state;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user