diff options
author | Edward Wang <ewang@cyngn.com> | 2015-10-05 16:23:15 -0700 |
---|---|---|
committer | Steve Kondik <steve@cyngn.com> | 2015-10-26 17:54:09 -0700 |
commit | d802032d354778f96851c5ea600249b6cd9411c6 (patch) | |
tree | dfa18a1771044984de726b3e2c1b89901c44b364 | |
parent | dc8387b35a843f36d807c74ba1d5a0ecaa0e0353 (diff) | |
download | hardware_libhardware-d802032d354778f96851c5ea600249b6cd9411c6.zip hardware_libhardware-d802032d354778f96851c5ea600249b6cd9411c6.tar.gz hardware_libhardware-d802032d354778f96851c5ea600249b6cd9411c6.tar.bz2 |
remote_submix: Fix resampler and channel conversion
* Add support for multiple channels to resampler
* Fix out-of-bounds write during channel conversion.
When pipe stream is stereo and input stream is mono, it will do
inplace conversion. But the input buffer is only allocated for
mono channel. Repurpose resampler_buffer for both conversion and
resampling.
Change-Id: I5a683148317e4fabc1c40b308472f698a8429c6b
-rw-r--r-- | modules/audio_remote_submix/audio_hw.cpp | 55 |
1 files changed, 39 insertions, 16 deletions
diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp index 20c0fab..58bc4a2 100644 --- a/modules/audio_remote_submix/audio_hw.cpp +++ b/modules/audio_remote_submix/audio_hw.cpp @@ -159,11 +159,11 @@ typedef struct route_config { // destroyed if both and input and output streams are destroyed. struct submix_stream_out *output; struct submix_stream_in *input; -#if ENABLE_RESAMPLING - // Buffer used as temporary storage for resampled data prior to returning data to the output +#if (ENABLE_RESAMPLING || ENABLE_CHANNEL_CONVERSION) + // Buffer used as temporary storage for audio data prior to returning data to the output // stream. - int16_t resampler_buffer[DEFAULT_PIPE_SIZE_IN_FRAMES]; -#endif // ENABLE_RESAMPLING + int16_t processor_buffer[DEFAULT_PIPE_SIZE_IN_FRAMES]; +#endif } route_config_t; struct submix_audio_device { @@ -473,8 +473,8 @@ static void submix_audio_device_release_pipe_l(struct submix_audio_device * cons rsxadev->routes[route_idx].rsxSource = 0; } memset(rsxadev->routes[route_idx].address, 0, AUDIO_DEVICE_MAX_ADDRESS_LEN); -#ifdef ENABLE_RESAMPLING - memset(rsxadev->routes[route_idx].resampler_buffer, 0, +#if (ENABLE_RESAMPLING || ENABLE_CHANNEL_CONVERSION) + memset(rsxadev->routes[route_idx].processor_buffer, 0, sizeof(int16_t) * DEFAULT_PIPE_SIZE_IN_FRAMES); #endif } @@ -1133,13 +1133,14 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, } #endif // ENABLE_CHANNEL_CONVERSION +#if (ENABLE_RESAMPLING || ENABLE_CHANNEL_CONVERSION) + const size_t processor_buffer_size_frames = + sizeof(rsxadev->routes[in->route_handle].processor_buffer) / frame_size; +#endif #if ENABLE_RESAMPLING const uint32_t input_sample_rate = in_get_sample_rate(&stream->common); const uint32_t output_sample_rate = rsxadev->routes[in->route_handle].config.output_sample_rate; - const size_t resampler_buffer_size_frames = - sizeof(rsxadev->routes[in->route_handle].resampler_buffer) / - sizeof(rsxadev->routes[in->route_handle].resampler_buffer[0]); float resampler_ratio = 1.0f; // Determine whether resampling is required. if (input_sample_rate != output_sample_rate) { @@ -1156,16 +1157,18 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, while ((remaining_frames > 0) && (attempts < MAX_READ_ATTEMPTS)) { ssize_t frames_read = -1977; size_t read_frames = remaining_frames; -#if ENABLE_RESAMPLING +#if (ENABLE_RESAMPLING || ENABLE_CHANNEL_CONVERSION) char* const saved_buff = buff; +#endif +#if ENABLE_RESAMPLING if (resampler_ratio != 1.0f) { // Calculate the number of frames from the pipe that need to be read to generate // the data for the input stream read. const size_t frames_required_for_resampler = (size_t)( (float)read_frames * (float)resampler_ratio); - read_frames = min(frames_required_for_resampler, resampler_buffer_size_frames); + read_frames = min(frames_required_for_resampler, processor_buffer_size_frames); // Read into the resampler buffer. - buff = (char*)rsxadev->routes[in->route_handle].resampler_buffer; + buff = (char*)rsxadev->routes[in->route_handle].processor_buffer; } #endif // ENABLE_RESAMPLING #if ENABLE_CHANNEL_CONVERSION @@ -1173,6 +1176,13 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, // Need to read half the requested frames since the converted output // data will take twice the space (mono->stereo). read_frames /= 2; + } else if (output_channels == 2 && input_channels == 1) { + // If the resampler is active, we already swapped for the processor_buffer + if (resampler_ratio == 1.0f) { + buff = (char*)rsxadev->routes[in->route_handle].processor_buffer; + } + + read_frames = min(read_frames, processor_buffer_size_frames/2); } #endif // ENABLE_CHANNEL_CONVERSION @@ -1191,11 +1201,17 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, if (output_channels == 2 && input_channels == 1) { // Offset into the output stream data in samples. ssize_t output_stream_offset = 0; + // If resampler is active, continue writing to the temporary buffer + int16_t *mixed_buffer = + (resampler_ratio == 1.0f) ? (int16_t*)saved_buff : (int16_t*)buff; for (ssize_t input_stream_frame = 0; input_stream_frame < frames_read; input_stream_frame++, output_stream_offset += 2) { // Average the content from both channels. - data[input_stream_frame] = ((int32_t)data[output_stream_offset] + - (int32_t)data[output_stream_offset + 1]) / 2; + mixed_buffer[input_stream_frame] = ((int32_t)data[output_stream_offset] + + (int32_t)data[output_stream_offset + 1]) / 2; + } + if (resampler_ratio == 1.0f) { + buff = saved_buff; } } else if (output_channels == 1 && input_channels == 2) { // Offset into the input stream data in samples. @@ -1219,13 +1235,20 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, // sampled at a different rate this will result in very nasty aliasing. const float output_stream_frames = (float)frames_read; size_t input_stream_frame = 0; + size_t input_buf_offset = 0, output_buf_offset = 0; for (float output_stream_frame = 0.0f; output_stream_frame < output_stream_frames && input_stream_frame < remaining_frames; output_stream_frame += resampler_ratio, input_stream_frame++) { - resampled_buffer[input_stream_frame] = data[(size_t)output_stream_frame]; + input_buf_offset = input_stream_frame * input_channels; + output_buf_offset = (size_t)output_stream_frame * input_channels; + resampled_buffer[input_buf_offset] = data[output_buf_offset]; + if (input_channels == 2) { + // copy second channel in the frame + resampled_buffer[input_buf_offset + 1] = data[output_buf_offset + 1]; + } } - ALOG_ASSERT(input_stream_frame <= (ssize_t)resampler_buffer_size_frames); + ALOG_ASSERT(input_stream_frame <= (ssize_t)processor_buffer_size_frames); SUBMIX_ALOGV("in_read(): resampler produced %zd frames", input_stream_frame); frames_read = input_stream_frame; buff = saved_buff; |