版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/iamlvshijie/article/details/79334339
硬件、网络初始化完成后(此处略),建立web radio的任务
xTaskCreate(web_radio_task, "web_radio_task", 4096, NULL, 5, NULL);
vTaskSuspend(NULL);
web radio 初始化外部SPI Ram FIFO后,建立mp3 decode 任务,
void web_radio_task(void* pvParameters){
spiRamFifoInit();
xTaskCreate(mp3_decode_task, "mp3_decode_task", 8192, NULL, 5, NULL);
//start a http requet
http_client_get("http://icecast.omroep.nl/3fm-sb-mp3", &settings,NULL);
ESP_LOGE(TAG,"get completed!");
vTaskDelete(NULL);
}
在mp3 decode 任务中,
先初始化mad需要的stream,fram,synth
void mp3_decode_task(void *pvParameters)
{
int ret;
struct mad_stream *stream;
struct mad_frame *frame;
struct mad_synth *synth;
//Allocate structs needed for mp3 decoding
stream = malloc(sizeof(struct mad_stream));
frame = malloc(sizeof(struct mad_frame));
synth = malloc(sizeof(struct mad_synth));
//buffer_t *buf = buf_create(MAX_FRAME_SIZE);
if (stream==NULL) { printf("MAD: malloc(stream) failed\n"); return; }
if (synth==NULL) { printf("MAD: malloc(synth) failed\n"); return; }
if (frame==NULL) { printf("MAD: malloc(frame) failed\n"); return; }
//uint32_t buf_underrun_cnt = 0;
printf("MAD: Decoder start.\n");
//Initialize mp3 parts
mad_stream_init(stream);
mad_frame_init(frame);
mad_synth_init(synth);
while(1) {
// calls mad_stream_buffer internally
if (input(stream) == MAD_FLOW_STOP ) {
break;
}
// decode frames until MAD complains
while(1) {
// returns 0 or -1
ret = mad_frame_decode(frame, stream);
if (ret == -1) {
if (!MAD_RECOVERABLE(stream->error)) {
//We're most likely out of buffer and need to call input() again
break;
}
error(NULL, stream, frame);
continue;
}
mad_synth_frame(synth, frame);
}
// ESP_LOGI(TAG, "RAM left %d", esp_get_free_heap_size());
}
// abort:
// // avoid noise
// i2s_zero_dma_buffer(0);
// free(synth);
// free(frame);
// free(stream);
// // clear semaphore for reader task
// spiRamFifoReset();
// printf("MAD: Decoder stopped.\n");
// ESP_LOGI(TAG, "MAD decoder stack: %d\n", uxTaskGetStackHighWaterMark(NULL));
vTaskDelete(NULL);
}
其中,input中调用mad_stream_buffer
"此函数把原始的未解码的 MPEG 数据和 mad_stream 数据结构关联,以便使用 mad_frame_decode( ) 来解码 MPEG 帧数据"(http://blog.csdn.net/gepanqiang3020/article/details/73695483)。
static enum mad_flow input(struct mad_stream *stream) {
int n, i;
int rem, fifoLen;
//Shift remaining contents of buf to the front
rem=stream->bufend-stream->next_frame;
memmove(readBuf, stream->next_frame, rem);
while (rem<sizeof(readBuf)) {
n=(sizeof(readBuf)-rem); //Calculate amount of bytes we need to fill buffer.
i=spiRamFifoFill();
if (i<n) n=i; //If the fifo can give us less, only take that amount
if (n==0) { //Can't take anything?
//Wait until there is enough data in the buffer. This only happens when the data feed
//rate is too low, and shouldn't normally be needed!
// printf("Buf uflow, need %d bytes.\n", sizeof(readBuf)-rem);
bufUnderrunCt++;
//We both silence the output as well as wait a while by pushing silent samples into the i2s system.
//This waits for about 200mS
i2s_zero_dma_buffer(0);
} else {
//Read some bytes from the FIFO to re-fill the buffer.
spiRamFifoRead(&readBuf[rem], n);
rem+=n;
}
}
//Okay, let MAD decode the buffer.
mad_stream_buffer(stream, (unsigned char*)readBuf, sizeof(readBuf));
return MAD_FLOW_CONTINUE;
}
其中,mad_frame_decode
其中,mad_synth_frame
void mad_synth_frame(struct mad_synth *synth, struct mad_frame const *frame)
{
unsigned int nch, ns;
void (*synth_frame)(struct mad_synth *, struct mad_frame const *,
unsigned int, unsigned int);
nch = MAD_NCHANNELS(&frame->header);
ns = MAD_NSBSAMPLES(&frame->header);
synth->pcm.samplerate = frame->header.samplerate;
set_dac_sample_rate(synth->pcm.samplerate);
synth->pcm.channels = nch;
// synth->pcm.length = 32 * ns;
synth->pcm.length = 128 * ns;
synth_frame = synth_full;
if (frame->options & MAD_OPTION_HALFSAMPLERATE) {
synth->pcm.samplerate /= 2;
synth->pcm.length /= 2;
set_dac_sample_rate(synth->pcm.samplerate);
synth_frame = synth_half;
}
synth_frame(synth, frame, nch, ns);
synth->phase = (synth->phase + ns) % 16;
}
其中,synth_full
# if defined(ASO_SYNTH)
void synth_full(struct mad_synth *, struct mad_frame const *,
unsigned int, unsigned int);
# else
/*
* NAME: synth->full()
* DESCRIPTION: perform full frequency PCM synthesis
*/
static
void synth_full(struct mad_synth *synth, struct mad_frame const *frame,
unsigned int nch, unsigned int ns)
{
unsigned int phase, ch, s, sb, pe, po;
short int *pcm1, *pcm2;
mad_fixed_t (*filter)[2][2][16][8];
mad_fixed_t (*sbsample)[36][32];
register mad_fixed_t (*fe)[8], (*fx)[8], (*fo)[8];
register mad_fixed_t const (*Dptr)[32], *ptr ;
register mad_fixed64hi_t hi;
register mad_fixed64lo_t lo;
mad_fixed_t raw_sample;
short int short_sample_buff[32];
phase = synth->phase;
.....
/* Render di un blocco */
render_sample_block(short_sample_buff, 32);
phase = (phase + 1) % 16;
} /* Block for */
}
#endif
其中,render_sample_block将数据通过I2S写入codec/* render callback for the libmad synth */
void render_sample_block(short *short_sample_buff, int no_samples)
{
//ESP_LOGI(TAG,"render_sample_length:%d",len);
// while (nsamples--) {
// signed int sample;
// /* output sample(s) in 16-bit signed little-endian PCM */
// sample = scale(*left_ch++);
// putchar((sample >> 0) & 0xff);
// putchar((sample >> 8) & 0xff);
// if (nchannels == 2) {
// sample = scale(*right_ch++);
// putchar((sample >> 0) & 0xff);
// putchar((sample >> 8) & 0xff);
// }
// }
uint32_t len=no_samples*4;
for(int i=0;i<no_samples;i++){
short right=short_sample_buff[i];
short left=short_sample_buff[i];
char buf[4];
memcpy(buf,&right,2);
memcpy(buf+2,&left,2);
i2s_write_bytes(0,buf, 4, 1000 / portTICK_RATE_MS);
}
//render_samples((char*) sample_buff_ch0, len, &mad_buffer_fmt);
return;
}
同样
在synth_half调用render_sample_block函数
render_sample_block(short_sample_buff, 16);
参考:
http://blog.csdn.net/gepanqiang3020/article/details/73695483
http://blog.csdn.net/gepanqiang3020/article/details/73696533
http://blog.chinaunix.net/uid-30008524-id-5211762.html
http://www.linuxfromscratch.org/blfs/view/svn/index.html