Skip to content

Commit

Permalink
audio: Impl channel adjustment for input sound to allow Mic capture
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
AlexBobro committed Nov 13, 2020
1 parent 5ae55d0 commit d04fa5d
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 2 deletions.
4 changes: 4 additions & 0 deletions audio/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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
89 changes: 87 additions & 2 deletions audio/audio_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#endif

#include <audio_utils/resampler.h>
#include <audio_utils/channels.h>

#include <tinyhal/audio_config.h>

Expand All @@ -57,6 +58,23 @@
#include <vendor/cirrus/scchal/scc_audio.h>
#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
Expand All @@ -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))

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand All @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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 */
Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit d04fa5d

Please sign in to comment.