sim/sim_alsa.c: support streaming data when offload playback.
Audio offload playback, change data organization from fragmented to streaming. Signed-off-by: qiaohaijiao1 <qiaohaijiao1@xiaomi.com>
This commit is contained in:
parent
26ac5335e5
commit
38039df16a
@ -201,6 +201,7 @@ endif
|
||||
|
||||
ifeq ($(CONFIG_SIM_SOUND_ALSA),y)
|
||||
CSRCS += sim_alsa.c
|
||||
CSRCS += sim_offload.c
|
||||
STDLIBS += -lasound
|
||||
STDLIBS += -lmad
|
||||
endif
|
||||
|
@ -31,49 +31,19 @@
|
||||
#include <debug.h>
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <mad.h>
|
||||
|
||||
#include "sim_offload.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define AUDMIN(a,b) ((a) > (b) ? (b) : (a))
|
||||
#define AUDCODEC_DEC 0x01
|
||||
#define AUDCODEC_ENC 0x10
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct sim_codec_ops_s
|
||||
{
|
||||
uint8_t format;
|
||||
uint8_t flags;
|
||||
|
||||
/* init codec handle */
|
||||
|
||||
void *(*init)(void);
|
||||
|
||||
/* return how much samples return from deocde.
|
||||
* or encoder needed.
|
||||
* */
|
||||
|
||||
int (*get_samples)(void *handle);
|
||||
|
||||
/* perform dec or enc on [in] data with [insize] bytes
|
||||
* [out] data with [outsize] is pcm data after decode, or
|
||||
* compress data when encode.
|
||||
* return: < 0 means failed. == 0 success
|
||||
*/
|
||||
|
||||
int (*process)(void *handle, uint8_t *in, uint32_t insize,
|
||||
uint8_t **out, unsigned int *outsize);
|
||||
|
||||
/* uninit codec handle */
|
||||
|
||||
void (*uninit)(void *handle);
|
||||
};
|
||||
|
||||
struct sim_audio_s
|
||||
{
|
||||
struct audio_lowerhalf_s dev;
|
||||
@ -96,20 +66,9 @@ struct sim_audio_s
|
||||
snd_mixer_elem_t *volume;
|
||||
|
||||
void *codec;
|
||||
const struct sim_codec_ops_s *ops;
|
||||
};
|
||||
const sim_codec_ops_s *ops;
|
||||
|
||||
struct sim_decoder_mp3_s
|
||||
{
|
||||
uint8_t *out;
|
||||
struct mad_stream stream;
|
||||
struct mad_frame frame;
|
||||
struct mad_synth synth;
|
||||
};
|
||||
|
||||
struct sim_codec_pcm_s
|
||||
{
|
||||
uint32_t frame_size;
|
||||
struct ap_buffer_s *aux;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@ -142,19 +101,6 @@ static int sim_audio_ioctl(struct audio_lowerhalf_s *dev, int cmd,
|
||||
static int sim_audio_reserve(struct audio_lowerhalf_s *dev);
|
||||
static int sim_audio_release(struct audio_lowerhalf_s *dev);
|
||||
|
||||
static void *sim_audio_mp3_init(void);
|
||||
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(void);
|
||||
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);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
@ -178,26 +124,6 @@ static const struct audio_ops_s g_sim_audio_ops =
|
||||
.release = sim_audio_release,
|
||||
};
|
||||
|
||||
static const struct sim_codec_ops_s g_codec_ops[] =
|
||||
{
|
||||
{
|
||||
AUDIO_FMT_PCM,
|
||||
AUDCODEC_DEC | AUDCODEC_ENC,
|
||||
sim_audio_pcm_init,
|
||||
NULL,
|
||||
sim_audio_pcm_process,
|
||||
sim_audio_pcm_uninit,
|
||||
},
|
||||
{
|
||||
AUDIO_FMT_MP3,
|
||||
AUDCODEC_DEC,
|
||||
sim_audio_mp3_init,
|
||||
sim_audio_mp3_samples,
|
||||
sim_audio_mp3_decode,
|
||||
sim_audio_mp3_uninit
|
||||
}
|
||||
};
|
||||
|
||||
static sq_queue_t g_sim_audio;
|
||||
|
||||
/****************************************************************************
|
||||
@ -297,7 +223,7 @@ static void sim_audio_config_ops(struct sim_audio_s *priv, uint8_t fmt)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(g_codec_ops) / sizeof(g_codec_ops[0]); i++)
|
||||
for (i = 0; g_codec_ops[i].format != AUDIO_FMT_UNDEF; i++)
|
||||
{
|
||||
if (g_codec_ops[i].format == fmt &&
|
||||
((priv->playback && g_codec_ops[i].flags & AUDCODEC_DEC) ||
|
||||
@ -536,8 +462,21 @@ static int sim_audio_shutdown(struct audio_lowerhalf_s *dev)
|
||||
static int sim_audio_start(struct audio_lowerhalf_s *dev)
|
||||
{
|
||||
struct sim_audio_s *priv = (struct sim_audio_s *)dev;
|
||||
struct audio_buf_desc_s buf_desc;
|
||||
int ret;
|
||||
|
||||
priv->codec = priv->ops->init();
|
||||
/* reserved aux buffer. */
|
||||
|
||||
buf_desc.numbytes = priv->buffer_size * 2;
|
||||
buf_desc.u.pbuffer = &priv->aux;
|
||||
|
||||
ret = apb_alloc(&buf_desc);
|
||||
if (ret != sizeof(buf_desc))
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->codec = priv->ops->init(NULL);
|
||||
if (priv->codec == NULL)
|
||||
{
|
||||
return -ENOSYS;
|
||||
@ -571,6 +510,9 @@ static int sim_audio_stop(struct audio_lowerhalf_s *dev)
|
||||
priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_COMPLETE, NULL, OK);
|
||||
#endif
|
||||
|
||||
apb_free(priv->aux);
|
||||
priv->aux = NULL;
|
||||
|
||||
priv->ops->uninit(priv->codec);
|
||||
priv->ops = NULL;
|
||||
|
||||
@ -665,12 +607,85 @@ static int sim_audio_release(struct audio_lowerhalf_s *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_audio_process_playback(struct sim_audio_s *priv,
|
||||
struct ap_buffer_s *apb,
|
||||
bool *dequeue)
|
||||
{
|
||||
struct ap_buffer_s *aux = priv->aux;
|
||||
uint8_t *out = NULL;
|
||||
uint8_t *in = NULL;
|
||||
uint32_t outsize;
|
||||
uint32_t insize;
|
||||
int ret;
|
||||
|
||||
/* 1, copy apb buffer to aux when the apb buffer just enqueued.
|
||||
* */
|
||||
|
||||
if (apb->flags & AUDIO_APB_OUTPUT_ENQUEUED)
|
||||
{
|
||||
memcpy(aux->samp + aux->nbytes, apb->samp, apb->nbytes);
|
||||
aux->nbytes += apb->nbytes;
|
||||
apb->flags &= ~AUDIO_APB_OUTPUT_ENQUEUED;
|
||||
}
|
||||
|
||||
in = aux->samp + aux->curbyte;
|
||||
insize = aux->nbytes - aux->curbyte;
|
||||
|
||||
/* 2, decode or passthrough. */
|
||||
|
||||
ret = priv->ops->process(priv->codec, in, insize, &out, &outsize);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* 3, if return -ENODATA, means there is no enough data in aux apb.
|
||||
* memmove the remaining data to aux->samp.
|
||||
* */
|
||||
|
||||
if (ret == -ENODATA)
|
||||
{
|
||||
memmove(aux->samp, in, insize);
|
||||
aux->curbyte = 0;
|
||||
aux->nbytes = insize;
|
||||
*dequeue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 4, if other error, increase apb->curbyte and try again. */
|
||||
|
||||
aux->curbyte++;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 5, decode success, process remain data. write to alsa. */
|
||||
|
||||
aux->curbyte += ret;
|
||||
|
||||
ret = snd_pcm_writei(priv->pcm, out, outsize / priv->frame_size);
|
||||
ret *= priv->frame_size;
|
||||
}
|
||||
|
||||
/* 6, whether send DEQUEUE msg to apps. */
|
||||
|
||||
if (aux->curbyte == aux->nbytes)
|
||||
{
|
||||
aux->curbyte = 0;
|
||||
aux->nbytes = 0;
|
||||
*dequeue = true;
|
||||
}
|
||||
|
||||
/* 7, return actual bytes which write to alsa driver. */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sim_audio_process(struct sim_audio_s *priv)
|
||||
{
|
||||
struct ap_buffer_s *apb;
|
||||
snd_pcm_sframes_t expect;
|
||||
struct ap_buffer_s *apb;
|
||||
snd_pcm_sframes_t avail;
|
||||
uint8_t *out = NULL;
|
||||
bool dequeue = false;
|
||||
uint32_t outsize;
|
||||
int ret = 0;
|
||||
|
||||
@ -705,15 +720,7 @@ static void sim_audio_process(struct sim_audio_s *priv)
|
||||
|
||||
if (priv->playback)
|
||||
{
|
||||
ret = priv->ops->process(priv->codec, apb->samp, apb->nbytes,
|
||||
&out, &outsize);
|
||||
if (ret < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ret = snd_pcm_writei(priv->pcm, out, outsize / priv->frame_size);
|
||||
ret *= priv->frame_size;
|
||||
ret = sim_audio_process_playback(priv, apb, &dequeue);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -730,16 +737,17 @@ static void sim_audio_process(struct sim_audio_s *priv)
|
||||
return;
|
||||
}
|
||||
|
||||
ret = outsize;
|
||||
apb->curbyte += ret;
|
||||
dequeue = true;
|
||||
}
|
||||
|
||||
if (ret >= 0)
|
||||
if (dequeue)
|
||||
{
|
||||
bool final = false;
|
||||
|
||||
dq_remfirst(&priv->pendq);
|
||||
|
||||
apb->nbytes = ret;
|
||||
apb->nbytes = apb->curbyte;
|
||||
if (apb->flags & AUDIO_APB_FINAL)
|
||||
{
|
||||
final = true;
|
||||
@ -853,147 +861,6 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_audio_mp3_scale(mad_fixed_t sample)
|
||||
{
|
||||
sample += 1L << (MAD_F_FRACBITS - 16);
|
||||
|
||||
if (sample >= MAD_F_ONE)
|
||||
{
|
||||
sample = MAD_F_ONE - 1;
|
||||
}
|
||||
else if (sample < -MAD_F_ONE)
|
||||
{
|
||||
sample = -MAD_F_ONE;
|
||||
}
|
||||
|
||||
return sample >> (MAD_F_FRACBITS + 1 - 16);
|
||||
}
|
||||
|
||||
static void *sim_audio_mp3_init(void)
|
||||
{
|
||||
struct sim_decoder_mp3_s *codec;
|
||||
|
||||
codec = kmm_malloc(sizeof(struct sim_decoder_mp3_s));
|
||||
if (codec == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mad_stream_init(&codec->stream);
|
||||
mad_frame_init(&codec->frame);
|
||||
mad_synth_init(&codec->synth);
|
||||
|
||||
codec->out = kmm_malloc(sizeof(codec->synth.pcm.samples));
|
||||
if (codec->out == NULL)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
return codec;
|
||||
|
||||
out:
|
||||
mad_synth_finish(&(codec->synth));
|
||||
mad_frame_finish(&(codec->frame));
|
||||
mad_stream_finish(&(codec->stream));
|
||||
kmm_free(codec);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int sim_audio_mp3_samples(void *handle)
|
||||
{
|
||||
struct sim_decoder_mp3_s *codec = (struct sim_decoder_mp3_s *)handle;
|
||||
|
||||
return sizeof(codec->synth.pcm.samples[0]) / sizeof(mad_fixed_t);
|
||||
}
|
||||
|
||||
static int sim_audio_mp3_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;
|
||||
const mad_fixed_t *right_ch;
|
||||
const mad_fixed_t *left_ch;
|
||||
int nchannels;
|
||||
int nsamples;
|
||||
uint8_t *ptr;
|
||||
int i = 0;
|
||||
int ret;
|
||||
|
||||
mad_stream_buffer(&codec->stream, in, insize);
|
||||
ret = mad_frame_decode(&codec->frame, &codec->stream);
|
||||
if (ret < 0)
|
||||
{
|
||||
aerr("%s mp3 decode failed error %d\n", __func__, codec->stream.error);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mad_synth_frame(&codec->synth, &codec->frame);
|
||||
|
||||
nchannels = codec->synth.pcm.channels;
|
||||
nsamples = codec->synth.pcm.length;
|
||||
left_ch = codec->synth.pcm.samples[0];
|
||||
right_ch = codec->synth.pcm.samples[1];
|
||||
|
||||
ptr = codec->out;
|
||||
while (nsamples--)
|
||||
{
|
||||
int sample;
|
||||
|
||||
/* output sample(s) in 16-bit signed little-endian PCM */
|
||||
|
||||
sample = sim_audio_mp3_scale(*left_ch++);
|
||||
ptr[i] = (sample >> 0) & 0xff;
|
||||
ptr[i + 1] = (sample >> 8) & 0xff;
|
||||
|
||||
if (nchannels == 2)
|
||||
{
|
||||
sample = sim_audio_mp3_scale(*right_ch++);
|
||||
ptr[i + 2] = (sample >> 0) & 0xff;
|
||||
ptr[i + 3] = (sample >> 8) & 0xff;
|
||||
}
|
||||
|
||||
i += sizeof(short) * nchannels;
|
||||
}
|
||||
|
||||
*out = ptr;
|
||||
*outsize = codec->synth.pcm.length * nchannels * sizeof(short);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sim_audio_mp3_uninit(void *handle)
|
||||
{
|
||||
struct sim_decoder_mp3_s *codec = (struct sim_decoder_mp3_s *)handle;
|
||||
|
||||
mad_synth_finish(&(codec->synth));
|
||||
mad_frame_finish(&(codec->frame));
|
||||
mad_stream_finish(&(codec->stream));
|
||||
|
||||
kmm_free(codec->out);
|
||||
kmm_free(codec);
|
||||
}
|
||||
|
||||
static void *sim_audio_pcm_init(void)
|
||||
{
|
||||
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 0;
|
||||
}
|
||||
|
||||
static void sim_audio_pcm_uninit(void *handle)
|
||||
{
|
||||
kmm_free(handle);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
410
arch/sim/src/sim/posix/sim_offload.c
Normal file
410
arch/sim/src/sim/posix/sim_offload.c
Normal file
@ -0,0 +1,410 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/sim/posix/sim_offload.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <mad.h>
|
||||
|
||||
#include "sim_offload.h"
|
||||
|
||||
/****************************************************************************
|
||||
* 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);
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
const struct sim_codec_ops_s g_codec_ops[] =
|
||||
{
|
||||
{
|
||||
AUDIO_FMT_PCM,
|
||||
AUDCODEC_DEC | AUDCODEC_ENC,
|
||||
sim_audio_pcm_init,
|
||||
NULL,
|
||||
sim_audio_pcm_process,
|
||||
sim_audio_pcm_uninit,
|
||||
},
|
||||
{
|
||||
AUDIO_FMT_MP3,
|
||||
AUDCODEC_DEC,
|
||||
sim_audio_mp3_init,
|
||||
sim_audio_mp3_samples,
|
||||
sim_audio_mp3_decode,
|
||||
sim_audio_mp3_uninit
|
||||
},
|
||||
{
|
||||
AUDIO_FMT_UNDEF,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
},
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct sim_decoder_mp3_s
|
||||
{
|
||||
uint8_t *out;
|
||||
struct mad_stream stream;
|
||||
struct mad_frame frame;
|
||||
struct mad_synth synth;
|
||||
};
|
||||
|
||||
struct sim_codec_pcm_s
|
||||
{
|
||||
uint32_t frame_size;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const uint16_t g_mpa_freq_tab[3] =
|
||||
{
|
||||
44100, 48000, 32000
|
||||
};
|
||||
|
||||
static const uint16_t g_mpa_bitrate_tab[2][3][15] =
|
||||
{
|
||||
{
|
||||
{
|
||||
0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448
|
||||
},
|
||||
{
|
||||
0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384
|
||||
},
|
||||
{
|
||||
0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256
|
||||
},
|
||||
{
|
||||
0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160
|
||||
},
|
||||
{
|
||||
0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static int sim_audio_mp3_scale(mad_fixed_t sample)
|
||||
{
|
||||
sample += 1L << (MAD_F_FRACBITS - 16);
|
||||
|
||||
if (sample >= MAD_F_ONE)
|
||||
{
|
||||
sample = MAD_F_ONE - 1;
|
||||
}
|
||||
else if (sample < -MAD_F_ONE)
|
||||
{
|
||||
sample = -MAD_F_ONE;
|
||||
}
|
||||
|
||||
return sample >> (MAD_F_FRACBITS + 1 - 16);
|
||||
}
|
||||
|
||||
static int sim_audio_check_mpeg(uint32_t header)
|
||||
{
|
||||
/* header */
|
||||
|
||||
if ((header & 0xffe00000) != 0xffe00000)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* version check */
|
||||
|
||||
if ((header & (3 << 19)) == 1 << 19)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* layer check */
|
||||
|
||||
if ((header & (3 << 17)) == 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* bit rate */
|
||||
|
||||
if ((header & (0xf << 12)) == 0xf << 12)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* frequency */
|
||||
|
||||
if ((header & (3 << 10)) == 3 << 10)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_audio_mp3_check(uint32_t header)
|
||||
{
|
||||
int sample_rate;
|
||||
int frame_size;
|
||||
int padding;
|
||||
int mpeg25;
|
||||
int sr_idx;
|
||||
int br_idx;
|
||||
int layer;
|
||||
int lsf;
|
||||
int ret;
|
||||
|
||||
ret = sim_audio_check_mpeg(header);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (header & (1 << 20))
|
||||
{
|
||||
lsf = (header & (1 << 19)) ? 0 : 1;
|
||||
mpeg25 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lsf = 1;
|
||||
mpeg25 = 1;
|
||||
}
|
||||
|
||||
layer = 4 - ((header >> 17) & 3);
|
||||
br_idx = (header >> 12) & 0xf;
|
||||
sr_idx = (header >> 10) & 3;
|
||||
padding = (header >> 9) & 1;
|
||||
|
||||
if (sr_idx >= sizeof(g_mpa_freq_tab) / sizeof(g_mpa_freq_tab[0]) ||
|
||||
br_idx >= 0xf)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sample_rate = g_mpa_freq_tab[sr_idx] >> (lsf + mpeg25);
|
||||
|
||||
if (br_idx != 0)
|
||||
{
|
||||
frame_size = g_mpa_bitrate_tab[lsf][layer - 1][br_idx];
|
||||
|
||||
switch (layer)
|
||||
{
|
||||
case 1:
|
||||
frame_size = (frame_size * 12000) / sample_rate;
|
||||
frame_size = (frame_size + padding) * 4;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
frame_size = (frame_size * 144000) / sample_rate;
|
||||
frame_size += padding;
|
||||
break;
|
||||
|
||||
default:
|
||||
case 3:
|
||||
frame_size = (frame_size * 144000) / (sample_rate << lsf);
|
||||
frame_size += padding;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if no frame size computed, signal it */
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return frame_size;
|
||||
}
|
||||
|
||||
static void *sim_audio_mp3_init(struct audio_info_s *info)
|
||||
{
|
||||
struct sim_decoder_mp3_s *codec;
|
||||
|
||||
codec = kmm_malloc(sizeof(struct sim_decoder_mp3_s));
|
||||
if (codec == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mad_stream_init(&codec->stream);
|
||||
mad_frame_init(&codec->frame);
|
||||
mad_synth_init(&codec->synth);
|
||||
|
||||
codec->out = kmm_malloc(sizeof(codec->synth.pcm.samples));
|
||||
if (codec->out == NULL)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
return codec;
|
||||
|
||||
out:
|
||||
mad_synth_finish(&(codec->synth));
|
||||
mad_frame_finish(&(codec->frame));
|
||||
mad_stream_finish(&(codec->stream));
|
||||
kmm_free(codec);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int sim_audio_mp3_samples(void *handle)
|
||||
{
|
||||
struct sim_decoder_mp3_s *codec = (struct sim_decoder_mp3_s *)handle;
|
||||
|
||||
return sizeof(codec->synth.pcm.samples[0]) / sizeof(mad_fixed_t);
|
||||
}
|
||||
|
||||
static int sim_audio_mp3_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;
|
||||
const mad_fixed_t *right_ch;
|
||||
const mad_fixed_t *left_ch;
|
||||
int mpa_header;
|
||||
int nchannels;
|
||||
int nsamples;
|
||||
uint8_t *ptr;
|
||||
int i = 0;
|
||||
int size;
|
||||
int ret;
|
||||
|
||||
if (insize < 4)
|
||||
{
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
mpa_header = in[0] << 24 | in[1] << 16 | in[2] << 8 | in[3];
|
||||
size = sim_audio_mp3_check(mpa_header);
|
||||
if (size < 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (insize < size + 8)
|
||||
{
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
mad_stream_buffer(&codec->stream, in, insize);
|
||||
ret = mad_frame_decode(&codec->frame, &codec->stream);
|
||||
if (ret < 0)
|
||||
{
|
||||
aerr("%s mp3 decode failed error %d\n", __func__, codec->stream.error);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mad_synth_frame(&codec->synth, &codec->frame);
|
||||
|
||||
nchannels = codec->synth.pcm.channels;
|
||||
nsamples = codec->synth.pcm.length;
|
||||
left_ch = codec->synth.pcm.samples[0];
|
||||
right_ch = codec->synth.pcm.samples[1];
|
||||
|
||||
ptr = codec->out;
|
||||
while (nsamples--)
|
||||
{
|
||||
int sample;
|
||||
|
||||
/* output sample(s) in 16-bit signed little-endian PCM */
|
||||
|
||||
sample = sim_audio_mp3_scale(*left_ch++);
|
||||
ptr[i] = (sample >> 0) & 0xff;
|
||||
ptr[i + 1] = (sample >> 8) & 0xff;
|
||||
|
||||
if (nchannels == 2)
|
||||
{
|
||||
sample = sim_audio_mp3_scale(*right_ch++);
|
||||
ptr[i + 2] = (sample >> 0) & 0xff;
|
||||
ptr[i + 3] = (sample >> 8) & 0xff;
|
||||
}
|
||||
|
||||
i += sizeof(short) * nchannels;
|
||||
}
|
||||
|
||||
*out = ptr;
|
||||
*outsize = codec->synth.pcm.length * sizeof(short) * nchannels;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void sim_audio_mp3_uninit(void *handle)
|
||||
{
|
||||
struct sim_decoder_mp3_s *codec = (struct sim_decoder_mp3_s *)handle;
|
||||
|
||||
mad_synth_finish(&(codec->synth));
|
||||
mad_frame_finish(&(codec->frame));
|
||||
mad_stream_finish(&(codec->stream));
|
||||
|
||||
kmm_free(codec->out);
|
||||
kmm_free(codec);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
77
arch/sim/src/sim/posix/sim_offload.h
Normal file
77
arch/sim/src/sim/posix/sim_offload.h
Normal file
@ -0,0 +1,77 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/sim/posix/sim_offload.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_SIM_SRC_POSIX_SIM_OFFLOAD_H
|
||||
#define __ARCH_SIM_SRC_POSIX_SIM_OFFLOAD_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/audio/audio.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define AUDCODEC_DEC 0x01
|
||||
#define AUDCODEC_ENC 0x10
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct sim_codec_ops_s
|
||||
{
|
||||
uint8_t format;
|
||||
uint8_t flags;
|
||||
|
||||
/* init codec handle */
|
||||
|
||||
void *(*init)(struct audio_info_s *info);
|
||||
|
||||
/* return how much samples return from deocde.
|
||||
* or encoder needed.
|
||||
* */
|
||||
|
||||
int (*get_samples)(void *handle);
|
||||
|
||||
/* perform dec or enc on [in] data with [insize] bytes.
|
||||
* [out] is pcm data with [outsize] when decode,
|
||||
* [out] is compress data with [outsize] when encode.
|
||||
* return: < 0 means failed. >= 0 means size of source data consumed.
|
||||
*/
|
||||
|
||||
int (*process)(void *handle, uint8_t *in, uint32_t insize,
|
||||
uint8_t **out, unsigned int *outsize);
|
||||
|
||||
/* uninit codec handle */
|
||||
|
||||
void (*uninit)(void *handle);
|
||||
} sim_codec_ops_s;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
extern const sim_codec_ops_s g_codec_ops[];
|
||||
|
||||
#endif /* __ARCH_SIM_SRC_POSIX_SIM_OFFLOAD_H */
|
Loading…
Reference in New Issue
Block a user