| @@ -207,7 +207,7 @@ $(rtmidi): | rtmidi-4.0.0 | |||||
| $(MAKE) -C rtmidi-4.0.0 | $(MAKE) -C rtmidi-4.0.0 | ||||
| $(MAKE) -C rtmidi-4.0.0 install | $(MAKE) -C rtmidi-4.0.0 install | ||||
| RTAUDIO_FLAGS += -DRTAUDIO_BUILD_STATIC_LIBS=ON | |||||
| RTAUDIO_FLAGS += -DRTAUDIO_BUILD_STATIC_LIBS=ON -DRTAUDIO_BUILD_TESTING=OFF | |||||
| ifdef ARCH_LIN | ifdef ARCH_LIN | ||||
| RTAUDIO_FLAGS += -DRTAUDIO_API_ALSA=ON -DRTAUDIO_API_JACK=ON -DRTAUDIO_API_PULSE=OFF -DRTAUDIO_API_OSS=OFF | RTAUDIO_FLAGS += -DRTAUDIO_API_ALSA=ON -DRTAUDIO_API_JACK=ON -DRTAUDIO_API_PULSE=OFF -DRTAUDIO_API_OSS=OFF | ||||
| endif | endif | ||||
| @@ -1 +1 @@ | |||||
| Subproject commit 07b1c6228fec77a207afd5d5cccc36681e90d319 | |||||
| Subproject commit e9915064859381a7a616b088dadbaee81bc0e0df | |||||
| @@ -22,30 +22,45 @@ namespace audio { | |||||
| struct Device; | struct Device; | ||||
| struct Port; | struct Port; | ||||
| /** An audio driver API containing any number of audio devices. | |||||
| */ | |||||
| struct Driver { | struct Driver { | ||||
| virtual ~Driver() {} | virtual ~Driver() {} | ||||
| /** Returns the name of the driver. E.g. "ALSA". */ | |||||
| virtual std::string getName() { | virtual std::string getName() { | ||||
| return ""; | return ""; | ||||
| } | } | ||||
| /** Returns a list of all device IDs that can be subscribed to. */ | |||||
| virtual std::vector<int> getDeviceIds() { | virtual std::vector<int> getDeviceIds() { | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| /** Gets the name of a device without subscribing to it. */ | |||||
| /** Returns the name of a device without obtaining it. */ | |||||
| virtual std::string getDeviceName(int deviceId) { | virtual std::string getDeviceName(int deviceId) { | ||||
| return ""; | return ""; | ||||
| } | } | ||||
| /** Returns the number of inputs of a device without obtaining it. */ | |||||
| virtual int getDeviceNumInputs(int deviceId) { | virtual int getDeviceNumInputs(int deviceId) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /** Returns the number of output of a device without obtaining it. */ | |||||
| virtual int getDeviceNumOutputs(int deviceId) { | virtual int getDeviceNumOutputs(int deviceId) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /** Returns a detailed description of the device without obtaining it. | |||||
| `offset` specifies the first channel (zero-indexed). | |||||
| E.g. "MySoundcard (1-2 in, 1-2 out)" | |||||
| */ | |||||
| std::string getDeviceDetail(int deviceId, int offset, int maxChannels); | std::string getDeviceDetail(int deviceId, int offset, int maxChannels); | ||||
| /** Adds the given port as a reference holder of a device and returns the it. | |||||
| Creates the Device if no ports are subscribed before calling. | |||||
| */ | |||||
| virtual Device* subscribe(int deviceId, Port* port) { | virtual Device* subscribe(int deviceId, Port* port) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /** Removes the give port as a reference holder of a device. | |||||
| Deletes the Device if no ports are subscribed after calling. | |||||
| */ | |||||
| virtual void unsubscribe(int deviceId, Port* port) {} | virtual void unsubscribe(int deviceId, Port* port) {} | ||||
| }; | }; | ||||
| @@ -53,6 +68,12 @@ struct Driver { | |||||
| // Device | // Device | ||||
| //////////////////// | //////////////////// | ||||
| /** A single audio device of a driver API. | |||||
| Modules should | |||||
| Methods throw `rack::Exception` if the driver API has an exception. | |||||
| */ | |||||
| struct Device { | struct Device { | ||||
| std::set<Port*> subscribed; | std::set<Port*> subscribed; | ||||
| virtual ~Device() {} | virtual ~Device() {} | ||||
| @@ -69,22 +90,36 @@ struct Device { | |||||
| virtual int getNumOutputs() { | virtual int getNumOutputs() { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /** Returns a detailed description of the device. | |||||
| `offset` specifies the first channel (zero-indexed). | |||||
| E.g. "MySoundcard (1-2 in, 1-2 out)" | |||||
| */ | |||||
| std::string getDetail(int offset, int maxChannels); | std::string getDetail(int offset, int maxChannels); | ||||
| /** Returns a list of all valid (user-selectable) sample rates. | |||||
| The device may accept sample rates not in this list, but it *must* accept sample rates in the list. | |||||
| */ | |||||
| virtual std::vector<int> getSampleRates() { | virtual std::vector<int> getSampleRates() { | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| /** Returns the current sample rate. */ | |||||
| virtual int getSampleRate() { | virtual int getSampleRate() { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /** Sets the sample rate of the device, re-opening it if needed. */ | |||||
| virtual void setSampleRate(int sampleRate) {} | virtual void setSampleRate(int sampleRate) {} | ||||
| /** Returns a list of all valid (user-selectable) block sizes. | |||||
| The device may accept block sizes not in this list, but it *must* accept block sizes in the list. | |||||
| */ | |||||
| virtual std::vector<int> getBlockSizes() { | virtual std::vector<int> getBlockSizes() { | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| /** Returns the current block size. */ | |||||
| virtual int getBlockSize() { | virtual int getBlockSize() { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /** Sets the block size of the device, re-opening it if needed. */ | |||||
| virtual void setBlockSize(int blockSize) {} | virtual void setBlockSize(int blockSize) {} | ||||
| // Called by this Device class, forwards to subscribed Ports. | // Called by this Device class, forwards to subscribed Ports. | ||||
| @@ -97,6 +132,11 @@ struct Device { | |||||
| // Port | // Port | ||||
| //////////////////// | //////////////////// | ||||
| /** A handle to a Device, typically owned by modules to have shared access to a single Device. | |||||
| All Port methods safely wrap Drivers methods. | |||||
| That is, if the active Device thrown a `rack::Exception`, it is caught and logged inside all Port methods, so you can consider them nothrow. | |||||
| */ | |||||
| struct Port { | struct Port { | ||||
| /** The first channel index of the device to process. */ | /** The first channel index of the device to process. */ | ||||
| int offset = 0; | int offset = 0; | ||||
| @@ -115,51 +155,27 @@ struct Port { | |||||
| virtual ~Port(); | virtual ~Port(); | ||||
| void reset(); | void reset(); | ||||
| Driver* getDriver() { | |||||
| return driver; | |||||
| } | |||||
| int getDriverId() { | |||||
| return driverId; | |||||
| } | |||||
| Driver* getDriver(); | |||||
| int getDriverId(); | |||||
| void setDriverId(int driverId); | void setDriverId(int driverId); | ||||
| std::string getDriverName(); | |||||
| Device* getDevice() { | |||||
| return device; | |||||
| } | |||||
| int getDeviceId() { | |||||
| return deviceId; | |||||
| } | |||||
| Device* getDevice(); | |||||
| std::vector<int> getDeviceIds(); | |||||
| int getDeviceId(); | |||||
| void setDeviceId(int deviceId); | void setDeviceId(int deviceId); | ||||
| std::vector<int> getSampleRates() { | |||||
| if (!device) | |||||
| return {}; | |||||
| return device->getSampleRates(); | |||||
| } | |||||
| int getSampleRate() { | |||||
| if (!device) | |||||
| return 0; | |||||
| return device->getSampleRate(); | |||||
| } | |||||
| void setSampleRate(int sampleRate) { | |||||
| if (device) | |||||
| device->setSampleRate(sampleRate); | |||||
| } | |||||
| std::vector<int> getBlockSizes() { | |||||
| if (!device) | |||||
| return {}; | |||||
| return device->getBlockSizes(); | |||||
| } | |||||
| int getBlockSize() { | |||||
| if (!device) | |||||
| return 0; | |||||
| return device->getBlockSize(); | |||||
| } | |||||
| void setBlockSize(int blockSize) { | |||||
| if (device) | |||||
| device->setBlockSize(blockSize); | |||||
| } | |||||
| int getDeviceNumInputs(int deviceId); | |||||
| int getDeviceNumOutputs(int deviceId); | |||||
| std::string getDeviceName(int deviceId); | |||||
| std::string getDeviceDetail(int deviceId, int offset); | |||||
| std::vector<int> getSampleRates(); | |||||
| int getSampleRate(); | |||||
| void setSampleRate(int sampleRate); | |||||
| std::vector<int> getBlockSizes(); | |||||
| int getBlockSize(); | |||||
| void setBlockSize(int blockSize); | |||||
| int getNumInputs(); | int getNumInputs(); | ||||
| int getNumOutputs(); | int getNumOutputs(); | ||||
| @@ -88,20 +88,31 @@ struct Output; | |||||
| struct Driver { | struct Driver { | ||||
| virtual ~Driver() {} | virtual ~Driver() {} | ||||
| /** Returns the name of the driver. E.g. "ALSA". */ | |||||
| virtual std::string getName() { | virtual std::string getName() { | ||||
| return ""; | return ""; | ||||
| } | } | ||||
| /** Returns a list of all input device IDs that can be subscribed to. */ | |||||
| virtual std::vector<int> getInputDeviceIds() { | virtual std::vector<int> getInputDeviceIds() { | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| /** Returns the name of an input device without obtaining it. */ | |||||
| virtual std::string getInputDeviceName(int deviceId) { | virtual std::string getInputDeviceName(int deviceId) { | ||||
| return ""; | return ""; | ||||
| } | } | ||||
| /** Adds the given port as a reference holder of a device and returns the it. | |||||
| Creates the Device if no ports are subscribed before calling. | |||||
| */ | |||||
| virtual InputDevice* subscribeInput(int deviceId, Input* input) { | virtual InputDevice* subscribeInput(int deviceId, Input* input) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /** Removes the give port as a reference holder of a device. | |||||
| Deletes the Device if no ports are subscribed after calling. | |||||
| */ | |||||
| virtual void unsubscribeInput(int deviceId, Input* input) {} | virtual void unsubscribeInput(int deviceId, Input* input) {} | ||||
| // The following behave identically as the above methods except for outputs. | |||||
| virtual std::vector<int> getOutputDeviceIds() { | virtual std::vector<int> getOutputDeviceIds() { | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| @@ -127,15 +138,21 @@ struct Device { | |||||
| struct InputDevice : Device { | struct InputDevice : Device { | ||||
| std::set<Input*> subscribed; | std::set<Input*> subscribed; | ||||
| /** Not public. Use Driver::subscribeInput(). */ | |||||
| void subscribe(Input* input); | void subscribe(Input* input); | ||||
| /** Not public. Use Driver::unsubscribeInput(). */ | |||||
| void unsubscribe(Input* input); | void unsubscribe(Input* input); | ||||
| /** Called when a MIDI message is received from the device. */ | |||||
| void onMessage(const Message &message); | void onMessage(const Message &message); | ||||
| }; | }; | ||||
| struct OutputDevice : Device { | struct OutputDevice : Device { | ||||
| std::set<Output*> subscribed; | std::set<Output*> subscribed; | ||||
| void subscribe(Output* input); | |||||
| void unsubscribe(Output* input); | |||||
| /** Not public. Use Driver::subscribeOutput(). */ | |||||
| void subscribe(Output* output); | |||||
| /** Not public. Use Driver::unsubscribeOutput(). */ | |||||
| void unsubscribe(Output* output); | |||||
| /** Sends a MIDI message to the device. */ | |||||
| virtual void sendMessage(const Message &message) {} | virtual void sendMessage(const Message &message) {} | ||||
| }; | }; | ||||
| @@ -40,7 +40,8 @@ struct AudioDriverChoice : LedDisplayChoice { | |||||
| text = ""; | text = ""; | ||||
| if (box.size.x >= 200.0) | if (box.size.x >= 200.0) | ||||
| text += "Driver: "; | text += "Driver: "; | ||||
| std::string driverName = (port && port->driver) ? port->getDriver()->getName() : ""; | |||||
| audio::Driver* driver = port ? port->getDriver() : NULL; | |||||
| std::string driverName = driver ? driver->getName() : ""; | |||||
| if (driverName != "") { | if (driverName != "") { | ||||
| text += driverName; | text += driverName; | ||||
| color.a = 1.0; | color.a = 1.0; | ||||
| @@ -73,7 +74,7 @@ struct AudioDeviceValueItem : ui::MenuItem { | |||||
| }; | }; | ||||
| static void appendAudioDeviceMenu(ui::Menu* menu, audio::Port* port) { | static void appendAudioDeviceMenu(ui::Menu* menu, audio::Port* port) { | ||||
| if (!port || !port->driver) | |||||
| if (!port) | |||||
| return; | return; | ||||
| { | { | ||||
| @@ -85,8 +86,8 @@ static void appendAudioDeviceMenu(ui::Menu* menu, audio::Port* port) { | |||||
| menu->addChild(item); | menu->addChild(item); | ||||
| } | } | ||||
| for (int deviceId : port->driver->getDeviceIds()) { | |||||
| int channels = std::max(port->driver->getDeviceNumInputs(deviceId), port->driver->getDeviceNumOutputs(deviceId)); | |||||
| for (int deviceId : port->getDeviceIds()) { | |||||
| int channels = std::max(port->getDeviceNumInputs(deviceId), port->getDeviceNumOutputs(deviceId)); | |||||
| // Prevents devices with a ridiculous number of channels from being displayed | // Prevents devices with a ridiculous number of channels from being displayed | ||||
| const int maxTotalChannels = port->maxChannels * 16; | const int maxTotalChannels = port->maxChannels * 16; | ||||
| channels = std::min(maxTotalChannels, channels); | channels = std::min(maxTotalChannels, channels); | ||||
| @@ -96,7 +97,7 @@ static void appendAudioDeviceMenu(ui::Menu* menu, audio::Port* port) { | |||||
| item->port = port; | item->port = port; | ||||
| item->deviceId = deviceId; | item->deviceId = deviceId; | ||||
| item->offset = offset; | item->offset = offset; | ||||
| item->text = port->driver->getDeviceDetail(deviceId, offset, port->maxChannels); | |||||
| item->text = port->getDeviceDetail(deviceId, offset); | |||||
| item->rightText = CHECKMARK(item->deviceId == port->getDeviceId() && item->offset == port->offset); | item->rightText = CHECKMARK(item->deviceId == port->getDeviceId() && item->offset == port->offset); | ||||
| menu->addChild(item); | menu->addChild(item); | ||||
| } | } | ||||
| @@ -96,11 +96,27 @@ Port::~Port() { | |||||
| } | } | ||||
| void Port::reset() { | void Port::reset() { | ||||
| setDriverId(-1); | |||||
| // Get default driver | |||||
| int firstDriverId = -1; | |||||
| std::vector<int> driverIds = getDriverIds(); | |||||
| if (!driverIds.empty()) | |||||
| firstDriverId = driverIds[0]; | |||||
| setDriverId(firstDriverId); | |||||
| offset = 0; | offset = 0; | ||||
| } | } | ||||
| Driver* Port::getDriver() { | |||||
| return driver; | |||||
| } | |||||
| int Port::getDriverId() { | |||||
| return driverId; | |||||
| } | |||||
| void Port::setDriverId(int driverId) { | void Port::setDriverId(int driverId) { | ||||
| if (driverId == this->driverId) | |||||
| return; | |||||
| // Unset device and driver | // Unset device and driver | ||||
| setDeviceId(-1); | setDeviceId(-1); | ||||
| driver = NULL; | driver = NULL; | ||||
| @@ -118,31 +134,206 @@ void Port::setDriverId(int driverId) { | |||||
| } | } | ||||
| } | } | ||||
| std::string Port::getDriverName() { | |||||
| if (!driver) | |||||
| return ""; | |||||
| try { | |||||
| return driver->getName(); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get driver name: %s", e.what()); | |||||
| return ""; | |||||
| } | |||||
| } | |||||
| Device* Port::getDevice() { | |||||
| return device; | |||||
| } | |||||
| std::vector<int> Port::getDeviceIds() { | |||||
| if (!driver) | |||||
| return {}; | |||||
| try { | |||||
| return driver->getDeviceIds(); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get device IDs: %s", e.what()); | |||||
| return {}; | |||||
| } | |||||
| } | |||||
| int Port::getDeviceId() { | |||||
| return deviceId; | |||||
| } | |||||
| void Port::setDeviceId(int deviceId) { | void Port::setDeviceId(int deviceId) { | ||||
| if (deviceId == this->deviceId) | |||||
| return; | |||||
| // Destroy device | // Destroy device | ||||
| if (driver && this->deviceId >= 0) { | if (driver && this->deviceId >= 0) { | ||||
| driver->unsubscribe(this->deviceId, this); | |||||
| try { | |||||
| driver->unsubscribe(this->deviceId, this); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not unsubscribe from device: %s", e.what()); | |||||
| } | |||||
| } | } | ||||
| device = NULL; | device = NULL; | ||||
| this->deviceId = -1; | this->deviceId = -1; | ||||
| // Create device | // Create device | ||||
| if (driver && deviceId >= 0) { | if (driver && deviceId >= 0) { | ||||
| device = driver->subscribe(deviceId, this); | |||||
| this->deviceId = deviceId; | |||||
| try { | |||||
| device = driver->subscribe(deviceId, this); | |||||
| this->deviceId = deviceId; | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not subscribe to device: %s", e.what()); | |||||
| } | |||||
| } | |||||
| } | |||||
| int Port::getDeviceNumInputs(int deviceId) { | |||||
| if (!driver) | |||||
| return 0; | |||||
| try { | |||||
| return driver->getDeviceNumInputs(deviceId); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get device number of inputs: %s", e.what()); | |||||
| return 0; | |||||
| } | |||||
| } | |||||
| int Port::getDeviceNumOutputs(int deviceId) { | |||||
| if (!driver) | |||||
| return 0; | |||||
| try { | |||||
| return driver->getDeviceNumOutputs(deviceId); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get device number of outputs: %s", e.what()); | |||||
| return 0; | |||||
| } | |||||
| } | |||||
| std::string Port::getDeviceName(int deviceId) { | |||||
| if (!driver) | |||||
| return ""; | |||||
| try { | |||||
| return driver->getDeviceName(deviceId); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get device name: %s", e.what()); | |||||
| return 0; | |||||
| } | |||||
| } | |||||
| std::string Port::getDeviceDetail(int deviceId, int offset) { | |||||
| if (!driver) | |||||
| return ""; | |||||
| try { | |||||
| // Use maxChannels from Port. | |||||
| return driver->getDeviceDetail(deviceId, offset, maxChannels); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get device detail: %s", e.what()); | |||||
| return 0; | |||||
| } | |||||
| } | |||||
| std::vector<int> Port::getSampleRates() { | |||||
| if (!device) | |||||
| return {}; | |||||
| try { | |||||
| return device->getSampleRates(); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get device sample rates: %s", e.what()); | |||||
| return {}; | |||||
| } | |||||
| } | |||||
| int Port::getSampleRate() { | |||||
| if (!device) | |||||
| return 0; | |||||
| try { | |||||
| return device->getSampleRate(); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get device sample rate: %s", e.what()); | |||||
| return 0; | |||||
| } | |||||
| } | |||||
| void Port::setSampleRate(int sampleRate) { | |||||
| if (!device) | |||||
| return; | |||||
| try { | |||||
| device->setSampleRate(sampleRate); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not set device sample rate: %s", e.what()); | |||||
| } | |||||
| } | |||||
| std::vector<int> Port::getBlockSizes() { | |||||
| if (!device) | |||||
| return {}; | |||||
| try { | |||||
| return device->getBlockSizes(); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get device block sizes: %s", e.what()); | |||||
| return {}; | |||||
| } | |||||
| } | |||||
| int Port::getBlockSize() { | |||||
| if (!device) | |||||
| return 0; | |||||
| try { | |||||
| return device->getBlockSize(); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get device block size: %s", e.what()); | |||||
| return 0; | |||||
| } | |||||
| } | |||||
| void Port::setBlockSize(int blockSize) { | |||||
| if (!device) | |||||
| return; | |||||
| try { | |||||
| device->setBlockSize(blockSize); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not set device block size: %s", e.what()); | |||||
| } | } | ||||
| } | } | ||||
| int Port::getNumInputs() { | int Port::getNumInputs() { | ||||
| if (!device) | if (!device) | ||||
| return 0; | return 0; | ||||
| return std::min(device->getNumInputs() - offset, maxChannels); | |||||
| try { | |||||
| return std::min(device->getNumInputs() - offset, maxChannels); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get device number of inputs: %s", e.what()); | |||||
| return 0; | |||||
| } | |||||
| } | } | ||||
| int Port::getNumOutputs() { | int Port::getNumOutputs() { | ||||
| if (!device) | if (!device) | ||||
| return 0; | return 0; | ||||
| return std::min(device->getNumOutputs() - offset, maxChannels); | |||||
| try { | |||||
| return std::min(device->getNumOutputs() - offset, maxChannels); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("Audio port could not get device number of outputs: %s", e.what()); | |||||
| return 0; | |||||
| } | |||||
| } | } | ||||
| json_t* Port::toJson() { | json_t* Port::toJson() { | ||||
| @@ -172,8 +363,11 @@ void Port::fromJson(json_t* rootJ) { | |||||
| if (deviceNameJ) { | if (deviceNameJ) { | ||||
| std::string deviceName = json_string_value(deviceNameJ); | std::string deviceName = json_string_value(deviceNameJ); | ||||
| // Search for device ID with equal name | // Search for device ID with equal name | ||||
| for (int deviceId : driver->getDeviceIds()) { | |||||
| if (driver->getDeviceName(deviceId) == deviceName) { | |||||
| for (int deviceId : getDeviceIds()) { | |||||
| std::string deviceNameCurr = getDeviceName(deviceId); | |||||
| if (deviceNameCurr == "") | |||||
| continue; | |||||
| if (deviceNameCurr == deviceName) { | |||||
| setDeviceId(deviceId); | setDeviceId(deviceId); | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -194,7 +388,6 @@ void Port::fromJson(json_t* rootJ) { | |||||
| offset = json_integer_value(offsetJ); | offset = json_integer_value(offsetJ); | ||||
| } | } | ||||
| //////////////////// | //////////////////// | ||||
| // audio | // audio | ||||
| //////////////////// | //////////////////// | ||||
| @@ -223,6 +416,7 @@ std::vector<int> getDriverIds() { | |||||
| } | } | ||||
| Driver* getDriver(int driverId) { | Driver* getDriver(int driverId) { | ||||
| // Search for driver by ID | |||||
| for (auto& pair : drivers) { | for (auto& pair : drivers) { | ||||
| if (pair.first == driverId) | if (pair.first == driverId) | ||||
| return pair.second; | return pair.second; | ||||
| @@ -39,7 +39,6 @@ struct RtAudioDevice : audio::Device { | |||||
| deviceInfo = rtAudio->getDeviceInfo(deviceId); | deviceInfo = rtAudio->getDeviceInfo(deviceId); | ||||
| } | } | ||||
| catch (RtAudioError& e) { | catch (RtAudioError& e) { | ||||
| WARN("Failed to query RtAudio device: %s", e.what()); | |||||
| throw Exception(string::f("Failed to query RtAudio device: %s", e.what())); | throw Exception(string::f("Failed to query RtAudio device: %s", e.what())); | ||||
| } | } | ||||
| @@ -55,8 +54,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) { | ||||
| WARN("RtAudio device %d has 0 inputs and 0 outputs", deviceId); | |||||
| return; | |||||
| throw Exception(string::f("RtAudio device %d has 0 inputs and 0 outputs", deviceId)); | |||||
| } | } | ||||
| inputParameters = RtAudio::StreamParameters(); | inputParameters = RtAudio::StreamParameters(); | ||||
| @@ -98,8 +96,7 @@ struct RtAudioDevice : audio::Device { | |||||
| &rtAudioCallback, this, &options, NULL); | &rtAudioCallback, this, &options, NULL); | ||||
| } | } | ||||
| catch (RtAudioError& e) { | catch (RtAudioError& e) { | ||||
| WARN("Failed to open RtAudio stream: %s", e.what()); | |||||
| return; | |||||
| throw Exception(string::f("Failed to open RtAudio stream: %s", e.what())); | |||||
| } | } | ||||
| INFO("Starting RtAudio stream %d", deviceId); | INFO("Starting RtAudio stream %d", deviceId); | ||||
| @@ -107,8 +104,7 @@ struct RtAudioDevice : audio::Device { | |||||
| rtAudio->startStream(); | rtAudio->startStream(); | ||||
| } | } | ||||
| catch (RtAudioError& e) { | catch (RtAudioError& e) { | ||||
| WARN("Failed to start RtAudio stream: %s", e.what()); | |||||
| return; | |||||
| throw Exception(string::f("Failed to start RtAudio stream: %s", e.what())); | |||||
| } | } | ||||
| // Update sample rate to actual value | // Update sample rate to actual value | ||||
| @@ -124,7 +120,7 @@ struct RtAudioDevice : audio::Device { | |||||
| rtAudio->stopStream(); | rtAudio->stopStream(); | ||||
| } | } | ||||
| catch (RtAudioError& e) { | catch (RtAudioError& e) { | ||||
| WARN("Failed to stop RtAudio stream %s", e.what()); | |||||
| throw Exception(string::f("Failed to stop RtAudio stream %s", e.what())); | |||||
| } | } | ||||
| } | } | ||||
| if (rtAudio->isStreamOpen()) { | if (rtAudio->isStreamOpen()) { | ||||
| @@ -133,7 +129,7 @@ struct RtAudioDevice : audio::Device { | |||||
| rtAudio->closeStream(); | rtAudio->closeStream(); | ||||
| } | } | ||||
| catch (RtAudioError& e) { | catch (RtAudioError& e) { | ||||
| WARN("Failed to close RtAudio stream %s", e.what()); | |||||
| throw Exception(string::f("Failed to close RtAudio stream %s", e.what())); | |||||
| } | } | ||||
| } | } | ||||
| INFO("Closed RtAudio stream"); | INFO("Closed RtAudio stream"); | ||||