Skip to content

Commit

Permalink
Advertise all sample rates if an exclusive stream is running.
Browse files Browse the repository at this point in the history
Fixes #66.
  • Loading branch information
dechamps committed Sep 3, 2020
1 parent 5c63b57 commit e68dd19
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 10 deletions.
27 changes: 19 additions & 8 deletions src/flexasio/FlexASIO/flexasio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,9 +484,11 @@ namespace flexasio {
Log() << "Returning: " << info->name << ", " << (info->isActive ? "active" : "inactive") << ", group " << info->channelGroup << ", type " << ::dechamps_ASIOUtil::GetASIOSampleTypeString(info->type);
}

Stream FlexASIO::OpenStream(bool inputEnabled, bool outputEnabled, double sampleRate, unsigned long framesPerBuffer, PaStreamCallback callback, void* callbackUserData)
FlexASIO::OpenStreamResult FlexASIO::OpenStream(bool inputEnabled, bool outputEnabled, double sampleRate, unsigned long framesPerBuffer, PaStreamCallback callback, void* callbackUserData)
{
Log() << "CFlexASIO::OpenStream(inputEnabled = " << inputEnabled << ", outputEnabled = " << outputEnabled << ", sampleRate = " << sampleRate << ", framesPerBuffer = " << framesPerBuffer << ", callback = " << callback << ", callbackUserData = " << callbackUserData;
OpenStreamResult result;
result.exclusive = hostApi.info.type == paWDMKS;

inputEnabled = inputEnabled && inputDevice.has_value();
outputEnabled = outputEnabled && outputDevice.has_value();
Expand Down Expand Up @@ -523,6 +525,7 @@ namespace flexasio {
Log() << "Using " << (config.input.wasapiExclusiveMode ? "exclusive" : "shared") << " mode for input WASAPI stream";
if (config.input.wasapiExclusiveMode) {
input_wasapi_stream_info.flags |= paWinWasapiExclusive;
result.exclusive = true;
}
Log() << (config.input.wasapiAutoConvert ? "Enabling" : "Disabling") << " auto-conversion for input WASAPI stream";
if (config.input.wasapiAutoConvert) {
Expand Down Expand Up @@ -551,6 +554,7 @@ namespace flexasio {
Log() << "Using " << (config.output.wasapiExclusiveMode ? "exclusive" : "shared") << " mode for output WASAPI stream";
if (config.output.wasapiExclusiveMode) {
output_wasapi_stream_info.flags |= paWinWasapiExclusive;
result.exclusive = true;
}
Log() << (config.output.wasapiAutoConvert ? "Enabling" : "Disabling") << " auto-conversion for output WASAPI stream";
if (config.output.wasapiAutoConvert) {
Expand All @@ -560,26 +564,33 @@ namespace flexasio {
}
}

auto stream = flexasio::OpenStream(
result.stream = flexasio::OpenStream(
inputEnabled ? &input_parameters : NULL,
outputEnabled ? &output_parameters : NULL,
sampleRate, framesPerBuffer, paPrimeOutputBuffersUsingStreamCallback, callback, callbackUserData);
if (stream != nullptr) {
const auto streamInfo = Pa_GetStreamInfo(stream.get());
if (result.stream != nullptr) {
const auto streamInfo = Pa_GetStreamInfo(result.stream.get());
if (streamInfo == nullptr) {
Log() << "Unable to get stream info";
}
else {
Log() << "Stream info: " << DescribeStreamInfo(*streamInfo);
}
}
return stream;
return result;
}

bool FlexASIO::CanSampleRate(ASIOSampleRate sampleRate)
{
Log() << "Checking for sample rate: " << sampleRate;

if (preparedState.has_value() && preparedState->IsExclusive()) {
// Some applications will call canSampleRate() while the stream is running. If the stream is exclusive our probes will fail.
// In that case we always say "yes" - always saying "no" confuses applications. See https://github.com/dechamps/FlexASIO/issues/66
Log() << "Faking sample rate " << sampleRate << " as available because an exclusive stream is currently running";
return true;
}

// We do not know whether the host application intends to use only input channels, only output channels, or both.
// This logic ensures the driver is usable for all three use cases.
bool available = false;
Expand Down Expand Up @@ -710,7 +721,7 @@ namespace flexasio {
bufferInfos.push_back(asioBufferInfo);
}
return bufferInfos;
}()), stream(flexASIO.OpenStream(buffers.inputChannelCount > 0, buffers.outputChannelCount > 0, sampleRate, unsigned long(bufferSizeInFrames), &PreparedState::StreamCallback, this)) {
}()), openStreamResult(flexASIO.OpenStream(buffers.inputChannelCount > 0, buffers.outputChannelCount > 0, sampleRate, unsigned long(bufferSizeInFrames), &PreparedState::StreamCallback, this)) {
if (callbacks->asioMessage) ProbeHostMessages(callbacks->asioMessage);
}

Expand All @@ -734,7 +745,7 @@ namespace flexasio {

void FlexASIO::PreparedState::GetLatencies(long* inputLatency, long* outputLatency)
{
const PaStreamInfo* stream_info = Pa_GetStreamInfo(stream.get());
const PaStreamInfo* stream_info = Pa_GetStreamInfo(openStreamResult.stream.get());
if (!stream_info) throw ASIOException(ASE_HWMalfunction, "unable to get stream info");

// See https://github.com/dechamps/FlexASIO/issues/10.
Expand Down Expand Up @@ -772,7 +783,7 @@ namespace flexasio {
return result;
}()),
hostSupportsOutputReady(preparedState.flexASIO.hostSupportsOutputReady),
activeStream(preparedState.stream.get()) {}
activeStream(preparedState.openStreamResult.stream.get()) {}

void FlexASIO::Stop() {
if (!preparedState.has_value()) throw ASIOException(ASE_InvalidMode, "stop() called before createBuffers()");
Expand Down
11 changes: 9 additions & 2 deletions src/flexasio/FlexASIO/flexasio.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ namespace flexasio {
size_t size;
};

struct OpenStreamResult {
Stream stream;
bool exclusive;
};

class PortAudioHandle {
public:
PortAudioHandle();
Expand All @@ -81,6 +86,8 @@ namespace flexasio {
PreparedState(const PreparedState&) = delete;
PreparedState(PreparedState&&) = delete;

bool IsExclusive() const { return openStreamResult.exclusive; }

bool IsChannelActive(bool isInput, long channel) const;

void GetLatencies(long* inputLatency, long* outputLatency);
Expand Down Expand Up @@ -178,7 +185,7 @@ namespace flexasio {
Buffers buffers;
const std::vector<ASIOBufferInfo> bufferInfos;

const Stream stream;
const OpenStreamResult openStreamResult;

// RunningState will set runningState before ownedRunningState has finished constructing.
// This allows PreparedState to properly forward stream callbacks that might fire before RunningState construction is fully complete.
Expand All @@ -203,7 +210,7 @@ namespace flexasio {
DWORD GetInputChannelMask() const;
DWORD GetOutputChannelMask() const;

Stream OpenStream(bool inputEnabled, bool outputEnabled, double sampleRate, unsigned long framesPerBuffer, PaStreamCallback callback, void* callbackUserData);
OpenStreamResult OpenStream(bool inputEnabled, bool outputEnabled, double sampleRate, unsigned long framesPerBuffer, PaStreamCallback callback, void* callbackUserData);

const HWND windowHandle = nullptr;
const Config config;
Expand Down

0 comments on commit e68dd19

Please sign in to comment.