summaryrefslogtreecommitdiff
path: root/drivers/pulseaudio
diff options
context:
space:
mode:
authorMarcelo Fernandez <marcelofg55@gmail.com>2018-07-03 22:08:43 -0300
committerSaracen <SaracenOne@gmail.com>2018-07-27 16:50:10 +0100
commit061358d8385a78a32a30ac5acf5443c465c8ec61 (patch)
tree9956b66bde27fa25ef97095b8b5f2422495783b1 /drivers/pulseaudio
parent76fd9d215c25874b1c5d33355de0ed983922c32d (diff)
Modified Microphone implementation to handle only one device at a time (WIP)
Diffstat (limited to 'drivers/pulseaudio')
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp184
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h10
2 files changed, 130 insertions, 64 deletions
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 49d3ab2070..2b1a336630 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -287,74 +287,71 @@ float AudioDriverPulseAudio::get_latency() {
void AudioDriverPulseAudio::thread_func(void *p_udata) {
AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)p_udata;
+ unsigned int write_ofs = 0;
+ size_t avail_bytes = 0;
while (!ad->exit_thread) {
- ad->lock();
- ad->start_counting_ticks();
+ size_t read_bytes = 0;
+ size_t written_bytes = 0;
- if (!ad->active) {
- for (unsigned int i = 0; i < ad->pa_buffer_size; i++) {
- ad->samples_out.write[i] = 0;
- }
+ if (avail_bytes == 0) {
+ ad->lock();
+ ad->start_counting_ticks();
- } else {
- ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
-
- if (ad->channels == ad->pa_map.channels) {
+ if (!ad->active) {
for (unsigned int i = 0; i < ad->pa_buffer_size; i++) {
- ad->samples_out.write[i] = ad->samples_in[i] >> 16;
+ ad->samples_out.write[i] = 0;
}
} else {
- // Uneven amount of channels
- unsigned int in_idx = 0;
- unsigned int out_idx = 0;
+ ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
- for (unsigned int i = 0; i < ad->buffer_frames; i++) {
- for (unsigned int j = 0; j < ad->pa_map.channels - 1; j++) {
- ad->samples_out.write[out_idx++] = ad->samples_in[in_idx++] >> 16;
+ if (ad->channels == ad->pa_map.channels) {
+ for (unsigned int i = 0; i < ad->pa_buffer_size; i++) {
+ ad->samples_out.write[i] = ad->samples_in[i] >> 16;
+ }
+ } else {
+ // Uneven amount of channels
+ unsigned int in_idx = 0;
+ unsigned int out_idx = 0;
+
+ for (unsigned int i = 0; i < ad->buffer_frames; i++) {
+ for (unsigned int j = 0; j < ad->pa_map.channels - 1; j++) {
+ ad->samples_out.write[out_idx++] = ad->samples_in[in_idx++] >> 16;
+ }
+ uint32_t l = ad->samples_in[in_idx++];
+ uint32_t r = ad->samples_in[in_idx++];
+ ad->samples_out.write[out_idx++] = (l >> 1 + r >> 1) >> 16;
}
- uint32_t l = ad->samples_in[in_idx++];
- uint32_t r = ad->samples_in[in_idx++];
- ad->samples_out.write[out_idx++] = (l >> 1 + r >> 1) >> 16;
}
}
+
+ avail_bytes = ad->pa_buffer_size * sizeof(int16_t);
+ write_ofs = 0;
+ ad->stop_counting_ticks();
+ ad->unlock();
}
- int error_code;
- int byte_size = ad->pa_buffer_size * sizeof(int16_t);
+ ad->lock();
+ ad->start_counting_ticks();
+
int ret;
do {
ret = pa_mainloop_iterate(ad->pa_ml, 0, NULL);
} while (ret > 0);
- if (pa_stream_get_state(ad->pa_str) == PA_STREAM_READY) {
- const void *ptr = ad->samples_out.ptr();
- while (byte_size > 0) {
- size_t bytes = pa_stream_writable_size(ad->pa_str);
- if (bytes > 0) {
- if (bytes > byte_size) {
- bytes = byte_size;
- }
-
- ret = pa_stream_write(ad->pa_str, ptr, bytes, NULL, 0LL, PA_SEEK_RELATIVE);
- if (ret >= 0) {
- byte_size -= bytes;
- ptr = (const char *)ptr + bytes;
- }
+ if (avail_bytes > 0 && pa_stream_get_state(ad->pa_str) == PA_STREAM_READY) {
+ size_t bytes = pa_stream_writable_size(ad->pa_str);
+ if (bytes > 0) {
+ size_t bytes_to_write = MIN(bytes, avail_bytes);
+ const void *ptr = ad->samples_out.ptr();
+ ret = pa_stream_write(ad->pa_str, ptr + write_ofs, bytes_to_write, NULL, 0LL, PA_SEEK_RELATIVE);
+ if (ret != 0) {
+ ERR_PRINT("pa_stream_write error");
} else {
- ret = pa_mainloop_iterate(ad->pa_ml, 0, NULL);
- if (ret == 0) {
- // If pa_mainloop_iterate returns 0 sleep for 1 msec to wait
- // for the stream to be able to process more bytes
- ad->stop_counting_ticks();
- ad->unlock();
-
- OS::get_singleton()->delay_usec(1000);
-
- ad->lock();
- ad->start_counting_ticks();
- }
+ avail_bytes -= bytes_to_write;
+ write_ofs += bytes_to_write;
+ written_bytes += bytes_to_write;
}
}
}
@@ -379,8 +376,41 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
}
}
+ if (ad->pa_rec_str && pa_stream_get_state(ad->pa_rec_str) == PA_STREAM_READY) {
+ size_t bytes = pa_stream_readable_size(ad->pa_rec_str);
+ if (bytes > 0) {
+ const void *ptr = NULL;
+ size_t maxbytes = ad->audio_input_buffer.size() * sizeof(int16_t);
+
+ bytes = MIN(bytes, maxbytes);
+ ret = pa_stream_peek(ad->pa_rec_str, &ptr, &bytes);
+ if (ret != 0) {
+ ERR_PRINT("pa_stream_peek error");
+ } else {
+ int16_t *srcptr = (int16_t *)ptr;
+ for (size_t i = bytes >> 1; i > 0; i--) {
+ ad->audio_input_buffer.write[ad->audio_input_position++] = int32_t(*srcptr++) << 16;
+ if (ad->audio_input_position >= ad->audio_input_buffer.size()) {
+ ad->audio_input_position = 0;
+ }
+ }
+
+ read_bytes += bytes;
+ ret = pa_stream_drop(ad->pa_rec_str);
+ if (ret != 0) {
+ ERR_PRINT("pa_stream_drop error");
+ }
+ }
+ }
+ }
+
ad->stop_counting_ticks();
ad->unlock();
+
+ // Let the thread rest a while if we haven't read or write anything
+ if (written_bytes == 0 && read_bytes == 0) {
+ OS::get_singleton()->delay_usec(1000);
+ }
}
ad->thread_exited = true;
@@ -510,26 +540,60 @@ void AudioDriverPulseAudio::finish() {
thread = NULL;
}
-bool AudioDriverPulseAudio::capture_device_start(StringName p_name) {
+Error AudioDriverPulseAudio::capture_start() {
- return false;
-}
+ Error err = OK;
-bool AudioDriverPulseAudio::capture_device_stop(StringName p_name) {
+ lock();
- return false;
-}
+ pa_sample_spec spec;
-PoolStringArray AudioDriverPulseAudio::capture_device_get_names() {
+ spec.format = PA_SAMPLE_S16LE;
+ spec.channels = 2;
+ spec.rate = mix_rate;
+
+ int latency = 30;
+ input_buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
+ int buffer_size = input_buffer_frames * spec.channels;
- PoolStringArray names;
+ pa_buffer_attr attr;
+ attr.fragsize = buffer_size * sizeof(int16_t);
+
+ pa_channel_map pa_rec_map;
+ pa_channel_map_init_stereo(&pa_rec_map);
- return names;
+ pa_rec_str = pa_stream_new(pa_ctx, "Record", &spec, &pa_rec_map);
+ if (pa_rec_str == NULL) {
+ ERR_PRINTS("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx))));
+ ERR_FAIL_V(ERR_CANT_OPEN);
+ }
+
+ 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);
+ if (error_code < 0) {
+ ERR_PRINTS("PulseAudio: pa_stream_connect_record error: " + String(pa_strerror(error_code)));
+ err = ERR_CANT_OPEN;
+ }
+
+ audio_input_buffer.resize(input_buffer_frames * 8);
+ for (int i = 0; i < audio_input_buffer.size(); i++) {
+ audio_input_buffer.write[i] = 0;
+ }
+ audio_input_position = 0;
+
+ unlock();
+
+ return err;
}
-StringName AudioDriverPulseAudio::capture_device_get_default_name() {
+Error AudioDriverPulseAudio::capture_stop() {
+ if (pa_rec_str) {
+ pa_stream_disconnect(pa_rec_str);
+ pa_stream_unref(pa_rec_str);
+ pa_rec_str = NULL;
+ }
- return "";
+ return OK;
}
AudioDriverPulseAudio::AudioDriverPulseAudio() {
@@ -537,6 +601,7 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() {
pa_ml = NULL;
pa_ctx = NULL;
pa_str = NULL;
+ pa_rec_str = NULL;
mutex = NULL;
thread = NULL;
@@ -550,6 +615,7 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() {
mix_rate = 0;
buffer_frames = 0;
+ input_buffer_frames = 0;
pa_buffer_size = 0;
channels = 0;
pa_ready = 0;
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
index bfbd340e26..67b99133fb 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -47,6 +47,7 @@ class AudioDriverPulseAudio : public AudioDriver {
pa_mainloop *pa_ml;
pa_context *pa_ctx;
pa_stream *pa_str;
+ pa_stream *pa_rec_str;
pa_channel_map pa_map;
String device_name;
@@ -58,6 +59,7 @@ class AudioDriverPulseAudio : public AudioDriver {
unsigned int mix_rate;
unsigned int buffer_frames;
+ unsigned int input_buffer_frames;
unsigned int pa_buffer_size;
int channels;
int pa_ready;
@@ -98,13 +100,11 @@ public:
virtual void unlock();
virtual void finish();
- virtual bool capture_device_start(StringName p_name);
- virtual bool capture_device_stop(StringName p_name);
- virtual PoolStringArray capture_device_get_names();
- virtual StringName capture_device_get_default_name();
-
virtual float get_latency();
+ virtual Error capture_start();
+ virtual Error capture_stop();
+
AudioDriverPulseAudio();
~AudioDriverPulseAudio();
};