player.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003-2006 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00056 #include <sys/heap.h>
00057 #include <sys/event.h>
00058 #include <sys/timer.h>
00059 #include <sys/thread.h>
00060 
00061 #include <dev/vs1001k.h>
00062 
00063 #include <stdlib.h>
00064 #include <string.h>
00065 #include <stdio.h>
00066 
00067 #include "player.h"
00068 #include <sys/bankmem.h>
00069 
00070 #define MAX_WAITSTREAM      20
00071 #define BIGBUF_WATERMARK    65535UL
00072 
00073 
00074 PLAYERINFO player;
00075 
00076 #if defined(__AVR__)
00077 
00078 /*
00079  * Process embedded meta data.
00080  */
00081 static void ClearMetaData(void)
00082 {
00083     if (player.psi_metatitle) {
00084         free(player.psi_metatitle);
00085         player.psi_metatitle = 0;
00086     }
00087     if (player.psi_metaurl) {
00088         free(player.psi_metaurl);
00089         player.psi_metaurl = 0;
00090     }
00091 }
00092 
00093 /*
00094  * Process embedded meta data.
00095  */
00096 static int ProcessMetaData(void)
00097 {
00098     u_char blks = 0;
00099     u_short cnt;
00100     int got;
00101     int rc = 0;
00102     u_char to_cnt = 0;
00103     char *mbuf;
00104     char *mn1;
00105     char *mn2;
00106     char *md1;
00107     char *md2;
00108 
00109     /*
00110      * Wait for the lenght byte.
00111      */
00112     while (player.psi_status == PSI_RUNNING) {
00113         if ((got = NutTcpReceive(player.psi_sock, &blks, 1)) == 1)
00114             break;
00115         if (got < 0 || to_cnt++ > MAX_WAITSTREAM) {
00116             printf("[NoLen]");
00117             return -1;
00118         }
00119     }
00120     if (blks) {
00121         if (blks > 32) {
00122             printf("[Blks=%u]", blks);
00123             return -1;
00124         }
00125 
00126         cnt = blks * 16;
00127         if ((mbuf = malloc(cnt + 1)) == 0) {
00128             printf("[NoMem]");
00129             return -1;
00130         }
00131 
00132         /*
00133          * Receive the metadata block.
00134          */
00135         while (player.psi_status == PSI_RUNNING) {
00136             if ((got = NutTcpReceive(player.psi_sock, mbuf + rc, cnt)) < 0) {
00137                 printf("[RxFail]");
00138                 return -1;
00139             }
00140             if (got) {
00141                 to_cnt = 0;
00142                 if ((cnt -= got) == 0)
00143                     break;
00144                 rc += got;
00145                 mbuf[rc] = 0;
00146             } else if (to_cnt++ > MAX_WAITSTREAM) {
00147                 printf("[RxTo]");
00148                 return -1;
00149             }
00150         }
00151 
00152         ClearMetaData();
00153         printf("\nMeta='%s'\n", mbuf);
00154         mn1 = mbuf;
00155         while (mn1) {
00156             if ((mn2 = strchr(mn1, ';')) != 0)
00157                 *mn2++ = 0;
00158             if ((md1 = strchr(mn1, '=')) != 0) {
00159                 *md1++ = 0;
00160                 while (*md1 == ' ' || *md1 == '\'')
00161                     md1++;
00162                 if ((md2 = strrchr(md1, '\'')) != 0)
00163                     *md2 = 0;
00164                 if (strcasecmp(mn1, "StreamTitle") == 0 && player.psi_metatitle == 0) {
00165                     player.psi_metatitle = malloc(strlen(md1) + 1);
00166                     strcpy(player.psi_metatitle, md1);
00167                 } else if (strcasecmp(mn1, "StreamUrl") == 0 && player.psi_metaurl == 0) {
00168                     player.psi_metaurl = malloc(strlen(md1) + 1);
00169                     strcpy(player.psi_metaurl, md1);
00170                 }
00171             }
00172             mn1 = mn2;
00173         }
00174         free(mbuf);
00175         player.psi_metaupdate = 1;
00176     }
00177     return 0;
00178 }
00179 
00180 
00181 /*
00182  * Background thread for playing stream.
00183  */
00184 THREAD(Player, arg)
00185 {
00186     size_t rbytes;
00187     char  *mp3buf;
00188     u_char to_cnt = 0;
00189     int got;
00190     u_char ief;
00191 
00192     /*
00193      * Nut/OS threads run forever.
00194      */
00195     for (;;) {
00196         /*
00197          * Idle loop.
00198          */
00199         for (;;) {
00200             /* Broadcast idle status. */
00201             printf("[IDLE]");
00202             ClearMetaData();
00203             player.psi_status = PSI_IDLE;
00204             NutEventBroadcast(&player.psi_stsevt);
00205 
00206             /* Wait for start event. */
00207             NutEventWait(&player.psi_cmdevt, 0);
00208             printf("[EVT%u]", player.psi_status);
00209             if (player.psi_status == PSI_START)
00210                 break;
00211         }
00212 
00213         /* Broadcast running event. */
00214         printf("[RUN]");
00215         player.psi_status = PSI_RUNNING;
00216         player.psi_mp3left = player.psi_metaint;
00217         NutEventBroadcast(&player.psi_stsevt);
00218 
00219         /* Reset decoder buffer. */
00220         ief = VsPlayerInterrupts(0);
00221         NutSegBufReset();
00222         VsPlayerInterrupts(ief);
00223 
00224         /*
00225          * Running loop.
00226          */
00227         while (player.psi_status == PSI_RUNNING) {
00228 
00229             /*
00230              * Query number of byte available in MP3 buffer. If it is
00231              * zero, then the player may have stopped running.
00232              */
00233             ief = VsPlayerInterrupts(0);
00234             mp3buf = NutSegBufWriteRequest(&rbytes);
00235             VsPlayerInterrupts(ief);
00236             if (rbytes < 1024) {
00237                 if (VsGetStatus() != VS_STATUS_RUNNING)
00238                     VsPlayerKick();
00239                 if (rbytes == 0) {
00240                     NutSleep(125);
00241                     continue;
00242                 }
00243             }
00244 
00245             /* Do not read pass metadata. */
00246             if (player.psi_metaint && rbytes > player.psi_mp3left)
00247                 rbytes = player.psi_mp3left;
00248 
00249             /*
00250              * Loop until MP3 buffer space is filled.
00251              */
00252             while (rbytes) {
00253 
00254                 /* Read data directly into the MP3 buffer. */
00255                 if ((got = NutTcpReceive(player.psi_sock, mp3buf, rbytes)) < 0) {
00256                     /* This is fatal. Return to idle state. */
00257                     printf("[RXFAIL]");
00258                     player.psi_status = PSI_IDLE;
00259                     break;
00260                 }
00261 
00262                 /* 
00263                  * Got some MP3 data. 
00264                  */
00265                 if (got) {
00266                     /* Commit the buffer. */
00267                     ief = VsPlayerInterrupts(0);
00268                     mp3buf = NutSegBufWriteCommit(got);
00269                     VsPlayerInterrupts(ief);
00270 
00271                     /* Reset timeout counter and reduce number of buffer bytes. */
00272                     to_cnt = 0;
00273                     rbytes -= got;
00274 
00275                     /* Process meta data. */
00276                     if (player.psi_metaint) {
00277                         player.psi_mp3left -= got;
00278                         if (player.psi_mp3left == 0) {
00279                             if (ProcessMetaData()) {
00280                                 printf("[METAFAIL]");
00281                                 //player.psi_status = PSI_IDLE;
00282                                 //break;
00283                             }
00284                             player.psi_mp3left = player.psi_metaint;
00285                         }
00286                     }
00287 
00288                     /* Start early with large buffers. */
00289                     if (VsGetStatus() != VS_STATUS_RUNNING) {
00290                         ief = VsPlayerInterrupts(0);
00291                         if ((NutSegBufUsed() > 2048 && player.psi_start) ||
00292                             (NutSegBufUsed() > BIGBUF_WATERMARK && NutSegBufAvailable() < BIGBUF_WATERMARK))
00293                             VsPlayerKick();
00294                         else
00295                             VsPlayerInterrupts(ief);
00296                     }
00297                     player.psi_start = 0;
00298                 }
00299 
00300                 /*
00301                  * Got no MP3 data. 
00302                  */
00303                 else {
00304                     printf("[T%u, %u]", to_cnt, NutHeapAvailable());
00305                     NutSleep(100);
00306                     if (to_cnt++ > MAX_WAITSTREAM) {
00307                         /* If timeouts reach our limit, go back to idle state. */
00308                         printf("[RXTO]");
00309                         player.psi_status = PSI_IDLE;
00310                         break;
00311                     }
00312                 }
00313 
00314                 /*
00315                  * If we won't yield the CPU, we may consume the complete
00316                  * TCP buffer before being stopped in NutTcpReceive. That
00317                  * would result in bumpy feeding.
00318                  */
00319                 NutThreadYield();
00320             }
00321 
00322             /* If play loop is not entered, we may omit the watchdog 
00323                update here and force a system reset. */
00324             NutThreadYield();
00325         }
00326         /* Flush decoder and wait until finished. */
00327         printf("[FLUSH]");
00328         VsPlayerFlush();
00329         while (VsGetStatus() == VS_STATUS_RUNNING) {
00330             NutSleep(63);
00331         }
00332 
00333         /* Reset the decoder. */
00334         printf("[RESET]");
00335         VsPlayerReset(0);
00336     }
00337 }
00338 
00345 int PlayerInit(void)
00346 {
00347     /* Init decoder. */
00348     if (VsPlayerInit() || VsPlayerReset(0))
00349         return -1;
00350 
00351     /* Start player thread. */
00352     if (NutThreadCreate("player", Player, 0, 512) == 0)
00353         return -1;
00354 
00355     return 0;
00356 }
00357 
00363 int PlayerStop(u_long tmo)
00364 {
00365     while (player.psi_status != PSI_IDLE) {
00366         printf("[STOP]");
00367         player.psi_status = PSI_STOP;
00368         NutEventPost(&player.psi_cmdevt);
00369         if (NutEventWait(&player.psi_stsevt, tmo)) {
00370             printf("[TOP]");
00371             return -1;
00372         }
00373     }
00374     printf("[STOPPED]");
00375     return 0;
00376 }
00377 
00383 int PlayerStart(TCPSOCKET * sock, u_long metaint, u_long tmo)
00384 {
00385     if (PlayerStop(tmo))
00386         return -1;
00387 
00388     /* Clear event queue and send start command. */
00389     NutEventBroadcast(&player.psi_stsevt);
00390     printf("[START]");
00391     player.psi_status = PSI_START;
00392     player.psi_sock = sock;
00393     player.psi_metaint = metaint;
00394     NutEventPost(&player.psi_cmdevt);
00395 
00396     /* The next event will be the result of our start command. */
00397     if (NutEventWait(&player.psi_stsevt, tmo) || player.psi_status != PSI_RUNNING) {
00398         printf("[TOS]");
00399         return -1;
00400     }
00401     return 0;
00402 }
00403 
00404 #endif /* __AVR__ */

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/