sim/sim_alsa: add audio offload capture support.
use host liblame as encoder. Signed-off-by: qiaohaijiao1 <qiaohaijiao1@xiaomi.com>
This commit is contained in:
parent
1faeba3f2d
commit
b6472b8b15
@ -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)
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <lame/lame.h>
|
||||
#include <mad.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user