esp32- esp32snow webradio代码学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 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

猜你喜欢

转载自blog.csdn.net/iamlvshijie/article/details/79334339
今日推荐