Browse Source

Scan RtAudio devices for all drivers at launch. Make logging more

verbose.
tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
768a29b9ae
1 changed files with 64 additions and 51 deletions
  1. +64
    -51
      src/rtaudio.cpp

+ 64
- 51
src/rtaudio.cpp View File

@@ -18,9 +18,24 @@
namespace rack { namespace rack {




static const std::map<RtAudio::Api, std::string> RTAUDIO_API_NAMES = {
{RtAudio::LINUX_ALSA, "ALSA"},
{RtAudio::UNIX_JACK, "JACK"},
{RtAudio::LINUX_PULSE, "PulseAudio"},
{RtAudio::LINUX_OSS, "OSS"},
{RtAudio::WINDOWS_WASAPI, "WASAPI"},
{RtAudio::WINDOWS_ASIO, "ASIO"},
{RtAudio::WINDOWS_DS, "DirectSound"},
{RtAudio::MACOSX_CORE, "CoreAudio"},
{RtAudio::RTAUDIO_DUMMY, "Dummy"},
{RtAudio::UNSPECIFIED, "Unspecified"},
};


struct RtAudioDevice : audio::Device { struct RtAudioDevice : audio::Device {
RtAudio* rtAudio;
RtAudio::Api api;
int deviceId; int deviceId;
RtAudio* rtAudio;
RtAudio::DeviceInfo deviceInfo; RtAudio::DeviceInfo deviceInfo;
RtAudio::StreamParameters inputParameters; RtAudio::StreamParameters inputParameters;
RtAudio::StreamParameters outputParameters; RtAudio::StreamParameters outputParameters;
@@ -29,12 +44,16 @@ struct RtAudioDevice : audio::Device {
float sampleRate = 0; float sampleRate = 0;


RtAudioDevice(RtAudio::Api api, int deviceId) { RtAudioDevice(RtAudio::Api api, int deviceId) {
this->api = api;
this->deviceId = deviceId;

// Create RtAudio object // Create RtAudio object
INFO("Creating RtAudio %s context", RTAUDIO_API_NAMES.at(api).c_str());
try { try {
rtAudio = new RtAudio(api); rtAudio = new RtAudio(api);
} }
catch (RtAudioError& e) { catch (RtAudioError& e) {
throw Exception("Failed to create RtAudio driver %d: %s", api, e.what());
throw Exception("Failed to create RtAudio %s context: %s", RTAUDIO_API_NAMES.at(api).c_str(), e.what());
} }


rtAudio->showWarnings(false); rtAudio->showWarnings(false);
@@ -44,10 +63,9 @@ struct RtAudioDevice : audio::Device {
deviceInfo = rtAudio->getDeviceInfo(deviceId); deviceInfo = rtAudio->getDeviceInfo(deviceId);
} }
catch (RtAudioError& e) { catch (RtAudioError& e) {
throw Exception("Failed to query RtAudio device %d: %s", deviceId, e.what());
throw Exception("Failed to query RtAudio %s device %d: %s", RTAUDIO_API_NAMES.at(api).c_str(), deviceId, e.what());
} }


this->deviceId = deviceId;
openStream(); openStream();
} }


@@ -57,7 +75,7 @@ struct RtAudioDevice : audio::Device {
delete rtAudio; delete rtAudio;
} }
catch (Exception& e) { catch (Exception& e) {
WARN("Failed to destroy RtAudioDevice: %s", e.what());
WARN("Failed to destroy RtAudio %s context: %s", RTAUDIO_API_NAMES.at(api).c_str(), e.what());
// Ignore exceptions // Ignore exceptions
} }
} }
@@ -65,7 +83,7 @@ struct RtAudioDevice : audio::Device {
void openStream() { void openStream() {
// Open new device // Open new device
if (deviceInfo.outputChannels == 0 && deviceInfo.inputChannels == 0) { if (deviceInfo.outputChannels == 0 && deviceInfo.inputChannels == 0) {
throw Exception("RtAudio device %d has 0 inputs and 0 outputs", deviceId);
throw Exception("RtAudio %s device %d has 0 inputs and 0 outputs", RTAUDIO_API_NAMES.at(api).c_str(), deviceId);
} }


inputParameters = RtAudio::StreamParameters(); inputParameters = RtAudio::StreamParameters();
@@ -98,7 +116,7 @@ struct RtAudioDevice : audio::Device {
blockSize = 256; blockSize = 256;
} }


INFO("Opening audio RtAudio device %d with %d in %d out, %g sample rate %d block size", deviceId, inputParameters.nChannels, outputParameters.nChannels, closestSampleRate, blockSize);
INFO("Opening RtAudio %s device %d: %s (%d in, %d out, %g sample rate, %d block size)", RTAUDIO_API_NAMES.at(api).c_str(), deviceId, deviceInfo.name.c_str(), inputParameters.nChannels, outputParameters.nChannels, closestSampleRate, blockSize);
try { try {
rtAudio->openStream( rtAudio->openStream(
outputParameters.nChannels > 0 ? &outputParameters : NULL, outputParameters.nChannels > 0 ? &outputParameters : NULL,
@@ -107,43 +125,43 @@ struct RtAudioDevice : audio::Device {
&rtAudioCallback, this, &options, NULL); &rtAudioCallback, this, &options, NULL);
} }
catch (RtAudioError& e) { catch (RtAudioError& e) {
throw Exception("Failed to open RtAudio stream: %s", e.what());
throw Exception("Failed to open RtAudio %s device %d: %s", RTAUDIO_API_NAMES.at(api).c_str(), deviceId, e.what());
} }


INFO("Starting RtAudio stream %d", deviceId);
INFO("Starting RtAudio %s device %d", RTAUDIO_API_NAMES.at(api).c_str(), deviceId);
try { try {
rtAudio->startStream(); rtAudio->startStream();
} }
catch (RtAudioError& e) { catch (RtAudioError& e) {
throw Exception("Failed to start RtAudio stream: %s", e.what());
throw Exception("Failed to start RtAudio %s device %d: %s", RTAUDIO_API_NAMES.at(api).c_str(), deviceId, e.what());
} }


// Update sample rate to actual value // Update sample rate to actual value
sampleRate = rtAudio->getStreamSampleRate(); sampleRate = rtAudio->getStreamSampleRate();
INFO("Opened RtAudio stream");
INFO("Opened RtAudio %s device %d", RTAUDIO_API_NAMES.at(api).c_str(), deviceId);
onStartStream(); onStartStream();
} }


void closeStream() { void closeStream() {
INFO("Stopping RtAudio %s device %d", RTAUDIO_API_NAMES.at(api).c_str(), deviceId);
if (rtAudio->isStreamRunning()) { if (rtAudio->isStreamRunning()) {
INFO("Stopping RtAudio stream %d", deviceId);
try { try {
rtAudio->stopStream(); rtAudio->stopStream();
} }
catch (RtAudioError& e) { catch (RtAudioError& e) {
throw Exception("Failed to stop RtAudio stream %s", e.what());
throw Exception("Failed to stop RtAudio %s device %d: %s", RTAUDIO_API_NAMES.at(api).c_str(), deviceId, e.what());
} }
} }
INFO("Closing RtAudio %s device %d", RTAUDIO_API_NAMES.at(api).c_str(), deviceId);
if (rtAudio->isStreamOpen()) { if (rtAudio->isStreamOpen()) {
INFO("Closing RtAudio stream %d", deviceId);
try { try {
rtAudio->closeStream(); rtAudio->closeStream();
} }
catch (RtAudioError& e) { catch (RtAudioError& e) {
throw Exception("Failed to close RtAudio stream %s", e.what());
throw Exception("Failed to close RtAudio %s device %d: %s", RTAUDIO_API_NAMES.at(api).c_str(), deviceId, e.what());
} }
} }
INFO("Closed RtAudio stream");
INFO("Closed RtAudio %s device %d", RTAUDIO_API_NAMES.at(api).c_str(), deviceId);
onStopStream(); onStopStream();
} }


@@ -192,6 +210,9 @@ struct RtAudioDevice : audio::Device {
} }


static int rtAudioCallback(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) { static int rtAudioCallback(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) {
// fprintf(stderr, ".");
// fflush(stderr);

RtAudioDevice* device = (RtAudioDevice*) userData; RtAudioDevice* device = (RtAudioDevice*) userData;
assert(device); assert(device);


@@ -206,73 +227,65 @@ struct RtAudioDevice : audio::Device {




struct RtAudioDriver : audio::Driver { struct RtAudioDriver : audio::Driver {
// Just for querying device IDs names
RtAudio* rtAudio;
RtAudio::Api api;
// deviceId -> Device // deviceId -> Device
std::map<int, RtAudioDevice*> devices; std::map<int, RtAudioDevice*> devices;
std::vector<RtAudio::DeviceInfo> deviceInfos;


RtAudioDriver(RtAudio::Api api) { RtAudioDriver(RtAudio::Api api) {
this->api = api;

INFO("Creating RtAudio %s driver", RTAUDIO_API_NAMES.at(api).c_str());
RtAudio* rtAudio;
try { try {
rtAudio = new RtAudio(api); rtAudio = new RtAudio(api);
} }
catch (RtAudioError& e) { catch (RtAudioError& e) {
throw Exception("Failed to create RtAudio driver %d: %s", api, e.what());
throw Exception("Failed to create RtAudio %s driver: %s", RTAUDIO_API_NAMES.at(api).c_str(), e.what());
} }


rtAudio->showWarnings(false); rtAudio->showWarnings(false);

// Cache all DeviceInfos for performance and stability (especially for ASIO).
int count = rtAudio->getDeviceCount();
for (int deviceId = 0; deviceId < count; deviceId++) {
RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
INFO("Found RtAudio %s device %d: %s (%d in, %d out)", RTAUDIO_API_NAMES.at(api).c_str(), deviceId, deviceInfo.name.c_str(), deviceInfo.inputChannels, deviceInfo.outputChannels);
deviceInfos.push_back(deviceInfo);
}
} }


~RtAudioDriver() { ~RtAudioDriver() {
assert(devices.empty()); assert(devices.empty());
delete rtAudio;
} }


std::string getName() override { std::string getName() override {
static const std::map<RtAudio::Api, std::string> apiNames = {
{RtAudio::LINUX_ALSA, "ALSA"},
{RtAudio::UNIX_JACK, "JACK"},
{RtAudio::LINUX_PULSE, "PulseAudio"},
{RtAudio::LINUX_OSS, "OSS"},
{RtAudio::WINDOWS_WASAPI, "WASAPI"},
{RtAudio::WINDOWS_ASIO, "ASIO"},
{RtAudio::WINDOWS_DS, "DirectSound"},
{RtAudio::MACOSX_CORE, "CoreAudio"},
{RtAudio::RTAUDIO_DUMMY, "Dummy"},
{RtAudio::UNSPECIFIED, "Unspecified"},
};
return apiNames.at(rtAudio->getCurrentApi());
return RTAUDIO_API_NAMES.at(api);
} }


std::vector<int> getDeviceIds() override { std::vector<int> getDeviceIds() override {
int count = rtAudio->getDeviceCount();
std::vector<int> deviceIds; std::vector<int> deviceIds;
for (int i = 0; i < count; i++)
for (int i = 0; i < (int) deviceInfos.size(); i++)
deviceIds.push_back(i); deviceIds.push_back(i);
return deviceIds; return deviceIds;
} }


std::string getDeviceName(int deviceId) override { std::string getDeviceName(int deviceId) override {
if (deviceId >= 0) {
RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
return deviceInfo.name;
}
return "";
if (!(0 <= deviceId && deviceId < (int) deviceInfos.size()))
return "";
return deviceInfos[deviceId].name;
} }


int getDeviceNumInputs(int deviceId) override { int getDeviceNumInputs(int deviceId) override {
if (deviceId >= 0) {
RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
return deviceInfo.inputChannels;
}
return 0;
if (!(0 <= deviceId && deviceId < (int) deviceInfos.size()))
return 0;
return deviceInfos[deviceId].inputChannels;
} }


int getDeviceNumOutputs(int deviceId) override { int getDeviceNumOutputs(int deviceId) override {
if (deviceId >= 0) {
RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
return deviceInfo.outputChannels;
}
return 0;
if (!(0 <= deviceId && deviceId < (int) deviceInfos.size()))
return 0;
return deviceInfos[deviceId].outputChannels;
} }


audio::Device* subscribe(int deviceId, audio::Port* port) override { audio::Device* subscribe(int deviceId, audio::Port* port) override {
@@ -280,7 +293,7 @@ struct RtAudioDriver : audio::Driver {
auto it = devices.find(deviceId); auto it = devices.find(deviceId);
if (it == devices.end()) { if (it == devices.end()) {
// Can throw Exception // Can throw Exception
device = new RtAudioDevice(rtAudio->getCurrentApi(), deviceId);
device = new RtAudioDevice(api, deviceId);
devices[deviceId] = device; devices[deviceId] = device;
} }
else { else {


Loading…
Cancel
Save