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

shoutcast.c

Go to the documentation of this file.
00001 
00044 #include <cfg/os.h>
00045 #include <cfg/clock.h>
00046 #include <dev/board.h>
00047 
00048 #include <stdlib.h>
00049 #include <string.h>
00050 #include <stdio.h>
00051 #include <fcntl.h>
00052 #include <io.h>
00053 
00054 #include <sys/version.h>
00055 #include <sys/confnet.h>
00056 #include <sys/atom.h>
00057 #include <sys/heap.h>
00058 #include <sys/thread.h>
00059 #include <sys/timer.h>
00060 #include <sys/event.h>
00061 #include <sys/socket.h>
00062 
00063 #include <hxmp3/mp3dec.h>
00064 
00065 #include <netinet/tcp.h>
00066 #include <arpa/inet.h>
00067 #include <net/route.h>
00068 #include <pro/dhcp.h>
00069 
00070 #include "tlv320dac.h"
00071 #include "config.h"
00072 #include "utils.h"
00073 #include "userif.h"
00074 #include "mp3player.h"
00075 #include "shoutcast.h"
00076 
00077 #ifndef SHOUTCAST_THREAD_STACK
00078 #ifdef AT91SAM7X_EK
00079 #define SHOUTCAST_THREAD_STACK  1024
00080 #else
00081 #define SHOUTCAST_THREAD_STACK  2048
00082 #endif
00083 #endif
00084 
00088 static int ProcessMetaData(TCPSOCKET * sock, SHOUTCASTINFO * sci, u_int *status)
00089 {
00090     u_char blks = 0;
00091     u_int mlen;
00092     char *mbuf;
00093     char *mn1;
00094     char *mn2;
00095     char *md1;
00096     char *md2;
00097 
00098     /*
00099      * Wait for the lenght byte.
00100      */
00101     if (TcpGetBuffer(sock, (char *)&blks, 1, status)) {
00102         /* Status change or receive error. */
00103         return -1;
00104     }
00105 
00106     if (blks == 0) {
00107         /* Empty metadata block. */
00108         return 0;
00109     }
00110     if (blks > 32) {
00111         /* We are probably out of sync. */
00112         return -1;
00113     }
00114     mlen = (u_int)blks * 16;
00115 
00116     /*
00117      * Wait for the metadata block.
00118      */
00119     if ((mbuf = malloc(mlen + 1)) == 0) {
00120         return -1;
00121     }
00122     mbuf[mlen] = 0;
00123     if (TcpGetBuffer(sock, mbuf, mlen, status)) {
00124         /* Status change or receive error. */
00125         return -1;
00126     }
00127 
00128     //ClearMetaData();
00129     printf("\nMeta=\"%s\"\n", mbuf);
00130     mn1 = mbuf;
00131     while (mn1) {
00132         if ((mn2 = strchr(mn1, ';')) != 0)
00133             *mn2++ = 0;
00134         if ((md1 = strchr(mn1, '=')) != 0) {
00135             *md1++ = 0;
00136             while (*md1 == ' ' || *md1 == '\'')
00137                 md1++;
00138             if ((md2 = strrchr(md1, '\'')) != 0)
00139                 *md2 = 0;
00140             if (strcasecmp(mn1, "StreamTitle") == 0) {
00141                 if (sci->sci_metatitle) {
00142                     free(sci->sci_metatitle);
00143                 }
00144                 if ((sci->sci_metatitle = malloc(strlen(md1) + 1)) != NULL) {
00145                     strcpy(sci->sci_metatitle, md1);
00146                 }
00147             } else if (strcasecmp(mn1, "StreamUrl") == 0) {
00148                 if (sci->sci_metaurl) {
00149                     free(sci->sci_metaurl);
00150                 }
00151                 if ((sci->sci_metaurl = malloc(strlen(md1) + 1)) != NULL) {
00152                     strcpy(sci->sci_metaurl, md1);
00153                 }
00154             }
00155         }
00156         mn1 = mn2;
00157     }
00158 
00159     free(mbuf);
00160 
00161     return 0;
00162 }
00163 
00172 THREAD(ShoutCastThread, arg)
00173 {
00174     RECEIVERINFO *rip = (RECEIVERINFO *) arg;
00175     SHOUTCASTINFO *sci = (SHOUTCASTINFO *) rip->ri_bcast;
00176     STATIONINFO *sip;
00177     int rbytes;
00178     int got;
00179 
00180     for (;;) {
00181         /* Idle loop. */
00182         for (;;) {
00183             printf("[RIDLE]");
00184             memset(sci, 0, sizeof(SHOUTCASTINFO));
00185             rip->ri_status = RSTAT_IDLE;
00186             NutEventBroadcast(&rip->ri_stsevt);
00187 
00188             /* Wait for start event. */
00189             NutEventWait(&rip->ri_cmdevt, 0);
00190             printf("[REVT%u]", rip->ri_status);
00191             if (rip->ri_status == RSTAT_START) {
00192                 break;
00193             }
00194         }
00195 
00196         printf("[RRUN]");
00197         sip = rip->ri_sip;
00198         sci->sci_metapos = sci->sci_metaint;
00199         /* Broadcast running event. */
00200         rip->ri_status = RSTAT_RUNNING;
00201         NutEventBroadcast(&rip->ri_stsevt);
00202 
00203         /* Running loop. */
00204         while (rip->ri_status == RSTAT_RUNNING) {
00205             /* Wrap write pointer, if the read pointer is not at the
00206                buffer start. */
00207             if (rip->ri_wpos >= MP3_BUFSIZ && rip->ri_rpos > 0) {
00208                 rip->ri_wpos = 0;
00209             }
00210             if (rip->ri_wpos >= rip->ri_rpos) {
00211                 /* Write pointer is in front of or equal to the read pointer. 
00212                    Allow to write up to the end of the buffer. */
00213                 rbytes = MP3_BUFSIZ - rip->ri_wpos;
00214             } else {
00215                 /* Write pointer is behind read pointer. Allow to write up
00216                    to the last byte before the read pointer. */
00217                 rbytes = rip->ri_rpos - rip->ri_wpos - 1;
00218             }
00219             /* Honor some limit. */
00220             if (rbytes > 4096) {
00221                 rbytes = 4096;
00222             }
00223             /* Do not read beyond meta data. */
00224             if (sci->sci_metaint && rbytes > sci->sci_metapos) {
00225                 rbytes = sci->sci_metapos;
00226             }
00227 
00228             /* If the buffer is full, wait for a signal from the consumer. */
00229             if (rbytes == 0) {
00230                 putchar('!');
00231                 NutEventWait(&rip->ri_wrbque, 1000);
00232                 continue;
00233             }
00234 
00235             if ((got = NutTcpReceive(sip->si_sock, &rip->ri_buff[rip->ri_wpos], rbytes)) < 0) {
00236                 printf("[RXFAIL(%d)%d]", rbytes, NutTcpError(sip->si_sock));
00237                 break;
00238             }
00239             if (got) {
00240                 rip->ri_wpos += got;
00241                 rip->ri_avail += got;
00242                 if (rip->ri_avail >= 2 * MAINBUF_SIZE) {
00243                     NutEventPost(&rip->ri_rdbque);
00244                 }
00245                 if (sci->sci_metaint) {
00246                     sci->sci_metapos -= got;
00247                     if (sci->sci_metapos == 0) {
00248                         if (ProcessMetaData(sip->si_sock, sci, &rip->ri_status)) {
00249                             break;
00250                         }
00251                         else {
00252                             UserIfShowStatus(DIST_FORCE);
00253                         }
00254                         sci->sci_metapos = sci->sci_metaint;
00255                     }
00256                 }
00257             }
00258         }
00259     }
00260 }
00261 
00269 int ShoutCastCreate(RECEIVERINFO * rip)
00270 {
00271     /* Allocate local info structure. */
00272     if ((rip->ri_bcast = malloc(sizeof(SHOUTCASTINFO))) != NULL) {
00273         memset(rip->ri_bcast, 0, sizeof(SHOUTCASTINFO));
00274 
00275         /* Allocate the audio stream buffer. */
00276         if ((rip->ri_buff = malloc(MP3_BUFSIZ + 2 * MAINBUF_SIZE)) != NULL) {
00277 
00278             /* Start the receiver thread. */
00279             if (NutThreadCreate("scast", ShoutCastThread, rip, SHOUTCAST_THREAD_STACK)) {
00280                 /* Success! */
00281                 return 0;
00282             }
00283             free(rip->ri_buff);
00284             rip->ri_buff = NULL;
00285         }
00286         free(rip->ri_bcast);
00287         rip->ri_bcast = NULL;
00288     }
00289     /* Not enough memory. */
00290     return -1;
00291 }
00292 
00301 int ShoutCastSetup(RECEIVERINFO * rip)
00302 {
00303     STATIONINFO *sip = rip->ri_sip;
00304     SHOUTCASTINFO *sci = (SHOUTCASTINFO *) rip->ri_bcast;
00305     int i;
00306     char *cp;
00307 
00308     /* 
00309      * Check if we really have a SHOUTcast server.
00310      */
00311     if (strlen(sip->si_header[0]) < 7 || strncmp(sip->si_header[0], "ICY", 3)) {
00312         return -1;
00313     }
00314     if (atoi(sip->si_header[0] + 4) != 200) {
00315         return -1;
00316     }
00317     sip->si_stype = STATION_TYPE_SHOUTCAST;
00318     sip->si_ptype = PLAYER_TYPE_MP3;
00319     sci->sci_metaint = 0;
00320 
00321     for (i = 1; sip->si_header[i]; i++) {
00322         if ((cp = strchr(sip->si_header[i], ':')) != NULL) {
00323             cp++;
00324             if (strncmp(sip->si_header[i], "icy-name:", 9) == 0) {
00325                 /* Set the station name. */
00326                 sip->si_name = cp;
00327             } else if (strncmp(sip->si_header[i], "icy-genre:", 10) == 0) {
00328                 /* Set the station's genre. */
00329                 sip->si_genre = cp;
00330             } else if (strncmp(sip->si_header[i], "icy-metaint:", 12) == 0) {
00331                 /* Set the metadata interval. */
00332                 sci->sci_metaint = atol(cp);
00333             } else if (strncmp(sip->si_header[i], "icy-br:", 7) == 0) {
00334                 /* Set the bit rate. */
00335                 sip->si_bitrate = atoi(cp);
00336             } else if (strncmp(sip->si_header[i], "content-type:", 13) == 0) {
00337                 /* Check content type. Modify this to add more decoders. */
00338                 if (strcmp(cp, "audio/mpeg")) {
00339                     sip->si_ptype = 0;
00340                 }
00341             }
00342         }
00343     }
00344     return 0;
00345 }
00346 
00352 RECEIVERPLUGIN rpiShoutcast = {
00353     ShoutCastCreate,    
00354     ShoutCastSetup      
00355 };
00356 

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