diff options
author | Marcelo Fernandez <marcelofg55@gmail.com> | 2018-07-03 22:08:43 -0300 |
---|---|---|
committer | Saracen <SaracenOne@gmail.com> | 2018-07-27 16:50:10 +0100 |
commit | 061358d8385a78a32a30ac5acf5443c465c8ec61 (patch) | |
tree | 9956b66bde27fa25ef97095b8b5f2422495783b1 /drivers/pulseaudio | |
parent | 76fd9d215c25874b1c5d33355de0ed983922c32d (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.cpp | 184 | ||||
-rw-r--r-- | drivers/pulseaudio/audio_driver_pulseaudio.h | 10 |
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(); }; |