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

shoutcast.c File Reference


Detailed Description

SHOUTcast receiver.

 *
 * $Log$
 *
 * 

Definition in file shoutcast.c.

#include <cfg/os.h>
#include <cfg/clock.h>
#include <dev/board.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <sys/version.h>
#include <sys/confnet.h>
#include <sys/atom.h>
#include <sys/heap.h>
#include <sys/thread.h>
#include <sys/timer.h>
#include <sys/event.h>
#include <sys/socket.h>
#include <hxmp3/mp3dec.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <net/route.h>
#include <pro/dhcp.h>
#include "tlv320dac.h"
#include "config.h"
#include "utils.h"
#include "userif.h"
#include "mp3player.h"
#include "shoutcast.h"

Include dependency graph for shoutcast.c:

Go to the source code of this file.

Defines

#define SHOUTCAST_THREAD_STACK   2048

Functions

static int ProcessMetaData (TCPSOCKET *sock, SHOUTCASTINFO *sci, u_int *status)
 Process embedded meta data.
void ShoutCastThread (void *arg)
 SHOUTcast receiver thread.
int ShoutCastCreate (RECEIVERINFO *rip)
 Create a SHOUTcast receiver instance.
int ShoutCastSetup (RECEIVERINFO *rip)
 Setup SHOUTcast receiver.

Variables

RECEIVERPLUGIN rpiShoutcast
 Receiver plug-in reference structure.


Define Documentation

#define SHOUTCAST_THREAD_STACK   2048
 

Definition at line 80 of file shoutcast.c.


Function Documentation

static int ProcessMetaData TCPSOCKET *  sock,
SHOUTCASTINFO sci,
u_int *  status
[static]
 

Process embedded meta data.

Definition at line 87 of file shoutcast.c.

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;

void ShoutCastThread void *  arg  ) 
 

SHOUTcast receiver thread.

Reads audio data from a TCP socket and passes it to a ring buffer. Meta data is parsed and removed from the audio stream.

Parameters:
arg Pointer to the player info structure.

Definition at line 171 of file shoutcast.c.

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     }

int ShoutCastCreate RECEIVERINFO rip  ) 
 

Create a SHOUTcast receiver instance.

Parameters:
rip Pointer to the receiver information structure.
Returns:
0 on success, -1 otherwise.

Definition at line 268 of file shoutcast.c.

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;

int ShoutCastSetup RECEIVERINFO rip  ) 
 

Setup SHOUTcast receiver.

Parses the header lines of the HTTP response.

Returns:
0 on success, or -1 if the server responded with an error code or doesn't seem to provide a SHOUTcast stream.

Definition at line 300 of file shoutcast.c.

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;


Variable Documentation

RECEIVERPLUGIN rpiShoutcast
 

Initial value:

Receiver plug-in reference structure.

Used by the application to create a SHOUTcast receiver instance.

Definition at line 351 of file shoutcast.c.


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