649 lines
25 KiB
C
649 lines
25 KiB
C
|
#include <assert.h>
|
||
|
|
||
|
#include "audio_scene.h"
|
||
|
|
||
|
#include "FreeRTOS.h"
|
||
|
#include "task.h"
|
||
|
#include "semphr.h"
|
||
|
|
||
|
#include "co_list.h"
|
||
|
#include "codec.h"
|
||
|
#include "algorithm.h"
|
||
|
#include "dsp_mem.h"
|
||
|
#include "dram_mem.h"
|
||
|
|
||
|
/*
|
||
|
* How to implement a audio scene
|
||
|
* 1. define audio_scene_param_xxx_t, add it into audio_scene_t->param
|
||
|
* 2. define xxx_env_t, add it into audio_scene_env_t->env
|
||
|
* 3. implement audio scene task xxx_task and xxx_init
|
||
|
* 4. add corresponding statement in function audio_scene_create
|
||
|
* 5. implement destroy_xxx
|
||
|
* 6. add corresponding statement in function destroy_task
|
||
|
*/
|
||
|
|
||
|
#define A2DP_SOURCE_SINGLE_FRAME_DUR 10 // unit: ms
|
||
|
|
||
|
#define AUDIO_ALGO_ADC_IN_BUFFER_FRAME_COUNT 8 // unit: algo_frame_size
|
||
|
|
||
|
#define DECODER_DATA_READY_THD 6
|
||
|
|
||
|
audio_scene_env_t audio_scene_env = {0};
|
||
|
static SemaphoreHandle_t wait_for_delete;
|
||
|
|
||
|
static void send_event(audio_scene_evt_t *evt)
|
||
|
{
|
||
|
if (evt == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GLOBAL_INT_DISABLE();
|
||
|
co_list_push_back(&audio_scene_env.evt_list, &evt->hdr);
|
||
|
GLOBAL_INT_RESTORE();
|
||
|
|
||
|
if(xPortIsInsideInterrupt()) {
|
||
|
vTaskNotifyGiveFromISR(audio_scene_env.audio_task_handle, NULL);
|
||
|
}
|
||
|
else {
|
||
|
xTaskNotifyGive(audio_scene_env.audio_task_handle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* this function may be called from interrupt, just send message to audio_scene_task */
|
||
|
static void decoder_request_raw_data_cb(audio_decoder_t *decoder)
|
||
|
{
|
||
|
audio_scene_evt_t *evt = (void *)pvPortMalloc(sizeof(audio_scene_evt_t));
|
||
|
|
||
|
if (evt) {
|
||
|
evt->type = AUDIO_SCENE_EVT_TYPE_REQ_RAW_DATA;
|
||
|
evt->p.decoder = decoder;
|
||
|
send_event(evt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void hw_request_a2dp_sink_pcm_cb(void *pcm, uint32_t samples, uint8_t channels)
|
||
|
{
|
||
|
uint32_t avaliable_data;
|
||
|
/* request PCM data from audio decoder */
|
||
|
avaliable_data = audio_decoder_get_pcm(audio_scene_env.env.a2dp_sink.decoder_to_hw, pcm, samples, channels);
|
||
|
}
|
||
|
|
||
|
static void hw_request_sco_pcm_cb(void *pcm, uint32_t samples, uint8_t channels)
|
||
|
{
|
||
|
/* request PCM data by speaker, these data are output of Audio algorithm */
|
||
|
audio_decoder_get_pcm(audio_scene_env.env.sco.decoder_to_hw, pcm, samples, channels);
|
||
|
}
|
||
|
|
||
|
static void hw_receive_adc_pcm_cb(uint32_t samples)
|
||
|
{
|
||
|
audio_scene_evt_t *evt = (void *)pvPortMalloc(sizeof(audio_scene_evt_t));
|
||
|
|
||
|
if (evt) {
|
||
|
evt->type = AUDIO_SCENE_EVT_TYPE_ADC_NEW_SAMPLES;
|
||
|
evt->p.adc_new_samples = samples;
|
||
|
send_event(evt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void init_a2dp_sink(void)
|
||
|
{
|
||
|
audio_scene_param_a2dp_sink_t *param;
|
||
|
|
||
|
/* initialize audio decoder module */
|
||
|
param = &audio_scene_env.scene->param.a2dp_sink;
|
||
|
audio_decoder_init(param->channels, param->sample_rate);
|
||
|
|
||
|
/* create and start a decoder */
|
||
|
audio_scene_env.env.a2dp_sink.decoder = audio_decoder_add(param->audio_type, decoder_request_raw_data_cb);
|
||
|
assert(audio_scene_env.env.a2dp_sink.decoder != NULL);
|
||
|
audio_decoder_start(audio_scene_env.env.a2dp_sink.decoder);
|
||
|
|
||
|
/* add an output to initialized audio decoder module */
|
||
|
audio_scene_env.env.a2dp_sink.decoder_to_hw = audio_decoder_output_add(true, AUDIO_CHANNELS_STEREO);
|
||
|
|
||
|
/* initialize audio hardware */
|
||
|
audio_scene_env.env.a2dp_sink.audio_hw = audio_hw_create(param->hw_type,
|
||
|
hw_request_a2dp_sink_pcm_cb,
|
||
|
param->hw_base_addr,
|
||
|
AUDIO_HW_DIR_OUT,
|
||
|
param->sample_rate,
|
||
|
param->channels);
|
||
|
|
||
|
co_list_init(&audio_scene_env.env.a2dp_sink.a2dp_data_list);
|
||
|
audio_scene_env.env.a2dp_sink.a2dp_data_counter = 0;
|
||
|
audio_scene_env.env.a2dp_sink.start_thd = DECODER_DATA_READY_THD;
|
||
|
}
|
||
|
|
||
|
static void init_sco(void)
|
||
|
{
|
||
|
audio_scene_param_sco_t *param;
|
||
|
sco_env_t *env;
|
||
|
|
||
|
env = &audio_scene_env.env.sco;
|
||
|
param = &audio_scene_env.scene->param.sco;
|
||
|
|
||
|
/* create audio algorithm instance */
|
||
|
/*
|
||
|
enum
|
||
|
{
|
||
|
kAgcModeUnchanged,
|
||
|
kAgcModeAdaptiveAnalog,
|
||
|
kAgcModeAdaptiveDigital,
|
||
|
kAgcModeFixedDigital
|
||
|
};
|
||
|
*/
|
||
|
env->audio_algo_handle = algorithm_init(/*AUDIO_ALGO_SEL_AGC | AUDIO_ALGO_SEL_NS | */AUDIO_ALGO_SEL_AEC,
|
||
|
param->sample_rate,
|
||
|
3, 3,
|
||
|
&env->algo_frame_size);
|
||
|
|
||
|
/* request buffers */
|
||
|
env->decoder_output = dsp_mem_alloc(env->algo_frame_size * sizeof(int16_t));
|
||
|
env->decoder_output_wr_ptr = 0;
|
||
|
env->adc_input = dsp_mem_alloc(env->algo_frame_size * sizeof(int16_t) * AUDIO_ALGO_ADC_IN_BUFFER_FRAME_COUNT);
|
||
|
env->adc_input_size = env->algo_frame_size * AUDIO_ALGO_ADC_IN_BUFFER_FRAME_COUNT;
|
||
|
env->adc_input_wr_ptr = 0;
|
||
|
env->adc_input_rd_ptr = 0;
|
||
|
|
||
|
/* initialize audio decoder module */
|
||
|
audio_decoder_init(AUDIO_CHANNELS_MONO, param->sample_rate);
|
||
|
|
||
|
/* create and start a decoder */
|
||
|
env->decoder = audio_decoder_add(param->audio_type, decoder_request_raw_data_cb);
|
||
|
audio_decoder_start(env->decoder);
|
||
|
|
||
|
/* add an output to initialized audio decoder module */
|
||
|
env->decoder_to_algo = audio_decoder_output_add(false, AUDIO_CHANNELS_MONO);
|
||
|
/* add an output to initialized audio decoder module */
|
||
|
env->decoder_to_hw = audio_decoder_output_add(true, AUDIO_CHANNELS_MONO);
|
||
|
|
||
|
/* create encoder */
|
||
|
struct msbc_encoder_param _param;
|
||
|
_param.i_bitrate = 128000;
|
||
|
_param.i_samp_freq = 16000;
|
||
|
if (param->audio_type == AUDIO_TYPE_MSBC) {
|
||
|
env->encoder = audio_encoder_init(param->audio_type, AUDIO_CHANNELS_MONO, param->sample_rate, 57, &_param);
|
||
|
}
|
||
|
else {
|
||
|
env->encoder = audio_encoder_init(param->audio_type, AUDIO_CHANNELS_MONO, param->sample_rate, 256, &_param);
|
||
|
}
|
||
|
|
||
|
/* initialize audio hardware */
|
||
|
env->audio_hw = audio_hw_create(param->hw_type,
|
||
|
hw_request_sco_pcm_cb,
|
||
|
param->hw_base_addr,
|
||
|
AUDIO_HW_DIR_INOUT,
|
||
|
param->sample_rate,
|
||
|
AUDIO_CHANNELS_STEREO);
|
||
|
env->audio_hw_output = audio_hw_output_add(env->audio_hw, hw_receive_adc_pcm_cb);
|
||
|
|
||
|
co_list_init(&env->sco_data_list);
|
||
|
env->sco_data_counter = 0;
|
||
|
env->start_thd = DECODER_DATA_READY_THD;
|
||
|
}
|
||
|
|
||
|
static void destroy_a2dp_sink(void)
|
||
|
{
|
||
|
if (audio_scene_env.scene
|
||
|
&& (audio_scene_env.scene->type == AUDIO_SCENE_TYPE_A2DP_SINK)) {
|
||
|
/* release audio hardware */
|
||
|
audio_hw_destroy(audio_scene_env.env.a2dp_sink.audio_hw);
|
||
|
|
||
|
/* release audio decoder module */
|
||
|
audio_decoder_destroy();
|
||
|
|
||
|
audio_data_element_t *elt = (void *)co_list_pop_front(&audio_scene_env.env.a2dp_sink.a2dp_data_list);
|
||
|
while (elt) {
|
||
|
dram_free(elt);
|
||
|
elt = (void *)co_list_pop_front(&audio_scene_env.env.a2dp_sink.a2dp_data_list);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void destroy_sco(void)
|
||
|
{
|
||
|
if (audio_scene_env.scene
|
||
|
&& (audio_scene_env.scene->type == AUDIO_SCENE_TYPE_SCO)) {
|
||
|
sco_env_t *env = &audio_scene_env.env.sco;
|
||
|
|
||
|
/* release audio hardware */
|
||
|
audio_hw_destroy(env->audio_hw);
|
||
|
|
||
|
/* release audio encoder */
|
||
|
audio_encoder_destroy(env->encoder);
|
||
|
|
||
|
/* release audio decoder module */
|
||
|
audio_decoder_destroy();
|
||
|
|
||
|
/* release audio algorithm instance */
|
||
|
algorithm_destroy(env->audio_algo_handle);
|
||
|
|
||
|
/* free allocated buffer */
|
||
|
dsp_mem_free(env->decoder_output);
|
||
|
dsp_mem_free(env->adc_input);
|
||
|
|
||
|
audio_data_element_t *elt = (void *)co_list_pop_front(&audio_scene_env.env.sco.sco_data_list);
|
||
|
while (elt) {
|
||
|
dram_free(elt);
|
||
|
elt = (void *)co_list_pop_front(&audio_scene_env.env.sco.sco_data_list);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void a2dp_sink_evt_handler(audio_scene_evt_t *evt)
|
||
|
{
|
||
|
audio_scene_t *scene = audio_scene_env.scene;
|
||
|
a2dp_sink_env_t *a2dp_sink_env = &audio_scene_env.env.a2dp_sink;
|
||
|
|
||
|
switch (evt->type) {
|
||
|
case AUDIO_SCENE_EVT_TYPE_REQ_RAW_DATA:
|
||
|
{
|
||
|
uint32_t length = 0;
|
||
|
if (evt->p.decoder == a2dp_sink_env->decoder) {
|
||
|
if (audio_decoder_decode(a2dp_sink_env->decoder,
|
||
|
NULL, &length) != AUDIO_RET_OUTPUT_ALMOTE_FULL) {
|
||
|
if (a2dp_sink_env->start_thd == 0) {
|
||
|
audio_data_element_t *elt;
|
||
|
int ret;
|
||
|
elt = (void *)co_list_pick(&a2dp_sink_env->a2dp_data_list);
|
||
|
while (elt) {
|
||
|
uint32_t length = elt->length - elt->offset;
|
||
|
ret = audio_decoder_decode(a2dp_sink_env->decoder, &elt->buffer[elt->offset], &length);
|
||
|
elt->offset += length;
|
||
|
if (elt->length == elt->offset) {
|
||
|
elt = (void *)co_list_pop_front(&a2dp_sink_env->a2dp_data_list);
|
||
|
a2dp_sink_env->a2dp_data_counter--;
|
||
|
dram_free(elt);
|
||
|
elt = (void *)co_list_pick(&a2dp_sink_env->a2dp_data_list);
|
||
|
}
|
||
|
if (ret == AUDIO_RET_OUTPUT_ALMOTE_FULL) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (evt->p.decoder == audio_scene_env.tone.decoder) {
|
||
|
// fputc('T', NULL);
|
||
|
if (audio_decoder_decode(audio_scene_env.tone.decoder,
|
||
|
NULL, &length) != AUDIO_RET_OUTPUT_ALMOTE_FULL) {
|
||
|
/* send request to app layer after checking PCM list */
|
||
|
void (*req_dec_cb)(audio_decoder_t *) = audio_scene_env.tone.req_dec_cb;
|
||
|
if (req_dec_cb) {
|
||
|
req_dec_cb(audio_scene_env.tone.decoder);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case AUDIO_SCENE_EVT_TYPE_RECV_RAW_DATA:
|
||
|
co_list_push_back(&audio_scene_env.env.a2dp_sink.a2dp_data_list, &evt->p.raw_data->hdr);
|
||
|
a2dp_sink_env->a2dp_data_counter++;
|
||
|
if (a2dp_sink_env->start_thd) {
|
||
|
a2dp_sink_env->start_thd--;
|
||
|
}
|
||
|
break;
|
||
|
case AUDIO_SCENE_EVT_TYPE_TONE_ADD:
|
||
|
audio_scene_env.tone.decoder = audio_decoder_add(evt->p.tone_add.type, decoder_request_raw_data_cb);
|
||
|
|
||
|
if (audio_scene_env.tone.decoder) {
|
||
|
audio_scene_env.tone.req_dec_cb = evt->p.tone_add.req_dec_cb;
|
||
|
audio_decoder_start(audio_scene_env.tone.decoder);
|
||
|
}
|
||
|
break;
|
||
|
case AUDIO_SCENE_EVT_TYPE_TONE_REMOVE:
|
||
|
if (audio_scene_env.tone.decoder == evt->p.decoder) {
|
||
|
audio_decoder_remove(audio_scene_env.tone.decoder);
|
||
|
audio_scene_env.tone.decoder = NULL;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
while(1);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void sco_evt_handler(audio_scene_evt_t *evt)
|
||
|
{
|
||
|
audio_scene_t *scene = audio_scene_env.scene;
|
||
|
sco_env_t *sco_env = &audio_scene_env.env.sco;
|
||
|
|
||
|
switch (evt->type) {
|
||
|
case AUDIO_SCENE_EVT_TYPE_REQ_RAW_DATA:
|
||
|
{
|
||
|
uint32_t length = 0;
|
||
|
if (evt->p.decoder == sco_env->decoder) {
|
||
|
if (audio_decoder_decode(sco_env->decoder,
|
||
|
NULL, &length) != AUDIO_RET_OUTPUT_ALMOTE_FULL) {
|
||
|
if (sco_env->start_thd == 0) {
|
||
|
audio_data_element_t *elt;
|
||
|
int ret;
|
||
|
elt = (void *)co_list_pick(&sco_env->sco_data_list);
|
||
|
while (elt) {
|
||
|
uint32_t length = elt->length - elt->offset;
|
||
|
if (elt->valid) {
|
||
|
uint32_t length = elt->length - elt->offset;
|
||
|
ret = audio_decoder_decode(sco_env->decoder, &elt->buffer[elt->offset], &length);
|
||
|
elt->offset += length;
|
||
|
}
|
||
|
else {
|
||
|
uint32_t length = AUDIO_SPECIAL_LENGTH_FOR_PLC;
|
||
|
ret = audio_decoder_decode(sco_env->decoder, NULL, &length);
|
||
|
elt->offset += length;
|
||
|
}
|
||
|
if (elt->length == elt->offset) {
|
||
|
elt = (void *)co_list_pop_front(&sco_env->sco_data_list);
|
||
|
sco_env->sco_data_counter--;
|
||
|
dram_free(elt);
|
||
|
elt = (void *)co_list_pick(&sco_env->sco_data_list);
|
||
|
}
|
||
|
if (ret == AUDIO_RET_OUTPUT_ALMOTE_FULL) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (evt->p.decoder == audio_scene_env.tone.decoder) {
|
||
|
if (audio_decoder_decode(audio_scene_env.tone.decoder,
|
||
|
NULL, &length) != AUDIO_RET_OUTPUT_ALMOTE_FULL) {
|
||
|
/* send request to app layer after checking PCM list */
|
||
|
void (*req_dec_cb)(audio_decoder_t *) = audio_scene_env.tone.req_dec_cb;
|
||
|
if (req_dec_cb) {
|
||
|
req_dec_cb(audio_scene_env.tone.decoder);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case AUDIO_SCENE_EVT_TYPE_RECV_RAW_DATA:
|
||
|
co_list_push_back(&audio_scene_env.env.sco.sco_data_list, &evt->p.raw_data->hdr);
|
||
|
sco_env->sco_data_counter++;
|
||
|
if (sco_env->start_thd) {
|
||
|
sco_env->start_thd--;
|
||
|
}
|
||
|
break;
|
||
|
case AUDIO_SCENE_EVT_TYPE_TONE_ADD:
|
||
|
audio_scene_env.tone.decoder = audio_decoder_add(evt->p.tone_add.type, decoder_request_raw_data_cb);
|
||
|
|
||
|
if (audio_scene_env.tone.decoder) {
|
||
|
audio_scene_env.tone.req_dec_cb = evt->p.tone_add.req_dec_cb;
|
||
|
audio_decoder_start(audio_scene_env.tone.decoder);
|
||
|
}
|
||
|
break;
|
||
|
case AUDIO_SCENE_EVT_TYPE_TONE_REMOVE:
|
||
|
if (audio_scene_env.tone.decoder == evt->p.decoder) {
|
||
|
audio_decoder_remove(audio_scene_env.tone.decoder);
|
||
|
audio_scene_env.tone.decoder = NULL;
|
||
|
}
|
||
|
break;
|
||
|
case AUDIO_SCENE_EVT_TYPE_ADC_NEW_SAMPLES:
|
||
|
{
|
||
|
uint32_t sco_in_length;
|
||
|
sco_env_t *sco = &audio_scene_env.env.sco;
|
||
|
uint32_t left_space;
|
||
|
uint32_t adc_samples = evt->p.adc_new_samples;
|
||
|
uint32_t available_samples;
|
||
|
|
||
|
/* save adc data into framebuffer */
|
||
|
left_space = sco->adc_input_size - sco->adc_input_wr_ptr;
|
||
|
if (left_space > adc_samples) {
|
||
|
audio_hw_read_pcm(sco->audio_hw_output, &sco->adc_input[sco->adc_input_wr_ptr], adc_samples, AUDIO_CHANNELS_MONO);
|
||
|
sco->adc_input_wr_ptr += adc_samples;
|
||
|
}
|
||
|
else {
|
||
|
audio_hw_read_pcm(sco->audio_hw_output, &sco->adc_input[sco->adc_input_wr_ptr], left_space, AUDIO_CHANNELS_MONO);
|
||
|
adc_samples -= left_space;
|
||
|
sco->adc_input_wr_ptr = 0;
|
||
|
if (adc_samples) {
|
||
|
audio_hw_read_pcm(sco->audio_hw_output, &sco->adc_input[0], adc_samples, AUDIO_CHANNELS_MONO);
|
||
|
sco->adc_input_wr_ptr = adc_samples;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* check whether received ADC data are enough for audio algorithm */
|
||
|
if (sco->adc_input_wr_ptr >= sco->adc_input_rd_ptr) {
|
||
|
available_samples = sco->adc_input_wr_ptr - sco->adc_input_rd_ptr;
|
||
|
}
|
||
|
else {
|
||
|
available_samples = sco->adc_input_size + sco->adc_input_wr_ptr - sco->adc_input_rd_ptr;
|
||
|
}
|
||
|
|
||
|
if (sco->decoder_output_wr_ptr < sco->algo_frame_size) {
|
||
|
/* request decoded PCM data (from ESCO IN), and send data to audio algorithim */
|
||
|
sco_in_length = audio_decoder_get_pcm(sco->decoder_to_algo,
|
||
|
&sco->decoder_output[sco->decoder_output_wr_ptr],
|
||
|
sco->algo_frame_size - sco->decoder_output_wr_ptr,
|
||
|
AUDIO_CHANNELS_MONO);
|
||
|
sco->decoder_output_wr_ptr += sco_in_length;
|
||
|
}
|
||
|
|
||
|
if (available_samples >= sco->algo_frame_size) {
|
||
|
// /* request decoded PCM data (from ESCO IN), and send data to audio algorithim */
|
||
|
// sco_in_length = audio_decoder_get_pcm(sco->decoder_to_algo,
|
||
|
// &sco->decoder_output[sco->decoder_output_wr_ptr],
|
||
|
// sco->algo_frame_size - sco->decoder_output_wr_ptr,
|
||
|
// AUDIO_CHANNELS_MONO);
|
||
|
// sco->decoder_output_wr_ptr += sco_in_length;
|
||
|
if (sco->decoder_output_wr_ptr >= sco->algo_frame_size) {
|
||
|
int16_t *output = NULL;
|
||
|
uint32_t encoded_frame;
|
||
|
uint32_t aec_out_samples = sco->algo_frame_size;
|
||
|
|
||
|
sco->decoder_output_wr_ptr = 0;
|
||
|
|
||
|
/* request start algorithim */
|
||
|
algorithm_launch(sco->audio_algo_handle,
|
||
|
&sco->decoder_output[0],
|
||
|
&sco->adc_input[sco->adc_input_rd_ptr],
|
||
|
&output);
|
||
|
sco->adc_input_rd_ptr += sco->algo_frame_size;
|
||
|
if (sco->adc_input_rd_ptr >= sco->adc_input_size) {
|
||
|
sco->adc_input_rd_ptr = 0;
|
||
|
}
|
||
|
|
||
|
/* use AEC output to do encoder, send encoded SCO frame to remote device */
|
||
|
audio_encoder_encode(sco->encoder,
|
||
|
(const uint8_t *)output,
|
||
|
sizeof(int16_t) * aec_out_samples,
|
||
|
AUDIO_CHANNELS_MONO,
|
||
|
audio_scene_env.scene->param.sco.sample_rate);
|
||
|
|
||
|
/* send encoded frame to peer device */
|
||
|
encoded_frame = audio_encoder_get_frame_count(sco->encoder);
|
||
|
while (encoded_frame--) {
|
||
|
audio_encoder_frame_t *frame;
|
||
|
frame = audio_encoder_frame_pop(sco->encoder);
|
||
|
if (audio_scene_env.scene->param.sco.report_enc_cb) {
|
||
|
audio_scene_env.scene->param.sco.report_enc_cb(audio_scene_env.scene->param.sco.report_enc_arg, frame->data, frame->length);
|
||
|
}
|
||
|
audio_encoder_frame_release(frame);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
while(1);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void _audio_scene_create(void)
|
||
|
{
|
||
|
audio_scene_t *audio_scene = audio_scene_env.scene;
|
||
|
|
||
|
if (audio_scene == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
switch (audio_scene->type) {
|
||
|
case AUDIO_SCENE_TYPE_A2DP_SINK:
|
||
|
init_a2dp_sink();
|
||
|
break;
|
||
|
case AUDIO_SCENE_TYPE_SCO:
|
||
|
init_sco();
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void _audio_scene_destroy(void)
|
||
|
{
|
||
|
audio_scene_t *scene = audio_scene_env.scene;
|
||
|
|
||
|
if (scene == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
switch (scene->type) {
|
||
|
case AUDIO_SCENE_TYPE_A2DP_SINK:
|
||
|
destroy_a2dp_sink();
|
||
|
break;
|
||
|
case AUDIO_SCENE_TYPE_SCO:
|
||
|
destroy_sco();
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
vPortFree(audio_scene_env.scene);
|
||
|
audio_scene_env.scene = NULL;
|
||
|
}
|
||
|
|
||
|
static void audio_scene_task(void *arg)
|
||
|
{
|
||
|
audio_scene_evt_t *evt;
|
||
|
audio_scene_t *scene;
|
||
|
|
||
|
while (1) {
|
||
|
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
|
||
|
GLOBAL_INT_DISABLE();
|
||
|
evt = (void *)co_list_pop_front(&audio_scene_env.evt_list);
|
||
|
GLOBAL_INT_RESTORE();
|
||
|
|
||
|
if (evt) {
|
||
|
switch (evt->type) {
|
||
|
case AUDIO_SCENE_EVT_TYPE_CREATE:
|
||
|
if (audio_scene_env.scene == NULL) {
|
||
|
audio_scene_env.scene = evt->p.scene;
|
||
|
_audio_scene_create();
|
||
|
}
|
||
|
else {
|
||
|
assert(0);
|
||
|
}
|
||
|
break;
|
||
|
case AUDIO_SCENE_EVT_TYPE_DESTROY:
|
||
|
if (audio_scene_env.scene == evt->p.scene) {
|
||
|
_audio_scene_destroy();
|
||
|
}
|
||
|
else {
|
||
|
assert(0);
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
scene = audio_scene_env.scene;
|
||
|
if (scene) {
|
||
|
switch (scene->type) {
|
||
|
case AUDIO_SCENE_TYPE_A2DP_SINK:
|
||
|
a2dp_sink_evt_handler(evt);
|
||
|
break;
|
||
|
case AUDIO_SCENE_TYPE_SCO:
|
||
|
sco_evt_handler(evt);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (evt->type == AUDIO_SCENE_EVT_TYPE_RECV_RAW_DATA) {
|
||
|
dram_free(evt->p.raw_data);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
vPortFree(evt);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void audio_scene_init(uint32_t stack_size, uint8_t priority)
|
||
|
{
|
||
|
co_list_init(&audio_scene_env.evt_list);
|
||
|
audio_scene_env.scene = NULL;
|
||
|
|
||
|
xTaskCreate(audio_scene_task, "AUDIO_SCENE_TASK", stack_size, NULL, priority, &audio_scene_env.audio_task_handle);
|
||
|
}
|
||
|
|
||
|
audio_scene_t *audio_scene_create(audio_scene_type_t type, void *param)
|
||
|
{
|
||
|
audio_scene_evt_t *evt;
|
||
|
audio_scene_t *audio_scene;
|
||
|
|
||
|
evt = (void *)pvPortMalloc(sizeof(audio_scene_evt_t));
|
||
|
|
||
|
audio_scene = (void *)pvPortMalloc(sizeof(audio_scene_t));
|
||
|
audio_scene->type = type;
|
||
|
switch (type) {
|
||
|
case AUDIO_SCENE_TYPE_A2DP_SINK:
|
||
|
memcpy((void *)&audio_scene->param.a2dp_sink, param, sizeof(audio_scene_param_a2dp_sink_t));
|
||
|
break;
|
||
|
case AUDIO_SCENE_TYPE_SCO:
|
||
|
memcpy((void *)&audio_scene->param.sco, param, sizeof(audio_scene_param_sco_t));
|
||
|
break;
|
||
|
default:
|
||
|
goto __err;
|
||
|
}
|
||
|
|
||
|
evt->type = AUDIO_SCENE_EVT_TYPE_CREATE;
|
||
|
evt->p.scene = audio_scene;
|
||
|
send_event(evt);
|
||
|
|
||
|
return audio_scene;
|
||
|
|
||
|
__err:
|
||
|
vPortFree(audio_scene);
|
||
|
vPortFree(evt);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void audio_scene_destroy(audio_scene_t *scene)
|
||
|
{
|
||
|
audio_scene_evt_t *evt;
|
||
|
evt = (void *)pvPortMalloc(sizeof(audio_scene_evt_t));
|
||
|
evt->type = AUDIO_SCENE_EVT_TYPE_DESTROY;
|
||
|
evt->p.scene = scene;
|
||
|
send_event(evt);
|
||
|
}
|
||
|
|
||
|
void audio_scene_recv_raw_data(audio_scene_t *scene, bool valid, uint8_t *buffer, uint32_t length)
|
||
|
{
|
||
|
audio_data_element_t *elt;
|
||
|
|
||
|
audio_scene_evt_t *evt;
|
||
|
evt = (void *)pvPortMalloc(sizeof(audio_scene_evt_t));
|
||
|
evt->type = AUDIO_SCENE_EVT_TYPE_RECV_RAW_DATA;
|
||
|
if (valid) {
|
||
|
elt = (void *)dram_malloc(sizeof(audio_data_element_t) + length);
|
||
|
elt->valid = true;
|
||
|
elt->length = length;
|
||
|
elt->offset = 0;
|
||
|
memcpy((void *)&elt->buffer[0], buffer, length);
|
||
|
}
|
||
|
else {
|
||
|
elt = (void *)dram_malloc(sizeof(audio_data_element_t));
|
||
|
elt->valid = false;
|
||
|
elt->length = AUDIO_SPECIAL_LENGTH_FOR_PLC;
|
||
|
elt->offset = 0;
|
||
|
}
|
||
|
evt->p.raw_data = elt;
|
||
|
send_event(evt);
|
||
|
}
|
||
|
|
||
|
bool audio_scene_dac_is_ready(audio_scene_t *scene)
|
||
|
{
|
||
|
return audio_decoder_is_started();
|
||
|
}
|