mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-14 13:21:13 +00:00
Fix synchronization issues and ensure we don't call Pa_WriteStream() if
the buffer is full, otherwise it'll block.
This commit is contained in:
parent
4afc8af219
commit
04fe549bf5
@ -204,67 +204,81 @@ IDevice* PortAudioOut::GetDefaultDevice() {
|
||||
}
|
||||
|
||||
OutputState PortAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
||||
std::unique_lock<decltype(this->mutex)> lock(this->mutex);
|
||||
bool bufferWritten = false;
|
||||
|
||||
if (this->state == StatePaused) {
|
||||
return OutputState::InvalidState;
|
||||
}
|
||||
{
|
||||
std::unique_lock<decltype(this->mutex)> lock(this->mutex);
|
||||
|
||||
if (!this->paStream) {
|
||||
auto device = static_cast<PortAudioDevice*>(this->GetDefaultDevice());
|
||||
if (device) {
|
||||
PaStreamParameters params = { 0 };
|
||||
params.device = device->Index();
|
||||
params.channelCount = buffer->Channels();
|
||||
params.sampleFormat = paFloat32;
|
||||
params.suggestedLatency = Pa_GetDeviceInfo(device->Index())->defaultHighOutputLatency;
|
||||
params.hostApiSpecificStreamInfo = nullptr;
|
||||
PaError result = Pa_OpenStream(
|
||||
&this->paStream,
|
||||
nullptr,
|
||||
¶ms,
|
||||
buffer->SampleRate(),
|
||||
buffer->Samples() / buffer->Channels(),
|
||||
0 /* stream flags */,
|
||||
nullptr /* buffer callback; nullptr = blocking */,
|
||||
nullptr /* callback context */);
|
||||
logPaError("Pa_OpenStream", result);
|
||||
if (result != paNoError) {
|
||||
return OutputState::InvalidState;
|
||||
}
|
||||
result = Pa_StartStream(this->paStream);
|
||||
logPaError("Pa_StartStream", result);
|
||||
device->Release();
|
||||
if (this->state == StatePaused) {
|
||||
return OutputState::InvalidState;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->paStream) {
|
||||
auto audio = buffer->BufferPointer();
|
||||
auto const samples = buffer->Samples();
|
||||
auto const frameCount = samples / buffer->Channels();
|
||||
|
||||
if (volume != 1.0f) {
|
||||
float gain = 0.0;
|
||||
if (volume > 0) {
|
||||
float dB = 20.0 * std::log(volume/1.0);
|
||||
gain = std::pow(10.0, dB / 20.0);
|
||||
}
|
||||
for (size_t i = 0; i < samples; i++) {
|
||||
(*audio) *= gain;
|
||||
++audio;
|
||||
if (!this->paStream) {
|
||||
auto device = static_cast<PortAudioDevice*>(this->GetDefaultDevice());
|
||||
if (device) {
|
||||
PaStreamParameters params = { 0 };
|
||||
params.device = device->Index();
|
||||
params.channelCount = buffer->Channels();
|
||||
params.sampleFormat = paFloat32;
|
||||
params.suggestedLatency = Pa_GetDeviceInfo(device->Index())->defaultHighOutputLatency;
|
||||
params.hostApiSpecificStreamInfo = nullptr;
|
||||
PaError result = Pa_OpenStream(
|
||||
&this->paStream,
|
||||
nullptr,
|
||||
¶ms,
|
||||
buffer->SampleRate(),
|
||||
buffer->Samples() / buffer->Channels(),
|
||||
0 /* stream flags */,
|
||||
nullptr /* buffer callback; nullptr = blocking */,
|
||||
nullptr /* callback context */);
|
||||
logPaError("Pa_OpenStream", result);
|
||||
if (result != paNoError) {
|
||||
return OutputState::InvalidState;
|
||||
}
|
||||
result = Pa_StartStream(this->paStream);
|
||||
logPaError("Pa_StartStream", result);
|
||||
device->Release();
|
||||
}
|
||||
}
|
||||
|
||||
PaError result = Pa_WriteStream(
|
||||
this->paStream, buffer->BufferPointer(), frameCount);
|
||||
if (this->paStream) {
|
||||
auto audio = buffer->BufferPointer();
|
||||
auto const samples = buffer->Samples();
|
||||
auto const frameCount = samples / buffer->Channels();
|
||||
auto const writeAvailable = Pa_GetStreamWriteAvailable(this->paStream);
|
||||
|
||||
if (result == paNoError) {
|
||||
provider->OnBufferProcessed(buffer);
|
||||
return OutputState::BufferWritten;
|
||||
if (writeAvailable < frameCount) {
|
||||
int retryMs = buffer->SampleRate() / samples;
|
||||
return static_cast<OutputState>(retryMs);
|
||||
}
|
||||
|
||||
if (volume != 1.0f) {
|
||||
float gain = 0.0;
|
||||
if (volume > 0) {
|
||||
float dB = 20.0 * std::log(volume/1.0);
|
||||
gain = std::pow(10.0, dB / 20.0);
|
||||
}
|
||||
for (size_t i = 0; i < samples; i++) {
|
||||
(*audio) *= gain;
|
||||
++audio;
|
||||
}
|
||||
}
|
||||
|
||||
PaError result = Pa_WriteStream(
|
||||
this->paStream, buffer->BufferPointer(), frameCount);
|
||||
|
||||
if (result == paNoError) {
|
||||
bufferWritten = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OutputState::BufferFull;
|
||||
if (bufferWritten) {
|
||||
provider->OnBufferProcessed(buffer);
|
||||
return OutputState::BufferWritten;
|
||||
}
|
||||
|
||||
return OutputState::InvalidState;
|
||||
}
|
||||
|
||||
double PortAudioOut::Latency() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user