* * $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. |
|
Definition at line 80 of file shoutcast.c. |
|
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;
|
|
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.
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 }
|
|
Create a SHOUTcast receiver instance.
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;
|
|
Setup SHOUTcast receiver. Parses the header lines of the HTTP response.
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;
|
|
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. |