Line data Source code
1 : // =============================================================================
2 : // PortAudio backend — device management
3 : // =============================================================================
4 :
5 : #include "audio/engine/audio_engine.h"
6 : #include "audio/backend/audio_backend.h"
7 : #include "audio/backend/audio_backend_portaudio_helpers.h"
8 : #include "audio/backend/audio_backend_portaudio_internal.h"
9 : #include <portaudio.h>
10 : #include <iostream>
11 : #include <vector>
12 :
13 : namespace Amplitron {
14 :
15 14 : std::string AudioEngine::get_input_device_name() const {
16 14 : if (input_device_ >= 0) {
17 3 : const PaDeviceInfo* info = Pa_GetDeviceInfo(input_device_);
18 3 : if (info) return info->name;
19 0 : }
20 11 : return "None";
21 7 : }
22 :
23 14 : std::string AudioEngine::get_output_device_name() const {
24 14 : if (output_device_ >= 0) {
25 3 : const PaDeviceInfo* info = Pa_GetDeviceInfo(output_device_);
26 3 : if (info) return info->name;
27 0 : }
28 11 : return "None";
29 7 : }
30 :
31 12 : std::vector<AudioDeviceInfo> AudioEngine::get_input_devices() const {
32 12 : std::vector<AudioDeviceInfo> devices;
33 12 : int count = Pa_GetDeviceCount();
34 33 : for (int i = 0; i < count; ++i) {
35 21 : const PaDeviceInfo* info = Pa_GetDeviceInfo(i);
36 21 : if (info && info->maxInputChannels > 0) {
37 34 : devices.push_back({
38 23 : i, info->name,
39 23 : info->maxInputChannels, info->maxOutputChannels,
40 12 : info->defaultSampleRate,
41 13 : is_usb_device_name(info->name)
42 : });
43 11 : }
44 18 : }
45 12 : return devices;
46 8 : }
47 :
48 12 : std::vector<AudioDeviceInfo> AudioEngine::get_output_devices() const {
49 12 : std::vector<AudioDeviceInfo> devices;
50 12 : int count = Pa_GetDeviceCount();
51 33 : for (int i = 0; i < count; ++i) {
52 21 : const PaDeviceInfo* info = Pa_GetDeviceInfo(i);
53 21 : if (info && info->maxOutputChannels > 0) {
54 34 : devices.push_back({
55 23 : i, info->name,
56 23 : info->maxInputChannels, info->maxOutputChannels,
57 12 : info->defaultSampleRate,
58 13 : is_usb_device_name(info->name)
59 : });
60 11 : }
61 18 : }
62 12 : return devices;
63 8 : }
64 :
65 15 : bool AudioEngine::set_input_device(int device_index) {
66 15 : const PaDeviceInfo* info = Pa_GetDeviceInfo(device_index);
67 15 : if (!info || info->maxInputChannels < 1) {
68 4 : last_error_ = "Invalid input device.";
69 4 : return false;
70 : }
71 :
72 11 : const PaDeviceInfo* out_info = Pa_GetDeviceInfo(output_device_);
73 11 : if (out_info && info->hostApi != out_info->hostApi) {
74 0 : const PaHostApiInfo* in_api = Pa_GetHostApiInfo(info->hostApi);
75 0 : const PaHostApiInfo* out_api = Pa_GetHostApiInfo(out_info->hostApi);
76 0 : std::cerr << "[Amplitron] Warning: Input (" << (in_api ? in_api->name : "?")
77 0 : << ") and output (" << (out_api ? out_api->name : "?")
78 0 : << ") are on different host APIs. Stream may fail." << std::endl;
79 0 : }
80 :
81 11 : int prev_device = input_device_;
82 11 : bool was_running = running_;
83 11 : if (was_running) stop();
84 11 : input_device_ = device_index;
85 8 : if (was_running) {
86 7 : if (!start()) {
87 3 : last_error_ = "Failed to start with new input device. Reverting.";
88 4 : std::cerr << "[Amplitron] " << last_error_ << std::endl;
89 3 : input_device_ = prev_device;
90 3 : if (!start()) {
91 1 : last_error_ = "Failed to revert to previous input device. Engine stopped.";
92 1 : std::cerr << "[Amplitron] " << last_error_ << std::endl;
93 1 : }
94 3 : return false;
95 : }
96 4 : last_error_.clear();
97 2 : }
98 5 : return true;
99 9 : }
100 :
101 15 : bool AudioEngine::set_output_device(int device_index) {
102 15 : const PaDeviceInfo* info = Pa_GetDeviceInfo(device_index);
103 15 : if (!info || info->maxOutputChannels < 1) {
104 5 : last_error_ = "Invalid output device.";
105 5 : return false;
106 : }
107 :
108 10 : const PaDeviceInfo* in_info = Pa_GetDeviceInfo(input_device_);
109 10 : if (in_info && in_info->hostApi != info->hostApi) {
110 0 : const PaHostApiInfo* in_api = Pa_GetHostApiInfo(in_info->hostApi);
111 0 : const PaHostApiInfo* out_api = Pa_GetHostApiInfo(info->hostApi);
112 0 : std::cerr << "[Amplitron] Warning: Input (" << (in_api ? in_api->name : "?")
113 0 : << ") and output (" << (out_api ? out_api->name : "?")
114 0 : << ") are on different host APIs. Stream may fail." << std::endl;
115 0 : }
116 :
117 10 : int prev_device = output_device_;
118 10 : bool was_running = running_;
119 10 : if (was_running) stop();
120 10 : output_device_ = device_index;
121 7 : if (was_running) {
122 7 : if (!start()) {
123 3 : last_error_ = "Failed to start with new output device. Reverting.";
124 4 : std::cerr << "[Amplitron] " << last_error_ << std::endl;
125 3 : output_device_ = prev_device;
126 3 : if (!start()) {
127 1 : last_error_ = "Failed to revert to previous output device. Engine stopped.";
128 1 : std::cerr << "[Amplitron] " << last_error_ << std::endl;
129 1 : }
130 3 : return false;
131 : }
132 4 : last_error_.clear();
133 2 : }
134 4 : return true;
135 9 : }
136 :
137 : } // namespace Amplitron
|