Skip to content

Commit

Permalink
Revert "Unblock ASIOStart() before calling bufferSwitch()."
Browse files Browse the repository at this point in the history
This reverts commit 1262460.

We don't need this workaround anymore since
PortAudio/portaudio@2d8c7eb fixed the
root cause of #60.
  • Loading branch information
dechamps committed Jan 2, 2021
1 parent ce20994 commit 53e395e
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 109 deletions.
10 changes: 1 addition & 9 deletions src/flexasio/FlexASIO/flexasio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ namespace flexasio {
return result;
}()),
hostSupportsOutputReady(preparedState.flexASIO.hostSupportsOutputReady),
activeStream(preparedState.openStreamResult.stream.get()) {}
activeStream(StartStream(preparedState.openStreamResult.stream.get())) {}

void FlexASIO::Stop() {
if (!preparedState.has_value()) throw ASIOException(ASE_InvalidMode, "stop() called before createBuffers()");
Expand Down Expand Up @@ -861,14 +861,6 @@ namespace flexasio {
memset(output_samples[output_channel_index], 0, frameCount * outputSampleSizeInBytes);
}

// Some backends (e.g. WASAPI) issue the first stream callback from within Pa_StartStream().
// This is problematic because some host applications (e.g. foo_out_asio) wait for Start() to finish
// before returning from bufferSwitch(), resulting in a deadlock. See: https://github.com/dechamps/FlexASIO/issues/60
// To work around this problem, unblock Start() if it is still running by the time we reach this point.
// One possible downside of this approach is that we might not report Start() errors properly if they occur
// after the first stream callback fires.
if (state == InitialState()) activeStream.EndWaitForStartOutcome();

// See dechamps_ASIOUtil/BUFFERS.md for the gory details of how ASIO buffer management works.

if (state != State::PRIMING) {
Expand Down
5 changes: 2 additions & 3 deletions src/flexasio/FlexASIO/flexasio.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,7 @@ namespace flexasio {
PreparedState& preparedState;
const bool host_supports_timeinfo;
const bool hostSupportsOutputReady;
State InitialState() const { return hostSupportsOutputReady ? State::PRIMING : State::PRIMED; }
State state = InitialState();
State state = hostSupportsOutputReady ? State::PRIMING : State::PRIMED;
// The index of the "unlocked" buffer (or "half-buffer", i.e. 0 or 1) that contains data not currently being processed by the ASIO host.
long driverBufferIndex = state == State::PRIMING ? 1 : 0;
std::atomic<SamplePosition> samplePosition;
Expand All @@ -170,7 +169,7 @@ namespace flexasio {

Win32HighResolutionTimer win32HighResolutionTimer;
Registration registration{ preparedState.runningState, *this };
ActiveStream activeStream;
const ActiveStream activeStream;
};

static int StreamCallback(const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) throw();
Expand Down
83 changes: 9 additions & 74 deletions src/flexasio/FlexASIO/portaudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,8 @@
#include "log.h"
#include "../FlexASIOUtil/portaudio.h"

#include <Objbase.h>

namespace flexasio {

namespace {

class COMInitializer {
public:
COMInitializer() {
Log() << "Initializing COM";
const auto hresult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hresult)) throw std::system_error(hresult, std::system_category(), "CoInitializeEx() failed");
}
~COMInitializer() {
Log() << "Uninitializing COM";
CoUninitialize();
}
};

}

void StreamDeleter::operator()(PaStream* stream) throw() {
Log() << "Closing PortAudio stream " << stream;
const auto error = Pa_CloseStream(stream);
Expand All @@ -47,65 +28,19 @@ namespace flexasio {
return Stream(stream);
}

ActiveStream::ActiveStream(PaStream* stream) : stream(stream), startThread([this] {
std::exception_ptr exception;
try {
Log() << "Starting PortAudio stream " << this->stream;
{
COMInitializer comInitializer; // Required because WASAPI Pa_StartStream() calls into the COM library
const auto error = Pa_StartStream(this->stream);
if (error != paNoError) throw std::runtime_error(std::string("unable to start PortAudio stream: ") + Pa_GetErrorText(error));
}
Log() << "PortAudio stream started";
}
catch (...) {
exception = std::current_exception();
}
Log() << "Setting start outcome";
try {
if (exception)
promisedOutcome.set_exception(exception);
else
promisedOutcome.set_value();
}
catch (const std::future_error& future_error) {
if (future_error.code() != std::future_errc::promise_already_satisfied) throw;
Log() << "Start outcome already set";
return;
}
Log() << "Start outcome set";
}) {
Log() << "Waiting for start outcome";
promisedOutcome.get_future().get();
Log() << "Start outcome is OK";
}

ActiveStream::StartThread::~StartThread() {
if (thread.joinable()) {
Log() << "Waiting for start thread to finish";
thread.join();
Log() << "Start thread finished";
}
}

void ActiveStream::EndWaitForStartOutcome() {
Log() << "Ending wait for outcome";
try {
promisedOutcome.set_value();
}
catch (const std::future_error& future_error) {
if (future_error.code() != std::future_errc::promise_already_satisfied) throw;
Log() << "Start outcome already set";
return;
}
Log() << "Outcome wait ended";
}

ActiveStream::~ActiveStream() {
void StreamStopper::operator()(PaStream* stream) throw() {
Log() << "Stopping PortAudio stream " << stream;
const auto error = Pa_StopStream(stream);
if (error != paNoError)
Log() << "Unable to stop PortAudio stream: " << Pa_GetErrorText(error);
}

ActiveStream StartStream(PaStream* const stream) {
Log() << "Starting PortAudio stream " << stream;
const auto error = Pa_StartStream(stream);
if (error != paNoError) throw std::runtime_error(std::string("unable to start PortAudio stream: ") + Pa_GetErrorText(error));
Log() << "PortAudio stream started";
return ActiveStream(stream);
}

}
27 changes: 4 additions & 23 deletions src/flexasio/FlexASIO/portaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
#include <portaudio.h>

#include <memory>
#include <future>
#include <thread>

namespace flexasio {

Expand All @@ -14,27 +12,10 @@ namespace flexasio {
using Stream = std::unique_ptr<PaStream, StreamDeleter>;
Stream OpenStream(const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData);

class ActiveStream {
public:
ActiveStream(PaStream*);
~ActiveStream();

void EndWaitForStartOutcome();

private:
class StartThread {
public:
template <typename... Args> StartThread(Args&&... args) : thread(std::forward<Args>(args)...) {}
~StartThread();

private:
std::thread thread;
};

PaStream* const stream;

std::promise<void> promisedOutcome;
StartThread startThread;
struct StreamStopper {
void operator()(PaStream*) throw();
};
using ActiveStream = std::unique_ptr<PaStream, StreamStopper>;
ActiveStream StartStream(PaStream*);

}

0 comments on commit 53e395e

Please sign in to comment.