From d04fa5d6b58fda7385effe4937b1e5b60efee8ff Mon Sep 17 00:00:00 2001 From: Oleksandr Bobro Date: Wed, 8 Jul 2020 10:48:26 +0300 Subject: [PATCH] audio: Impl channel adjustment for input sound to allow Mic capture Fix the issue where applications can not capture a sound through Tinyhal with requested channel count less than 8 (the min/max interval for allowed channel count values is set to [8..8] in 'pcm3168a' driver, so pcm_open() function returns error in case count != 8). Implement a patch that provides a channel adjustment for input sound by converting the 8-channel flow to requested Mono or Stereo flow. Signed-off-by: Oleksandr Bobro --- audio/Android.mk | 4 +++ audio/audio_hw.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/audio/Android.mk b/audio/Android.mk index b6ced76..c9a4d93 100644 --- a/audio/Android.mk +++ b/audio/Android.mk @@ -76,6 +76,10 @@ ifeq ($(strip $(TINYHAL_COMPRESS_PLAYBACK)),true) LOCAL_CFLAGS += -DTINYHAL_COMPRESS_PLAYBACK endif +ifeq ($(TARGET_DEVICE),kingfisher) +LOCAL_CFLAGS += -DPLATFORM_RCAR3 +endif + include $(BUILD_SHARED_LIBRARY) endif diff --git a/audio/audio_hw.c b/audio/audio_hw.c index 697a6c2..dbc565b 100644 --- a/audio/audio_hw.c +++ b/audio/audio_hw.c @@ -48,6 +48,7 @@ #endif #include +#include #include @@ -57,6 +58,23 @@ #include #endif +#ifdef PLATFORM_RCAR3 +/* R-Car3 driver supports only 8-channel streams and 48000 sample rate */ +/* These values are defined in _frames_ (not bytes) to match the ALSA API */ +#define OUT_PERIOD_SIZE_DEFAULT 256 +#define OUT_PERIOD_COUNT_DEFAULT 4 +#define OUT_CHANNEL_MASK_DEFAULT AUDIO_CHANNEL_OUT_7POINT1 +#define OUT_CHANNEL_COUNT_DEFAULT 8 +#define OUT_RATE_DEFAULT 48000 + +#define IN_PERIOD_SIZE_DEFAULT 256 +#define IN_PERIOD_COUNT_DEFAULT 4 +#define IN_CHANNEL_MASK_DEFAULT AUDIO_CHANNEL_IN_STEREO +#define IN_CHANNEL_COUNT_DEFAULT 8 +#define IN_RATE_DEFAULT 48000 + +#else + /* These values are defined in _frames_ (not bytes) to match the ALSA API */ #define OUT_PERIOD_SIZE_DEFAULT 256 #define OUT_PERIOD_COUNT_DEFAULT 4 @@ -70,6 +88,8 @@ #define IN_CHANNEL_COUNT_DEFAULT 1 #define IN_RATE_DEFAULT 44100 +#endif + #define IN_PCM_BUFFER_SIZE_DEFAULT \ (IN_PERIOD_SIZE_DEFAULT * IN_CHANNEL_COUNT_DEFAULT * sizeof(uint16_t)) @@ -234,6 +254,9 @@ struct stream_in_pcm { uint32_t period_size; /* ... of PCM input */ struct in_resampler resampler; + + void *pre_read_buf; /* Buffer to store read data before channel adjustment*/ + size_t pre_read_buf_size; }; static uint32_t out_get_sample_rate(const struct audio_stream *stream); @@ -1660,6 +1683,11 @@ static unsigned int in_pcm_cfg_rate(struct stream_in_pcm *in) static unsigned int in_pcm_cfg_channel_count(struct stream_in_pcm *in) { +#ifdef PLATFORM_RCAR3 + /* On R-Car3 driver supports only 8 channels reading */ + return IN_CHANNEL_COUNT_DEFAULT; +#endif + if (in->common.channel_count != 0) { return in->common.channel_count; } else { @@ -1741,6 +1769,22 @@ static int do_open_pcm_input(struct stream_in_pcm *in) ALOGV("input buffer size=0x%zx", in->common.buffer_size); + if (in->common.channel_count != in->hw_channel_count) { + ALOGV("Setup buffer to read %d channel stream with adjustment (HW only supports %d channel reading)", + in->common.channel_count, in->hw_channel_count); + in->pre_read_buf_size = in->common.buffer_size * in->hw_channel_count / in->common.channel_count; + ALOGV("in->pre_read_buf_size=0x%zx", in->pre_read_buf_size); + in->pre_read_buf = calloc(1, in->pre_read_buf_size); + if (!in->pre_read_buf) { + ret = -ENOMEM; + goto fail; + } + } + else { + in->pre_read_buf = NULL; + in->pre_read_buf_size = 0; + } + /* * If the stream rate differs from the PCM rate, we need to * create a resampler. @@ -1758,6 +1802,8 @@ static int do_open_pcm_input(struct stream_in_pcm *in) fail: pcm_close(in->pcm); in->pcm = NULL; + if (in->pre_read_buf) + free(in->pre_read_buf); exit: ALOGV("-do_open_pcm_input error:%d", ret); return ret; @@ -1864,6 +1910,8 @@ static ssize_t do_in_pcm_read(struct audio_stream_in *stream, void *buffer, int ret = 0; struct stream_in_pcm *in = (struct stream_in_pcm *)stream; size_t frames_rq = bytes / in->common.frame_size; + void *read_buf; + size_t read_buf_size; ALOGV("+do_in_pcm_read %zu", bytes); @@ -1874,10 +1922,39 @@ static ssize_t do_in_pcm_read(struct audio_stream_in *stream, void *buffer, goto exit; } + if (in->pre_read_buf) { + read_buf = in->pre_read_buf; + read_buf_size = in->pre_read_buf_size; + } else { + read_buf = buffer; + read_buf_size = bytes; + } + if (in->resampler.resampler != NULL) { - ret = read_resampled_frames(in, buffer, frames_rq); + ret = read_resampled_frames(in, read_buf, frames_rq); } else { - ret = pcm_read(in->pcm, buffer, bytes); + ret = pcm_read(in->pcm, read_buf, read_buf_size); + } + + if (ret < 0) + goto exit; + + if (in->common.channel_count != in->hw_channel_count) { + + ALOGV("do_in_pcm_read(): Adjust %d channel read stream to %d channel stream", + in->hw_channel_count, in->common.channel_count); + + bytes = adjust_channels(read_buf, /* Input buffer */ + in->hw_channel_count, /* Input channel count */ + buffer, /* Output buffer */ + in->common.channel_count, /* Output channel count */ + in->common.frame_size / in->common.channel_count, /* Sample size */ + read_buf_size /* Size of input buffer in bytes */ + ); + if (!bytes) { + ALOGE("do_in_pcm_read(): Failed to adjust channels"); + ret = -1; + } } /* Assume any non-negative return is a successful read */ @@ -2015,6 +2092,14 @@ static void do_close_in_pcm(struct audio_stream *stream) { struct stream_in_pcm *in = (struct stream_in_pcm *)stream; + ALOGV("do_close_in_pcm(%p)", in); + if (in && in->pre_read_buf) + { + free(in->pre_read_buf); + in->pre_read_buf = NULL; + in->pre_read_buf_size = 0; + } + do_close_in_common(stream); }