From b6472b8b154d8c3167e0938ab9c6fd12ccb7c79e Mon Sep 17 00:00:00 2001 From: qiaohaijiao1 Date: Mon, 30 Jan 2023 16:37:26 +0800 Subject: [PATCH] sim/sim_alsa: add audio offload capture support. use host liblame as encoder. Signed-off-by: qiaohaijiao1 --- arch/sim/src/Makefile | 1 + arch/sim/src/sim/posix/sim_alsa.c | 83 +++++++--- arch/sim/src/sim/posix/sim_offload.c | 222 +++++++++++++++++++++------ 3 files changed, 237 insertions(+), 69 deletions(-) diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index b5c2da974d8..deb7d59dbea 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -204,6 +204,7 @@ ifeq ($(CONFIG_SIM_SOUND_ALSA),y) CSRCS += sim_offload.c STDLIBS += -lasound STDLIBS += -lmad + STDLIBS += -lmp3lame endif ifeq ($(CONFIG_SIM_VIDEO_V4L2),y) diff --git a/arch/sim/src/sim/posix/sim_alsa.c b/arch/sim/src/sim/posix/sim_alsa.c index 558b8789e4b..1826f221f4a 100644 --- a/arch/sim/src/sim/posix/sim_alsa.c +++ b/arch/sim/src/sim/posix/sim_alsa.c @@ -675,13 +675,67 @@ static int sim_audio_process_playback(struct sim_audio_s *priv, return ret; } +static int sim_audio_process_capture(struct sim_audio_s *priv, + struct ap_buffer_s *apb, + int expect, bool *dequeue) +{ + struct ap_buffer_s *aux = priv->aux; + uint8_t *out = NULL; + uint32_t outsize; + int frames = 0; + int ret; + + frames = snd_pcm_readi(priv->pcm, apb->samp, expect); + if (frames < 0) + { + return frames; + } + + ret = priv->ops->process(priv->codec, apb->samp, + frames * priv->frame_size, &out, &outsize); + if (ret < 0) + { + return 0; + } + + /* pcm, process bypass */ + + if (out == apb->samp) + { + apb->nbytes = outsize; + *dequeue = true; + goto out; + } + + memcpy(aux->samp + aux->curbyte, out, outsize); + aux->curbyte += outsize; + + if (aux->curbyte >= apb->nmaxbytes) + { + /* memcpy from aux to apb, and dequeue to apps */ + + memcpy(apb->samp, aux->samp, apb->nmaxbytes); + apb->nbytes = apb->nmaxbytes; + *dequeue = true; + + /* memmove the remain data to beginning of aux */ + + memmove(aux->samp, + aux->samp + apb->nmaxbytes, + aux->curbyte - apb->nmaxbytes); + aux->curbyte -= apb->nmaxbytes; + } + +out: + return frames * priv->frame_size; +} + static void sim_audio_process(struct sim_audio_s *priv) { snd_pcm_sframes_t expect; struct ap_buffer_s *apb; snd_pcm_sframes_t avail; bool dequeue = false; - uint32_t outsize; int ret = 0; if (!priv->pcm) @@ -709,8 +763,7 @@ static void sim_audio_process(struct sim_audio_s *priv) avail = snd_pcm_avail(priv->pcm); if (avail < expect) { - ret = avail; - goto out; + return; } if (priv->playback) @@ -719,21 +772,12 @@ static void sim_audio_process(struct sim_audio_s *priv) } else { - ret = snd_pcm_readi(priv->pcm, apb->samp, expect); - if (ret < 0) - { - goto out; - } + ret = sim_audio_process_capture(priv, apb, expect, &dequeue); + } - ret = priv->ops->process(priv->codec, apb->samp, - ret * priv->frame_size, &apb->samp, &outsize); - if (ret < 0) - { - return; - } - - apb->curbyte += ret; - dequeue = true; + if (ret < 0) + { + goto out; } if (dequeue) @@ -742,7 +786,6 @@ static void sim_audio_process(struct sim_audio_s *priv) dq_remfirst(&priv->pendq); - apb->nbytes = apb->curbyte; if (apb->flags & AUDIO_APB_FINAL) { final = true; @@ -761,6 +804,8 @@ static void sim_audio_process(struct sim_audio_s *priv) } } + return; + out: if (ret == -EPIPE) { @@ -768,7 +813,7 @@ out: snd_pcm_prepare(priv->pcm); snd_pcm_start(priv->pcm); } - else if (ret < 0 && ret != -EAGAIN) + else if (ret != -EAGAIN) { aerr("pcm writei/readi failed %d, %s\n", ret, snd_strerror(ret)); } diff --git a/arch/sim/src/sim/posix/sim_offload.c b/arch/sim/src/sim/posix/sim_offload.c index 17755d2dc3e..25ed579c64d 100644 --- a/arch/sim/src/sim/posix/sim_offload.c +++ b/arch/sim/src/sim/posix/sim_offload.c @@ -25,6 +25,7 @@ #include #include +#include #include #include "sim_offload.h" @@ -33,19 +34,26 @@ * Private Function Prototypes ****************************************************************************/ -static void *sim_audio_mp3_init(struct audio_info_s *info); -static int sim_audio_mp3_samples(void *handle); -static int sim_audio_mp3_decode(void *handle, - uint8_t *in, uint32_t insize, - uint8_t **out, uint32_t *outsize); -static void sim_audio_mp3_uninit(void *handle); - static void *sim_audio_pcm_init(struct audio_info_s *info); static int sim_audio_pcm_process(void *handle, uint8_t *in, uint32_t insize, uint8_t **out, uint32_t *outsize); static void sim_audio_pcm_uninit(void *handle); +static void *sim_audio_mad_init(struct audio_info_s *info); +static int sim_audio_mad_samples(void *handle); +static int sim_audio_mad_decode(void *handle, + uint8_t *in, uint32_t insize, + uint8_t **out, uint32_t *outsize); +static void sim_audio_mad_uninit(void *handle); + +static void *sim_audio_lame_init(struct audio_info_s *info); +static int sim_audio_lame_samples(void *handle); +static int sim_audio_lame_encode(void *handle, + uint8_t *in, uint32_t insize, + uint8_t **out, uint32_t *outsize); +static void sim_audio_lame_uninit(void *handle); + /**************************************************************************** * Public Data ****************************************************************************/ @@ -63,10 +71,18 @@ const struct sim_codec_ops_s g_codec_ops[] = { AUDIO_FMT_MP3, AUDCODEC_DEC, - sim_audio_mp3_init, - sim_audio_mp3_samples, - sim_audio_mp3_decode, - sim_audio_mp3_uninit + sim_audio_mad_init, + sim_audio_mad_samples, + sim_audio_mad_decode, + sim_audio_mad_uninit + }, + { + AUDIO_FMT_MP3, + AUDCODEC_ENC, + sim_audio_lame_init, + sim_audio_lame_samples, + sim_audio_lame_encode, + sim_audio_lame_uninit }, { AUDIO_FMT_UNDEF, @@ -82,7 +98,12 @@ const struct sim_codec_ops_s g_codec_ops[] = * Private Types ****************************************************************************/ -struct sim_decoder_mp3_s +struct sim_codec_pcm_s +{ + uint32_t frame_size; +}; + +struct sim_mad_s { uint8_t *out; struct mad_stream stream; @@ -90,21 +111,23 @@ struct sim_decoder_mp3_s struct mad_synth synth; }; -struct sim_codec_pcm_s +struct sim_lame_s { - uint32_t frame_size; + uint8_t *out; + uint32_t max; + lame_global_flags *gfp; }; /**************************************************************************** * Private Data ****************************************************************************/ -static const uint16_t g_mpa_freq_tab[3] = +static const uint16_t g_mad_freq_tab[3] = { 44100, 48000, 32000 }; -static const uint16_t g_mpa_bitrate_tab[2][3][15] = +static const uint16_t g_mad_bitrate_tab[2][3][15] = { { { @@ -134,7 +157,27 @@ static const uint16_t g_mpa_bitrate_tab[2][3][15] = * Private Functions ****************************************************************************/ -static int sim_audio_mp3_scale(mad_fixed_t sample) +static void *sim_audio_pcm_init(struct audio_info_s *info) +{ + return kmm_malloc(sizeof(struct sim_codec_pcm_s)); +} + +static int sim_audio_pcm_process(void *handle, + uint8_t *in, uint32_t insize, + uint8_t **out, uint32_t *outsize) +{ + *out = in; + *outsize = insize; + + return *outsize; +} + +static void sim_audio_pcm_uninit(void *handle) +{ + kmm_free(handle); +} + +static int sim_mad_scale(mad_fixed_t sample) { sample += 1L << (MAD_F_FRACBITS - 16); @@ -150,7 +193,7 @@ static int sim_audio_mp3_scale(mad_fixed_t sample) return sample >> (MAD_F_FRACBITS + 1 - 16); } -static int sim_audio_check_mpeg(uint32_t header) +static int sim_mad_check_mpeg(uint32_t header) { /* header */ @@ -190,7 +233,7 @@ static int sim_audio_check_mpeg(uint32_t header) return 0; } -static int sim_audio_mp3_check(uint32_t header) +static int sim_mad_check(uint32_t header) { int sample_rate; int frame_size; @@ -202,7 +245,7 @@ static int sim_audio_mp3_check(uint32_t header) int lsf; int ret; - ret = sim_audio_check_mpeg(header); + ret = sim_mad_check_mpeg(header); if (ret < 0) { return ret; @@ -224,17 +267,17 @@ static int sim_audio_mp3_check(uint32_t header) sr_idx = (header >> 10) & 3; padding = (header >> 9) & 1; - if (sr_idx >= sizeof(g_mpa_freq_tab) / sizeof(g_mpa_freq_tab[0]) || + if (sr_idx >= sizeof(g_mad_freq_tab) / sizeof(g_mad_freq_tab[0]) || br_idx >= 0xf) { return -EINVAL; } - sample_rate = g_mpa_freq_tab[sr_idx] >> (lsf + mpeg25); + sample_rate = g_mad_freq_tab[sr_idx] >> (lsf + mpeg25); if (br_idx != 0) { - frame_size = g_mpa_bitrate_tab[lsf][layer - 1][br_idx]; + frame_size = g_mad_bitrate_tab[lsf][layer - 1][br_idx]; switch (layer) { @@ -265,12 +308,12 @@ static int sim_audio_mp3_check(uint32_t header) return frame_size; } -static void *sim_audio_mp3_init(struct audio_info_s *info) +static void *sim_audio_mad_init(struct audio_info_s *info) { - struct sim_decoder_mp3_s *codec; + struct sim_mad_s *codec; - codec = kmm_malloc(sizeof(struct sim_decoder_mp3_s)); - if (codec == NULL) + codec = kmm_malloc(sizeof(struct sim_mad_s)); + if (!codec) { return NULL; } @@ -280,7 +323,7 @@ static void *sim_audio_mp3_init(struct audio_info_s *info) mad_synth_init(&codec->synth); codec->out = kmm_malloc(sizeof(codec->synth.pcm.samples)); - if (codec->out == NULL) + if (!codec->out) { goto out; } @@ -296,24 +339,24 @@ out: return NULL; } -static int sim_audio_mp3_samples(void *handle) +static int sim_audio_mad_samples(void *handle) { - struct sim_decoder_mp3_s *codec = (struct sim_decoder_mp3_s *)handle; + struct sim_mad_s *codec = (struct sim_mad_s *)handle; return sizeof(codec->synth.pcm.samples[0]) / sizeof(mad_fixed_t); } -static int sim_audio_mp3_decode(void *handle, +static int sim_audio_mad_decode(void *handle, uint8_t *in, uint32_t insize, uint8_t **out, uint32_t *outsize) { - struct sim_decoder_mp3_s *codec = (struct sim_decoder_mp3_s *)handle; + struct sim_mad_s *codec = (struct sim_mad_s *)handle; const mad_fixed_t *right_ch; const mad_fixed_t *left_ch; - int mpa_header; int nchannels; int nsamples; uint8_t *ptr; + int header; int i = 0; int size; int ret; @@ -323,11 +366,11 @@ static int sim_audio_mp3_decode(void *handle, return -ENODATA; } - mpa_header = in[0] << 24 | in[1] << 16 | in[2] << 8 | in[3]; - size = sim_audio_mp3_check(mpa_header); + header = in[0] << 24 | in[1] << 16 | in[2] << 8 | in[3]; + size = sim_mad_check(header); if (size < 0) { - return -EINVAL; + return size; } if (insize < size + 8) @@ -357,13 +400,13 @@ static int sim_audio_mp3_decode(void *handle, /* output sample(s) in 16-bit signed little-endian PCM */ - sample = sim_audio_mp3_scale(*left_ch++); + sample = sim_mad_scale(*left_ch++); ptr[i] = (sample >> 0) & 0xff; ptr[i + 1] = (sample >> 8) & 0xff; if (nchannels == 2) { - sample = sim_audio_mp3_scale(*right_ch++); + sample = sim_mad_scale(*right_ch++); ptr[i + 2] = (sample >> 0) & 0xff; ptr[i + 3] = (sample >> 8) & 0xff; } @@ -377,9 +420,9 @@ static int sim_audio_mp3_decode(void *handle, return size; } -static void sim_audio_mp3_uninit(void *handle) +static void sim_audio_mad_uninit(void *handle) { - struct sim_decoder_mp3_s *codec = (struct sim_decoder_mp3_s *)handle; + struct sim_mad_s *codec = (struct sim_mad_s *)handle; mad_synth_finish(&(codec->synth)); mad_frame_finish(&(codec->frame)); @@ -389,22 +432,101 @@ static void sim_audio_mp3_uninit(void *handle) kmm_free(codec); } -static void *sim_audio_pcm_init(struct audio_info_s *info) +void *sim_audio_lame_init(struct audio_info_s *info) { - return kmm_malloc(sizeof(struct sim_codec_pcm_s)); + struct sim_lame_s *codec; + int samples; + int ret; + + codec = kmm_zalloc(sizeof(struct sim_lame_s)); + if (codec == NULL) + { + return NULL; + } + + codec->gfp = lame_init(); + if (codec->gfp == NULL) + { + goto error; + } + + if (info) + { + lame_set_num_channels(codec->gfp, info->channels); + lame_set_mode(codec->gfp, info->channels > 1 ? STEREO : MONO); + + lame_set_in_samplerate (codec->gfp, info->samplerate); + lame_set_out_samplerate(codec->gfp, info->samplerate); + } + + ret = lame_init_params(codec->gfp); + if (ret < 0) + { + goto error; + } + + samples = lame_get_framesize(codec->gfp); + codec->max = samples + samples / 4 + 7200; + + codec->out = kmm_malloc(codec->max); + if (codec->out == NULL) + { + goto error; + } + + return codec; + +error: + if (codec->gfp) + { + lame_close(codec->gfp); + } + + if (codec->out) + { + kmm_free(codec->out); + } + + kmm_free(codec); + return NULL; } -static int sim_audio_pcm_process(void *handle, - uint8_t *in, uint32_t insize, - uint8_t **out, uint32_t *outsize) +static int sim_audio_lame_samples(void *handle) { - *out = in; - *outsize = insize; + struct sim_lame_s *codec = (struct sim_lame_s *)handle; - return *outsize; + return lame_get_framesize(codec->gfp); } -static void sim_audio_pcm_uninit(void *handle) +static int sim_audio_lame_encode(void *handle, + uint8_t *in, uint32_t insize, + uint8_t **out, uint32_t *outsize) { - kmm_free(handle); + struct sim_lame_s *codec = (struct sim_lame_s *)handle; + int samples; + int ret; + int chs; + + chs = lame_get_num_channels(codec->gfp); + samples = insize / (sizeof(short int) * chs); + + ret = lame_encode_buffer_interleaved(codec->gfp, (short int *)in, samples, + codec->out, codec->max); + if (ret < 0) + { + return ret; + } + + *out = codec->out; + *outsize = ret; + return insize; +} + +static void sim_audio_lame_uninit(void *handle) +{ + struct sim_lame_s *codec = (struct sim_lame_s *)handle; + + kmm_free(codec->out); + lame_close(codec->gfp); + kmm_free(codec); }