summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp128
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h15
2 files changed, 132 insertions, 11 deletions
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 2b1a336630..71e7591566 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -402,6 +402,26 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
}
}
}
+
+ // User selected a new device, finish the current one so we'll init the new device
+ if (ad->capture_device_name != ad->capture_new_device) {
+ ad->capture_device_name = ad->capture_new_device;
+ ad->capture_finish_device();
+
+ Error err = ad->capture_init_device();
+ if (err != OK) {
+ ERR_PRINT("PulseAudio: capture_init_device error");
+ ad->capture_device_name = "Default";
+ ad->capture_new_device = "Default";
+
+ err = ad->capture_init_device();
+ if (err != OK) {
+ ad->active = false;
+ ad->exit_thread = true;
+ break;
+ }
+ }
+ }
}
ad->stop_counting_ticks();
@@ -540,11 +560,16 @@ void AudioDriverPulseAudio::finish() {
thread = NULL;
}
-Error AudioDriverPulseAudio::capture_start() {
-
- Error err = OK;
+Error AudioDriverPulseAudio::capture_init_device() {
- lock();
+ // If there is a specified device check that it is really present
+ if (capture_device_name != "Default") {
+ Array list = capture_get_device_list();
+ if (list.find(capture_device_name) == -1) {
+ capture_device_name = "Default";
+ capture_new_device = "Default";
+ }
+ }
pa_sample_spec spec;
@@ -568,11 +593,12 @@ Error AudioDriverPulseAudio::capture_start() {
ERR_FAIL_V(ERR_CANT_OPEN);
}
+ const char *dev = capture_device_name == "Default" ? NULL : capture_device_name.utf8().get_data();
pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE);
- int error_code = pa_stream_connect_record(pa_rec_str, NULL, &attr, flags);
+ int error_code = pa_stream_connect_record(pa_rec_str, dev, &attr, flags);
if (error_code < 0) {
ERR_PRINTS("PulseAudio: pa_stream_connect_record error: " + String(pa_strerror(error_code)));
- err = ERR_CANT_OPEN;
+ ERR_FAIL_V(ERR_CANT_OPEN);
}
audio_input_buffer.resize(input_buffer_frames * 8);
@@ -581,21 +607,101 @@ Error AudioDriverPulseAudio::capture_start() {
}
audio_input_position = 0;
- unlock();
-
- return err;
+ return OK;
}
-Error AudioDriverPulseAudio::capture_stop() {
+void AudioDriverPulseAudio::capture_finish_device() {
+
if (pa_rec_str) {
- pa_stream_disconnect(pa_rec_str);
+ int ret = pa_stream_disconnect(pa_rec_str);
+ if (ret != 0) {
+ ERR_PRINTS("PulseAudio: pa_stream_disconnect error: " + String(pa_strerror(ret)));
+ }
pa_stream_unref(pa_rec_str);
pa_rec_str = NULL;
}
+}
+
+Error AudioDriverPulseAudio::capture_start() {
+
+ lock();
+ Error err = capture_init_device();
+ unlock();
+
+ return err;
+}
+
+Error AudioDriverPulseAudio::capture_stop() {
+ lock();
+ capture_finish_device();
+ unlock();
return OK;
}
+void AudioDriverPulseAudio::capture_set_device(const String &p_name) {
+
+ lock();
+ capture_new_device = p_name;
+ unlock();
+}
+
+void AudioDriverPulseAudio::pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata) {
+ AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
+
+ // If eol is set to a positive number, you're at the end of the list
+ if (eol > 0) {
+ return;
+ }
+
+ if (l->monitor_of_sink == PA_INVALID_INDEX) {
+ ad->pa_rec_devices.push_back(l->name);
+ }
+
+ ad->pa_status++;
+}
+
+Array AudioDriverPulseAudio::capture_get_device_list() {
+
+ pa_rec_devices.clear();
+ pa_rec_devices.push_back("Default");
+
+ if (pa_ctx == NULL) {
+ return pa_rec_devices;
+ }
+
+ lock();
+
+ // Get the device list
+ pa_status = 0;
+ pa_operation *pa_op = pa_context_get_source_info_list(pa_ctx, pa_sourcelist_cb, (void *)this);
+ if (pa_op) {
+ while (pa_status == 0) {
+ int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
+ if (ret < 0) {
+ ERR_PRINT("pa_mainloop_iterate error");
+ }
+ }
+
+ pa_operation_unref(pa_op);
+ } else {
+ ERR_PRINT("pa_context_get_server_info error");
+ }
+
+ unlock();
+
+ return pa_rec_devices;
+}
+
+String AudioDriverPulseAudio::capture_get_device() {
+
+ lock();
+ String name = capture_device_name;
+ unlock();
+
+ return name;
+}
+
AudioDriverPulseAudio::AudioDriverPulseAudio() {
pa_ml = NULL;
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
index 67b99133fb..e8b2f19e6e 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -54,6 +54,10 @@ class AudioDriverPulseAudio : public AudioDriver {
String new_device;
String default_device;
+ String capture_device_name;
+ String capture_new_device;
+ String capture_default_device;
+
Vector<int32_t> samples_in;
Vector<int16_t> samples_out;
@@ -65,6 +69,7 @@ class AudioDriverPulseAudio : public AudioDriver {
int pa_ready;
int pa_status;
Array pa_devices;
+ Array pa_rec_devices;
bool active;
bool thread_exited;
@@ -76,10 +81,14 @@ class AudioDriverPulseAudio : public AudioDriver {
static void pa_sink_info_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata);
static void pa_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata);
static void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata);
+ static void pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata);
Error init_device();
void finish_device();
+ Error capture_init_device();
+ void capture_finish_device();
+
void detect_channels();
static void thread_func(void *p_udata);
@@ -93,9 +102,15 @@ public:
virtual void start();
virtual int get_mix_rate() const;
virtual SpeakerMode get_speaker_mode() const;
+
virtual Array get_device_list();
virtual String get_device();
virtual void set_device(String device);
+
+ virtual Array capture_get_device_list();
+ virtual void capture_set_device(const String &p_name);
+ virtual String capture_get_device();
+
virtual void lock();
virtual void unlock();
virtual void finish();