513 lines
14 KiB
C
513 lines
14 KiB
C
#include "asm/includes.h"
|
|
#include "media/includes.h"
|
|
#include "system/includes.h"
|
|
#include "asm/audio_src.h"
|
|
#include "audio_enc.h"
|
|
#include "audio_dec.h"
|
|
#include "audio_dongle_codec.h"
|
|
#include "app_main.h"
|
|
#include "clock_cfg.h"
|
|
#include "media/pcm_decoder.h"
|
|
|
|
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_DONGLE)
|
|
|
|
#define DONGLE_USE_PCM_DEC 1 //使用单独的pcm解码做节拍
|
|
|
|
#define DONGLE_FILL_ZERO_MS 800 //填0
|
|
|
|
struct dongle_codec_hdl {
|
|
struct audio_encoder encoder;
|
|
s16 output_frame[1152 / 2]; //align 4Bytes
|
|
int pcm_frame[64]; //align 4Bytes
|
|
u8 pcm_buf[1 * 1024];
|
|
/* u8 pcm_buf[8 * 1024]; */
|
|
cbuffer_t pcm_cbuf;
|
|
u32 start : 1;
|
|
void *cb_priv;
|
|
int (*out_cb)(void *priv, void *buf, int len);
|
|
|
|
#if DONGLE_FILL_ZERO_MS
|
|
u32 zero_fill_total;
|
|
u32 zero_fill_len;
|
|
#endif
|
|
|
|
#if DONGLE_USE_PCM_DEC
|
|
struct audio_mixer_ch mix_ch;
|
|
struct audio_res_wait wait;
|
|
struct pcm_decoder pcm_dec; // pcm解码句柄
|
|
struct audio_stream *audio_stream; // 音频流
|
|
#endif
|
|
};
|
|
|
|
static struct dongle_codec_hdl *p_dongle = NULL;
|
|
struct dongle_emitter_hdl dongle_emitter = {0};
|
|
|
|
#ifdef CONFIG_MIXER_CYCLIC
|
|
static s16 dongle_mix_buff[128 * 2 * 2];
|
|
#else
|
|
static s16 dongle_mix_buff[8];
|
|
#endif
|
|
|
|
extern struct audio_encoder_task *encode_task;
|
|
|
|
|
|
#if DONGLE_USE_PCM_DEC
|
|
|
|
static int pcm_fread(void *hdl, void *buf, int len)
|
|
{
|
|
len = len / 2;
|
|
memset(buf, 0, len);
|
|
/* putchar('A'); */
|
|
return len;
|
|
}
|
|
static int pcm_dec_data_handler(struct audio_stream_entry *entry,
|
|
struct audio_data_frame *in,
|
|
struct audio_data_frame *out)
|
|
{
|
|
struct audio_decoder *decoder = container_of(entry, struct audio_decoder, entry);
|
|
struct pcm_decoder *pcm_dec = container_of(decoder, struct pcm_decoder, decoder);
|
|
struct dongle_codec_hdl *dec = container_of(pcm_dec, struct dongle_codec_hdl, pcm_dec);
|
|
audio_stream_run(&decoder->entry, in);
|
|
/* audio_mixer_ch_pause(&dec->mix_ch, 0); */
|
|
return decoder->process_len;
|
|
}
|
|
static void pcm_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
|
|
{
|
|
}
|
|
static void dec_out_stream_resume(void *p)
|
|
{
|
|
struct dongle_codec_hdl *dec = (struct dongle_codec_hdl *)p;
|
|
|
|
audio_decoder_resume(&dec->pcm_dec.decoder);
|
|
}
|
|
static int pcm_dec_start(struct dongle_codec_hdl *stream)
|
|
{
|
|
int err = 0;
|
|
if (stream == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
err = pcm_decoder_open(&stream->pcm_dec, &decode_task);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
pcm_decoder_set_event_handler(&stream->pcm_dec, pcm_dec_event_handler, 0);
|
|
pcm_decoder_set_read_data(&stream->pcm_dec, pcm_fread, stream);
|
|
pcm_decoder_set_data_handler(&stream->pcm_dec, pcm_dec_data_handler);
|
|
|
|
audio_mixer_ch_open(&stream->mix_ch, &mixer);
|
|
/* audio_mixer_ch_open_head(&stream->mix_ch, &mixer); // 挂载到mixer最前面 */
|
|
audio_mixer_ch_set_src(&stream->mix_ch, 0, 0);
|
|
/* audio_mixer_ch_set_src(&stream->mix_ch, 1, 1); */
|
|
/* audio_mixer_ch_set_no_wait(&stream->mix_ch, 1, 5); // 超时自动丢数 */
|
|
/* audio_mixer_ch_pause(&stream->mix_ch, 1); */
|
|
// 数据流串联
|
|
struct audio_stream_entry *entries[8] = {NULL};
|
|
u8 entry_cnt = 0;
|
|
entries[entry_cnt++] = &stream->pcm_dec.decoder.entry;
|
|
entries[entry_cnt++] = &stream->mix_ch.entry;
|
|
stream->audio_stream = audio_stream_open(stream, dec_out_stream_resume);
|
|
audio_stream_add_list(stream->audio_stream, entries, entry_cnt);
|
|
|
|
audio_output_set_start_volume(APP_AUDIO_STATE_MUSIC);
|
|
err = audio_decoder_start(&stream->pcm_dec.decoder);
|
|
if (err == 0) {
|
|
printf("pcm_dec_start ok\n");
|
|
}
|
|
return err;
|
|
}
|
|
static void pcm_dec_stop(struct dongle_codec_hdl *stream)
|
|
{
|
|
printf("mic stream dec stop \n\n");
|
|
if (stream) {
|
|
/* audio_decoder_close(&stream->decoder); */
|
|
/* audio_mixer_ch_close(&stream->mix_ch); */
|
|
pcm_decoder_close(&stream->pcm_dec);
|
|
audio_mixer_ch_close(&stream->mix_ch);
|
|
if (stream->audio_stream) {
|
|
audio_stream_close(stream->audio_stream);
|
|
stream->audio_stream = NULL;
|
|
}
|
|
/* audio_decoder_task_del_wait(&decode_task, &stream->wait); */
|
|
}
|
|
}
|
|
|
|
static int pcmdec_wait_res_handler(struct audio_res_wait *wait, int event)
|
|
{
|
|
int err = 0;
|
|
struct dongle_codec_hdl *stream = container_of(wait, struct dongle_codec_hdl, wait);
|
|
if (event == AUDIO_RES_GET) {
|
|
err = pcm_dec_start(stream);
|
|
} else if (event == AUDIO_RES_PUT) {
|
|
/* pcm_dec_stop(stream); */
|
|
}
|
|
|
|
return err;
|
|
}
|
|
static int pcm_dec_open(struct dongle_codec_hdl *stream, struct audio_fmt *pfmt)
|
|
{
|
|
stream->pcm_dec.output_ch_num = stream->pcm_dec.ch_num = pfmt->channel;
|
|
stream->pcm_dec.sample_rate = pfmt->sample_rate;
|
|
if (stream->pcm_dec.output_ch_num == 2) {
|
|
stream->pcm_dec.output_ch_type = AUDIO_CH_LR;
|
|
} else {
|
|
stream->pcm_dec.output_ch_type = AUDIO_CH_DIFF;
|
|
}
|
|
|
|
stream->wait.priority = 0;
|
|
stream->wait.preemption = 0;
|
|
stream->wait.protect = 1;
|
|
stream->wait.handler = pcmdec_wait_res_handler;
|
|
return audio_decoder_task_add_wait(&decode_task, &stream->wait);
|
|
}
|
|
|
|
static void pcm_dec_close(struct dongle_codec_hdl *stream)
|
|
{
|
|
pcm_dec_stop(stream);
|
|
audio_decoder_task_del_wait(&decode_task, &stream->wait);
|
|
}
|
|
|
|
#endif /*DONGLE_USE_PCM_DEC*/
|
|
|
|
static int dongle_enc_pcm_get(struct audio_encoder *encoder, s16 **frame, u16 frame_len)
|
|
{
|
|
int rlen = 0;
|
|
int dlen = 0;
|
|
struct dongle_codec_hdl *enc = container_of(encoder, struct dongle_codec_hdl, encoder);
|
|
|
|
/* printf("l:%d", frame_len); */
|
|
|
|
if (!enc->start) {
|
|
return 0;
|
|
}
|
|
if (frame_len > sizeof(enc->pcm_frame)) {
|
|
frame_len = sizeof(enc->pcm_frame);
|
|
}
|
|
|
|
#if DONGLE_FILL_ZERO_MS
|
|
if (enc->zero_fill_len < enc->zero_fill_total) {
|
|
enc->zero_fill_len += frame_len;
|
|
memset(enc->pcm_frame, 0, frame_len);
|
|
*frame = (s16 *)enc->pcm_frame;
|
|
return frame_len;
|
|
}
|
|
#endif
|
|
|
|
dlen = cbuf_get_data_len(&enc->pcm_cbuf);
|
|
if (dlen < frame_len) {
|
|
/* putchar('T');*/
|
|
return 0;
|
|
}
|
|
|
|
rlen = cbuf_read(&enc->pcm_cbuf, enc->pcm_frame, frame_len);
|
|
audio_stream_resume(&dongle_emitter.entry);
|
|
|
|
*frame = (s16 *)enc->pcm_frame;
|
|
|
|
return rlen;
|
|
}
|
|
|
|
static void dongle_enc_pcm_put(struct audio_encoder *encoder, s16 *frame)
|
|
{
|
|
}
|
|
|
|
static const struct audio_enc_input dongle_enc_input = {
|
|
.fget = dongle_enc_pcm_get,
|
|
.fput = dongle_enc_pcm_put,
|
|
};
|
|
|
|
static int dongle_enc_probe_handler(struct audio_encoder *encoder)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int dongle_enc_output_handler(struct audio_encoder *encoder, u8 *frame, int len)
|
|
{
|
|
struct dongle_codec_hdl *enc = container_of(encoder, struct dongle_codec_hdl, encoder);
|
|
/* printf("output frame:%d \n", len); */
|
|
/* put_buf(frame, len); */
|
|
if (enc->out_cb) {
|
|
len = enc->out_cb(enc->cb_priv, frame, len);
|
|
}
|
|
return len;
|
|
}
|
|
|
|
const static struct audio_enc_handler dongle_enc_handler = {
|
|
.enc_probe = dongle_enc_probe_handler,
|
|
.enc_output = dongle_enc_output_handler,
|
|
};
|
|
|
|
static void dongle_enc_event_handler(struct audio_encoder *encoder, int argc, int *argv)
|
|
{
|
|
printf("dongle_enc_event_handler:0x%x,%d\n", argv[0], argv[0]);
|
|
switch (argv[0]) {
|
|
case AUDIO_ENC_EVENT_END:
|
|
puts("AUDIO_ENC_EVENT_END\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void audio_dongle_enc_close(void)
|
|
{
|
|
if (!p_dongle) {
|
|
return ;
|
|
}
|
|
p_dongle->start = 0;
|
|
|
|
audio_encoder_close(&p_dongle->encoder);
|
|
|
|
#if DONGLE_USE_PCM_DEC
|
|
pcm_dec_close(p_dongle);
|
|
#endif
|
|
|
|
local_irq_disable();
|
|
free(p_dongle);
|
|
p_dongle = NULL;
|
|
local_irq_enable();
|
|
|
|
audio_encoder_task_close();
|
|
|
|
clock_remove_set(DONGLE_ENC_CLK);
|
|
}
|
|
|
|
int audio_dongle_enc_open(struct audio_fmt *pfmt,
|
|
int (*out_cb)(void *priv, void *buf, int len),
|
|
void *cb_priv
|
|
)
|
|
{
|
|
struct audio_fmt fmt = {0};
|
|
|
|
audio_dongle_enc_close();
|
|
|
|
if (pfmt) {
|
|
memcpy(&fmt, pfmt, sizeof(struct audio_fmt));
|
|
} else {
|
|
fmt.coding_type = AUDIO_CODING_MP3;
|
|
/* fmt.coding_type = AUDIO_CODING_WAV; */
|
|
fmt.bit_rate = 128;
|
|
fmt.channel = audio_output_channel_num();
|
|
fmt.sample_rate = DONGLE_OUTPUT_SAMPLE_RATE;//audio_mixer_get_sample_rate(&mixer);
|
|
}
|
|
if (fmt.coding_type == AUDIO_CODING_MP3) {
|
|
if ((fmt.sample_rate < 16000) && (fmt.bit_rate > 64)) {
|
|
fmt.bit_rate = 64;
|
|
}
|
|
}
|
|
|
|
audio_encoder_task_open();
|
|
|
|
struct dongle_codec_hdl *p_enc = zalloc(sizeof(struct dongle_codec_hdl));
|
|
ASSERT(p_enc);
|
|
|
|
clock_add_set(DONGLE_ENC_CLK);
|
|
|
|
cbuf_init(&p_enc->pcm_cbuf, p_enc->pcm_buf, sizeof(p_enc->pcm_buf));
|
|
|
|
#if DONGLE_FILL_ZERO_MS
|
|
p_enc->zero_fill_total = fmt.channel * fmt.sample_rate * 2 * DONGLE_FILL_ZERO_MS / 1000;
|
|
p_enc->zero_fill_len = 0;
|
|
#endif
|
|
|
|
audio_encoder_open(&p_enc->encoder, &dongle_enc_input, encode_task);
|
|
audio_encoder_set_handler(&p_enc->encoder, &dongle_enc_handler);
|
|
audio_encoder_set_fmt(&p_enc->encoder, &fmt);
|
|
audio_encoder_set_event_handler(&p_enc->encoder, dongle_enc_event_handler, 0);
|
|
audio_encoder_set_output_buffs(&p_enc->encoder, p_enc->output_frame,
|
|
sizeof(p_enc->output_frame), 1);
|
|
p_enc->cb_priv = cb_priv;
|
|
p_enc->out_cb = out_cb;
|
|
p_enc->start = 1;
|
|
p_dongle = p_enc;
|
|
audio_encoder_start(&p_enc->encoder);
|
|
|
|
#if DONGLE_USE_PCM_DEC
|
|
pcm_dec_open(p_dongle, &fmt);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int audio_stream_dongle_emitter_data_handler(struct audio_stream_entry *entry,
|
|
struct audio_data_frame *in,
|
|
struct audio_data_frame *out)
|
|
{
|
|
if (in->data_len == 0) {
|
|
return 0;
|
|
}
|
|
int len = in->data_len;
|
|
|
|
local_irq_disable();
|
|
if (p_dongle && p_dongle->start) {
|
|
u32 wlen = cbuf_write(&p_dongle->pcm_cbuf, in->data, len);
|
|
if (wlen != len) {
|
|
log_w("wlen = %d, len = %d", wlen, len);
|
|
/* y_printf(">>>[test]:len = %d, wlen = %d\n", len, wlen); */
|
|
}
|
|
audio_encoder_resume(&p_dongle->encoder);
|
|
}
|
|
local_irq_enable();
|
|
|
|
return len;
|
|
}
|
|
|
|
void audio_dongle_emitter_init(void)
|
|
{
|
|
audio_mixer_open(&dongle_emitter.mixer);
|
|
/* audio_mixer_set_event_handler(&dongle_emitter.mixer, mixer_event_handler); */
|
|
/* audio_mixer_set_check_sr_handler(&dongle_emitter.mixer, audio_mixer_check_sr); */
|
|
/*初始化mix_buf的长度*/
|
|
audio_mixer_set_output_buf(&dongle_emitter.mixer, dongle_mix_buff, sizeof(dongle_mix_buff));
|
|
u8 ch_num = audio_output_channel_num();
|
|
audio_mixer_set_channel_num(&dongle_emitter.mixer, ch_num);
|
|
audio_mixer_set_sample_rate(&dongle_emitter.mixer, MIXER_SR_SPEC, DONGLE_OUTPUT_SAMPLE_RATE);
|
|
|
|
dongle_emitter.entry.data_handler = audio_stream_dongle_emitter_data_handler;
|
|
|
|
struct audio_stream_entry *entries[4] = {NULL};
|
|
u8 entry_cnt = 0;
|
|
entries[entry_cnt++] = &dongle_emitter.mixer.entry;
|
|
entries[entry_cnt++] = &dongle_emitter.entry;
|
|
|
|
dongle_emitter.mixer.stream = audio_stream_open(&dongle_emitter.mixer, audio_mixer_stream_resume);
|
|
audio_stream_add_list(dongle_emitter.mixer.stream, entries, entry_cnt);
|
|
|
|
audio_mixer_ch_open(&dongle_emitter.mix_ch, &dongle_emitter.mixer);
|
|
audio_mixer_ch_set_src(&dongle_emitter.mix_ch, 1, 0);
|
|
}
|
|
|
|
|
|
#if TCFG_VIR_UDISK_ENABLE
|
|
|
|
#include "virtual_mp3_file.h"
|
|
|
|
static void *dg_file = NULL;
|
|
static int dg_file_len = 0;
|
|
static int dg_out_cb(void *priv, void *buf, int len)
|
|
{
|
|
putchar('@');
|
|
|
|
virtual_mp3_file_write(buf, len);
|
|
/* if (dg_file) { */
|
|
/* fwrite(dg_file, buf, len); */
|
|
/* } */
|
|
dg_file_len += len;
|
|
return len;
|
|
}
|
|
|
|
void dongle_clear_enc_cbuf()
|
|
{
|
|
if (p_dongle) {
|
|
cbuf_clear(&p_dongle->pcm_cbuf);
|
|
/* memset(&p_dongle->pcm_buf, 0, 3 * 1024); */
|
|
/* memset(&p_dongle->output_frame, 0, 1152/2 ); */
|
|
/* memset(&p_dongle->pcm_frame, 0, 64); */
|
|
}
|
|
|
|
}
|
|
|
|
void dongle_enc_start_ex()
|
|
{
|
|
if (p_dongle) {
|
|
p_dongle->start = 1;
|
|
}
|
|
}
|
|
|
|
void dongle_enc_stop_ex()
|
|
{
|
|
if (p_dongle) {
|
|
p_dongle->start = 0;
|
|
}
|
|
}
|
|
|
|
void audio_dongle_reset()
|
|
{
|
|
audio_dongle_enc_open(NULL, dg_out_cb, NULL);
|
|
}
|
|
|
|
void dongle_enc_close()
|
|
{
|
|
if (p_dongle) {
|
|
y_printf("dongle close \n");
|
|
audio_dongle_enc_close();
|
|
printf("dg_file_len :%d ", dg_file_len);
|
|
}
|
|
}
|
|
|
|
void audio_usbdongle_ctrl(void)
|
|
{
|
|
|
|
if (p_dongle) {
|
|
y_printf("dongle close \n");
|
|
audio_dongle_enc_close();
|
|
printf("dg_file_len :%d ", dg_file_len);
|
|
} else {
|
|
y_printf("dongle open \n");
|
|
dg_file_len = 0;
|
|
audio_dongle_enc_open(NULL, dg_out_cb, NULL);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
static int dg_out_cb_test(void *priv, void *buf, int len)
|
|
{
|
|
putchar('@');
|
|
|
|
/* virtual_mp3_file_write(buf, len); */
|
|
if (dg_file) {
|
|
fwrite(dg_file, buf, len);
|
|
}
|
|
dg_file_len += len;
|
|
return len;
|
|
}
|
|
|
|
void audio_dongle_test(void)
|
|
{
|
|
#if 0
|
|
printf("%s,%d \n", __func__, __LINE__);
|
|
dg_file = fopen("storage/sd0/C/DONGLE/AC690000.MP3", "w+");
|
|
printf("%s,%d \n", __func__, __LINE__);
|
|
if (dg_file) {
|
|
u8 buf[128];
|
|
for (int i = 0; i < sizeof(buf); i++) {
|
|
buf[i] = i;
|
|
}
|
|
printf("%s,%d \n", __func__, __LINE__);
|
|
fwrite(dg_file, buf, sizeof(buf));
|
|
printf("%s,%d \n", __func__, __LINE__);
|
|
fclose(dg_file);
|
|
dg_file = NULL;
|
|
printf("%s,%d \n", __func__, __LINE__);
|
|
}
|
|
printf("%s,%d \n", __func__, __LINE__);
|
|
#endif
|
|
|
|
if (p_dongle) {
|
|
y_printf("dongle close \n");
|
|
audio_dongle_enc_close();
|
|
if (dg_file) {
|
|
fclose(dg_file);
|
|
dg_file = NULL;
|
|
}
|
|
printf("dg_file_len :%d ", dg_file_len);
|
|
} else {
|
|
y_printf("dongle open \n");
|
|
if (dg_file) {
|
|
fclose(dg_file);
|
|
dg_file = NULL;
|
|
}
|
|
dg_file_len = 0;
|
|
#if 0
|
|
dg_file = fopen("storage/sd0/C/DONGLE/AC690000.MP3", "w+");
|
|
#else
|
|
u8 name[128] = "storage/sd0/C/DONGLE/AC69****.MP3";
|
|
dg_file = fopen(name, "w+");
|
|
#endif
|
|
printf("fopen:0x%x \n", dg_file);
|
|
audio_dongle_enc_open(NULL, dg_out_cb_test, NULL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#endif /* (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_DONGLE) */
|
|
|