Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

mp3player.c File Reference


Detailed Description

MP3 player.

 *
 * $Log$
 *
 * 

Definition in file mp3player.c.

#include <cfg/os.h>
#include <cfg/clock.h>
#include <dev/board.h>
#include <sys/heap.h>
#include <sys/timer.h>
#include <sys/event.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <io.h>
#include "tlv320dac.h"
#include "webradio.h"
#include "utils.h"
#include "userif.h"
#include "mp3player.h"

Include dependency graph for mp3player.c:

Go to the source code of this file.

Defines

#define MP3_THREAD_STACK   2048
#define ENABLE_RESAMPLER

Functions

static void Mp3PlayerBufferFill (PLAYERINFO *pip)
 Wait until the MP3 data buffer is sufficiently filled.
void Mp3PlayerThread (void *arg)
 MP3 player thread.
int Mp3PlayerCreate (PLAYERINFO *pip)
 Create MP3 player instance.
int Mp3PlayerSetup (PLAYERINFO *pip)
 Setup MP3 player.

Variables

static void * hres
static int rs_maxout
static short * rs_pcmbuf
PLAYERPLUGIN ppiMp3
 MP3 player plug-in reference structure.


Define Documentation

#define MP3_THREAD_STACK   2048
 

Definition at line 66 of file mp3player.c.

#define ENABLE_RESAMPLER
 

Definition at line 73 of file mp3player.c.


Function Documentation

static void Mp3PlayerBufferFill PLAYERINFO pip  )  [static]
 

Wait until the MP3 data buffer is sufficiently filled.

Parameters:
pip Pointer to the player info structure.

Definition at line 86 of file mp3player.c.

00088 {
00089     RECEIVERINFO *rip;
00090     time_t start = time(NULL);
00091 
00092     printf("\nBuffering");
00093     for (;;) {
00094         /* Return if 2/3 of the buffer is filled. */
00095         rip = pip->pi_rcvr;
00096         if (rip == NULL || rip->ri_avail >= (MP3_BUFSIZ * 2) / 3) {
00097             break;
00098         }
00099         /* Return if we reached our time limit. */
00100         if (time(NULL) - start >= MAX_WAIT_MP3BUF_FILLED) {
00101             break;
00102         }
00103         /* Return if someone stopped the player. */
00104         if (pip->pi_status != PSTAT_RUNNING) {
00105             break;
00106         }
00107         /* Wait for an event from the producer. */
00108         if (NutEventWait(&rip->ri_rdbque, 500) == 0) {
00109             putchar('.');
00110         }
00111         UserIfShowMessage(1, 1, "Buffering %u%%",  (rip->ri_avail * 100) / MP3_BUFSIZ);
00112     }
00113     printf(" %u bytes free\n", (u_int)NutHeapAvailable());

void Mp3PlayerThread void *  arg  ) 
 

MP3 player thread.

Parameters:
arg Pointer to the player info structure.

Definition at line 120 of file mp3player.c.

00122 {
00123     PLAYERINFO *pip = (PLAYERINFO *)arg;
00124     MP3PLAYERINFO *mpi = (MP3PLAYERINFO *) pip->pi_bcast;
00125     RECEIVERINFO *rip;
00126     int rbytes;
00127     u_char *bufptr;
00128     int ec;
00129     int errcnt;
00130     int tmocnt;
00131     int first_frame;
00132     int samprate;
00133 
00134     Tlv320DacInit(DAC_OUTPUT_RATE);
00135     Tlv320DacSetVolume(radio.rc_rvolume, radio.rc_rvolume);
00136     radio.rc_cvolume = radio.rc_rvolume;
00137 
00138     for (;;) {
00139         /* Idle loop. */
00140         for (;;) {
00141             printf("[PIDLE]");
00142             pip->pi_status = PSTAT_IDLE;
00143             NutEventBroadcast(&pip->pi_stsevt);
00144 
00145             if (mpi->mpi_mp3dec) {
00146                 MP3FreeDecoder(mpi->mpi_mp3dec);
00147                 mpi->mpi_mp3dec = NULL;
00148             }
00149 
00150             /* Wait for start event. */
00151             NutEventWait(&pip->pi_cmdevt, 0);
00152             printf("[PEVT%u]", pip->pi_status);
00153             if (pip->pi_status == PSTAT_START) {
00154                 if (mpi->mpi_mp3dec == NULL) {
00155                     if ((mpi->mpi_mp3dec = MP3InitDecoder()) == NULL) {
00156                         printf("\n[ERR-MP3INI]");
00157                     }
00158                 }
00159                 if (mpi->mpi_mp3dec && pip->pi_rcvr) {
00160                     break;
00161                 }
00162             }
00163         }
00164 
00165         /* Broadcast running event. */
00166         printf("[PRUN]");
00167         pip->pi_status = PSTAT_RUNNING;
00168         NutEventBroadcast(&pip->pi_stsevt);
00169         rip = pip->pi_rcvr;
00170 
00171         /* Wait for enough data to start playing. */
00172         NutSleep(500);
00173         Mp3PlayerBufferFill(pip);
00174 
00175         /* Running loop. */
00176         errcnt = 0;
00177         tmocnt = 0;
00178         first_frame = 1;
00179         while (pip->pi_status == PSTAT_RUNNING) {
00180             /* Wait for new data. */
00181             if (rip->ri_avail < 2 * MAINBUF_SIZE) {
00182                 if (++tmocnt > 4) {
00183                     break;
00184                 }
00185                 Mp3PlayerBufferFill(pip);
00186                 continue;
00187             }
00188             if (tmocnt) {
00189                 tmocnt--;
00190             }
00191 
00192             if (rip->ri_rpos > rip->ri_wpos && MP3_BUFSIZ - rip->ri_rpos < 2 * MAINBUF_SIZE) {
00193                 /* The read pointer is in front of the write pointer, but
00194                    there is not enough MP3 data at the end of the buffer.
00195                    Wrap data from the front to the back, because the decoder
00196                    requires a continous buffer. Note, that we allocated the
00197                    additional bytes at the end of the MP3 data buffer for
00198                    this purpose. */
00199                 memcpy(&rip->ri_buff[MP3_BUFSIZ], rip->ri_buff, 2 * MAINBUF_SIZE - (MP3_BUFSIZ - rip->ri_rpos));
00200             }
00201 
00202             /* Test for sync error. Discard data up to the next sync word. */
00203             ec = 0;
00204             if ((rbytes = MP3FindSyncWord(&rip->ri_buff[rip->ri_rpos], 2 * MAINBUF_SIZE)) < 0) {
00205                 puts("\n[ERR-SYN]");
00206                 break;
00207             }
00208             else if (rbytes == 0) {
00209                 /* We are in sync. Decode the next MP3 frame. */
00210                 if (ec == 0) {
00211                     rbytes = 2 * MAINBUF_SIZE;
00212                     bufptr = &rip->ri_buff[rip->ri_rpos];
00213                     Led0(1);
00214                     ec = MP3Decode(mpi->mpi_mp3dec, &bufptr, &rbytes, pip->pi_pcmbuf, 0);
00215                     Led0(0);
00216                     if (ec) {
00217                         rbytes = 0;
00218                     }
00219                     else {
00220                         rbytes = 2 * MAINBUF_SIZE - rbytes;
00221                     }
00222                 }
00223                 if (ec == 0) {
00224                     if (first_frame) {
00225                         /*
00226                          * This is the first frame. Retrieve the frame data, print it
00227                          * to the debug port and optionally initialize the resampler.
00228                          */
00229                         MP3GetLastFrameInfo(mpi->mpi_mp3dec, &mpi->mpi_frameinfo);
00230                         printf("\nBitrate\t\t: %d", mpi->mpi_frameinfo.bitrate);
00231                         printf("\nChannels\t: ");
00232                         if (mpi->mpi_frameinfo.nChans == 1) {
00233                             printf("Mono");
00234                             samprate = mpi->mpi_frameinfo.samprate / 2;
00235                         }
00236                         else if (mpi->mpi_frameinfo.nChans == 2) {
00237                             printf("Stereo");
00238                             samprate = mpi->mpi_frameinfo.samprate;
00239                         }
00240                         else {
00241                             samprate = 0;
00242                             putchar('?');
00243                             ec = -1;
00244                         }
00245                         printf("\nSample rate\t: %d", mpi->mpi_frameinfo.samprate);
00246                         if (mpi->mpi_frameinfo.samprate < 8000 || samprate > DAC_OUTPUT_RATE) {
00247                             printf(" not supported");
00248                             ec = -1;
00249                         }
00250                         printf("\nBits/sample\t: %d", mpi->mpi_frameinfo.bitsPerSample);
00251                         if (mpi->mpi_frameinfo.bitsPerSample != 16) {
00252                             printf(" not supported");
00253                             ec = -1;
00254                         }
00255                         printf("\nSamples\t\t: %d", mpi->mpi_frameinfo.outputSamps);
00256 #ifdef ENABLE_RESAMPLER
00257                         /* If needed, initialize resampler. */
00258                         if (ec == 0 && samprate != DAC_OUTPUT_RATE) {
00259                             if ((hres = RAInitResamplerHermite(samprate, DAC_OUTPUT_RATE, mpi->mpi_frameinfo.nChans)) == NULL) {
00260                                 printf(" failed");
00261                                 ec = -1;
00262                             }
00263                             rs_maxout = RAGetMaxOutputHermite(mpi->mpi_frameinfo.outputSamps, hres);
00264                             printf(" -> %d", rs_maxout);
00265                             if ((rs_pcmbuf = malloc(rs_maxout * 2)) == NULL) {
00266                                 printf(" no mem");
00267                                 ec = -1;
00268                             }
00269                         }
00270 #endif
00271                         printf("\nLayer\t\t: %d", mpi->mpi_frameinfo.layer);
00272                         printf("\nVersion\t\t: %d\n", mpi->mpi_frameinfo.version);
00273                         if (ec) {
00274                             break;
00275                         }
00276                         first_frame = 0;
00277                     }
00278                     if (hres == NULL) {
00279                         /* Same rate as our DAC. */
00280                         if (Tlv320DacWrite(pip->pi_pcmbuf, mpi->mpi_frameinfo.outputSamps)) {
00281                             puts("\n[**ERR-ADC**]");
00282                             break;
00283                         }
00284                     }
00285 #ifdef ENABLE_RESAMPLER
00286                     else {
00287                         int os;
00288 
00289                         if (mpi->mpi_frameinfo.nChans == 1) {
00290                             os = RAResampleMonoHermite(pip->pi_pcmbuf, mpi->mpi_frameinfo.outputSamps, rs_pcmbuf, hres);
00291                         }
00292                         else {
00293                             os = RAResampleStereoHermite(pip->pi_pcmbuf, mpi->mpi_frameinfo.outputSamps, rs_pcmbuf, hres);
00294                         }
00295                         if (os <= 0) {
00296                             puts("\n[**ERR-RSMPLR**]");
00297                             break;
00298                         }
00299                         if (Tlv320DacWrite(rs_pcmbuf, os)) {
00300                             puts("\n[**ERR-ADC**]");
00301                             break;
00302                         }
00303                     }
00304 #endif
00305                     if (radio.rc_rvolume != radio.rc_cvolume) {
00306                         Tlv320DacSetVolume(radio.rc_rvolume, radio.rc_rvolume);
00307                         radio.rc_cvolume = radio.rc_rvolume;
00308                     }
00309                     /* Slowly recover from previous errors. */
00310                     if (errcnt) {
00311                         errcnt--;
00312                     }
00313                 }
00314                 else {
00315                     printf("\n[ERR%d] %u bytes free\n", ec, (u_int)NutHeapAvailable());
00316                     /* Move to idle state in case of fatal errors. */
00317                     if (ec == ERR_MP3_OUT_OF_MEMORY) {
00318                         break;
00319                     }
00320                     /* In case of too many errors move to idle state. */
00321                     if (++errcnt > MAX_PLAYERRORS) {
00322                         break;
00323                     }
00324                     /* Avoid to get stuck on the same error. */
00325                     if (rbytes == 0) {
00326                         rbytes = 1;
00327                     }
00328                 }
00329             }
00330             else {
00331                 /* In case of too many sync errors move to idle state. */
00332                 printf("[SKIP %d]", rbytes);
00333                 if (++errcnt > MAX_PLAYERRORS) {
00334                     break;
00335                 }
00336             }
00337             /* Adjust the read pointer and the number of bytes available. */
00338             rip->ri_avail -= rbytes;
00339             rip->ri_rpos += rbytes;
00340             if (rip->ri_rpos >= MP3_BUFSIZ) {
00341                 rip->ri_rpos -= MP3_BUFSIZ;
00342             }
00343             /* Inform the receiver, that we removed data from the buffer. */
00344             NutEventPost(&rip->ri_wrbque);
00345         }
00346 #ifdef ENABLE_RESAMPLER
00347         if (hres) {
00348             printf("[RSREL]");
00349             RAFreeResamplerHermite(hres);
00350             hres = NULL;
00351             if (rs_pcmbuf) {
00352                 free(rs_pcmbuf);
00353                 rs_pcmbuf = NULL;
00354             }
00355         }
00356 #endif
00357         if (Tlv320DacFlush()) {
00358             printf("\n[ERR DACFlush]");
00359         }
00360     }

int Mp3PlayerCreate PLAYERINFO pip  ) 
 

Create MP3 player instance.

Called when creating a player instance.

Parameters:
pip Pointer to the PLAYERINFO structure.
Returns:
0 on success, otherwise -1.

Definition at line 371 of file mp3player.c.

00373 {
00374     /* Allocate local info structure. */
00375     if ((pip->pi_bcast = malloc(sizeof(MP3PLAYERINFO))) != NULL) {
00376         memset(pip->pi_bcast, 0, sizeof(MP3PLAYERINFO));
00377 
00378         /* Start the player thread. */
00379         if (NutThreadCreate("mp3play", Mp3PlayerThread, pip, MP3_THREAD_STACK)) {
00380             /* Success! */
00381             return 0;
00382         }
00383         free(pip->pi_bcast);
00384     }
00385     /* Not enough memory. */
00386     return -1;
00387 

int Mp3PlayerSetup PLAYERINFO pip  ) 
 

Setup MP3 player.

Doesn't do anything right now.

Returns:
Always 0.

Definition at line 396 of file mp3player.c.

00398 {
00399     return 0;


Variable Documentation

void* hres [static]
 

Definition at line 70 of file mp3player.c.

int rs_maxout [static]
 

Definition at line 77 of file mp3player.c.

short* rs_pcmbuf [static]
 

Definition at line 78 of file mp3player.c.

PLAYERPLUGIN ppiMp3
 

Initial value:

MP3 player plug-in reference structure.

Used by the application to link an MP3 player instance.

Definition at line 406 of file mp3player.c.


Generated on Fri Feb 23 17:28:53 2007 for SAM Internet Radio by  doxygen 1.4.4