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
00100
00101 if (TcpGetBuffer(sock, (char *)&blks, 1, status)) {
00102
00103 return -1;
00104 }
00105
00106 if (blks == 0) {
00107
00108 return 0;
00109 }
00110 if (blks > 32) {
00111
00112 return -1;
00113 }
00114 mlen = (u_int)blks * 16;
00115
00116
00117
00118
00119 if ((mbuf = malloc(mlen + 1)) == 0) {
00120 return -1;
00121 }
00122 mbuf[mlen] = 0;
00123 if (TcpGetBuffer(sock, mbuf, mlen, status)) {
00124
00125 return -1;
00126 }
00127
00128
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
00182 for (;;) {
00183 printf("[RIDLE]");
00184 memset(sci, 0, sizeof(SHOUTCASTINFO));
00185 rip->ri_status = RSTAT_IDLE;
00186 NutEventBroadcast(&rip->ri_stsevt);
00187
00188
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
00200 rip->ri_status = RSTAT_RUNNING;
00201 NutEventBroadcast(&rip->ri_stsevt);
00202
00203
00204 while (rip->ri_status == RSTAT_RUNNING) {
00205
00206
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
00212
00213 rbytes = MP3_BUFSIZ - rip->ri_wpos;
00214 } else {
00215
00216
00217 rbytes = rip->ri_rpos - rip->ri_wpos - 1;
00218 }
00219
00220 if (rbytes > 4096) {
00221 rbytes = 4096;
00222 }
00223
00224 if (sci->sci_metaint && rbytes > sci->sci_metapos) {
00225 rbytes = sci->sci_metapos;
00226 }
00227
00228
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
00272 if ((rip->ri_bcast = malloc(sizeof(SHOUTCASTINFO))) != NULL) {
00273 memset(rip->ri_bcast, 0, sizeof(SHOUTCASTINFO));
00274
00275
00276 if ((rip->ri_buff = malloc(MP3_BUFSIZ + 2 * MAINBUF_SIZE)) != NULL) {
00277
00278
00279 if (NutThreadCreate("scast", ShoutCastThread, rip, SHOUTCAST_THREAD_STACK)) {
00280
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
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
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
00326 sip->si_name = cp;
00327 } else if (strncmp(sip->si_header[i], "icy-genre:", 10) == 0) {
00328
00329 sip->si_genre = cp;
00330 } else if (strncmp(sip->si_header[i], "icy-metaint:", 12) == 0) {
00331
00332 sci->sci_metaint = atol(cp);
00333 } else if (strncmp(sip->si_header[i], "icy-br:", 7) == 0) {
00334
00335 sip->si_bitrate = atoi(cp);
00336 } else if (strncmp(sip->si_header[i], "content-type:", 13) == 0) {
00337
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