硬件、网络初始化完成后(此处略),建立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); }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_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 */ } #endifsynth_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
