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 
00049 #include <sys/heap.h>
00050 #include <sys/event.h>
00051 #include <sys/timer.h>
00052 #include <sys/thread.h>
00053 
00054 #include <dev/vs1001k.h>
00055 
00056 #include <stdlib.h>
00057 #include <string.h>
00058 #include <stdio.h>
00059 
00060 #include "player.h"
00061 #include <sys/bankmem.h>
00062 
00063 #define MAX_WAITSTREAM      20
00064 #define BIGBUF_WATERMARK    65535UL
00065 
00066 
00067 PLAYERINFO player;
00068 
00069 #if defined(__AVR__)
00070 
00071 /*
00072  * Process embedded meta data.
00073  */
00074 static void ClearMetaData(void)
00075 {
00076     if (player.psi_metatitle) {
00077         free(player.psi_metatitle);
00078         player.psi_metatitle = 0;
00079     }
00080     if (player.psi_metaurl) {
00081         free(player.psi_metaurl);
00082         player.psi_metaurl = 0;
00083     }
00084 }
00085 
00086 /*
00087  * Process embedded meta data.
00088  */
00089 static int ProcessMetaData(void)
00090 {
00091     u_char blks = 0;
00092     u_short cnt;
00093     int got;
00094     int rc = 0;
00095     u_char to_cnt = 0;
00096     u_char *mbuf;
00097     u_char *mn1;
00098     u_char *mn2;
00099     u_char *md1;
00100     u_char *md2;
00101 
00102     /*
00103      * Wait for the lenght byte.
00104      */
00105     while (player.psi_status == PSI_RUNNING) {
00106         if ((got = NutTcpReceive(player.psi_sock, &blks, 1)) == 1)
00107             break;
00108         if (got < 0 || to_cnt++ > MAX_WAITSTREAM) {
00109             printf("[NoLen]");
00110             return -1;
00111         }
00112     }
00113     if (blks) {
00114         if (blks > 32) {
00115             printf("[Blks=%u]", blks);
00116             return -1;
00117         }
00118 
00119         cnt = blks * 16;
00120         if ((mbuf = malloc(cnt + 1)) == 0) {
00121             printf("[NoMem]");
00122             return -1;
00123         }
00124 
00125         /*
00126          * Receive the metadata block.
00127          */
00128         while (player.psi_status == PSI_RUNNING) {
00129             if ((got = NutTcpReceive(player.psi_sock, mbuf + rc, cnt)) < 0) {
00130                 printf("[RxFail]");
00131                 return -1;
00132             }
00133             if (got) {
00134                 to_cnt = 0;
00135                 if ((cnt -= got) == 0)
00136                     break;
00137                 rc += got;
00138                 mbuf[rc] = 0;
00139             } else if (to_cnt++ > MAX_WAITSTREAM) {
00140                 printf("[RxTo]");
00141                 return -1;
00142             }
00143         }
00144 
00145         ClearMetaData();
00146         printf("\nMeta='%s'\n", mbuf);
00147         mn1 = mbuf;
00148         while (mn1) {
00149             if ((mn2 = strchr(mn1, ';')) != 0)
00150                 *mn2++ = 0;
00151             if ((md1 = strchr(mn1, '=')) != 0) {
00152                 *md1++ = 0;
00153                 while (*md1 == ' ' || *md1 == '\'')
00154                     md1++;
00155                 if ((md2 = strrchr(md1, '\'')) != 0)
00156                     *md2 = 0;
00157                 if (strcasecmp(mn1, "StreamTitle") == 0 && player.psi_metatitle == 0) {
00158                     player.psi_metatitle = malloc(strlen(md1) + 1);
00159                     strcpy(player.psi_metatitle, md1);
00160                 } else if (strcasecmp(mn1, "StreamUrl") == 0 && player.psi_metaurl == 0) {
00161                     player.psi_metaurl = malloc(strlen(md1) + 1);
00162                     strcpy(player.psi_metaurl, md1);
00163                 }
00164             }
00165             mn1 = mn2;
00166         }
00167         free(mbuf);
00168         player.psi_metaupdate = 1;
00169     }
00170     return 0;
00171 }
00172 
00173 
00174 /*
00175  * Background thread for playing stream.
00176  */
00177 THREAD(Player, arg)
00178 {
00179     size_t rbytes;
00180     u_char *mp3buf;
00181     u_char to_cnt = 0;
00182     int got;
00183     u_char ief;
00184 
00185     /*
00186      * Nut/OS threads run forever.
00187      */
00188     for (;;) {
00189         /*
00190          * Idle loop.
00191          */
00192         for (;;) {
00193             /* Broadcast idle status. */
00194             printf("[IDLE]");
00195             ClearMetaData();
00196             player.psi_status = PSI_IDLE;
00197             NutEventBroadcast(&player.psi_stsevt);
00198 
00199             /* Wait for start event. */
00200             NutEventWait(&player.psi_cmdevt, 0);
00201             printf("[EVT%u]", player.psi_status);
00202             if (player.psi_status == PSI_START)
00203                 break;
00204         }
00205 
00206         /* Broadcast running event. */
00207         printf("[RUN]");
00208         player.psi_status = PSI_RUNNING;
00209         player.psi_mp3left = player.psi_metaint;
00210         NutEventBroadcast(&player.psi_stsevt);
00211 
00212         /* Reset decoder buffer. */
00213         ief = VsPlayerInterrupts(0);
00214         NutSegBufReset();
00215         VsPlayerInterrupts(ief);
00216 
00217         /*
00218          * Running loop.
00219          */
00220         while (player.psi_status == PSI_RUNNING) {
00221 
00222             /*
00223              * Query number of byte available in MP3 buffer. If it is
00224              * zero, then the player may have stopped running.
00225              */
00226             ief = VsPlayerInterrupts(0);
00227             mp3buf = NutSegBufWriteRequest(&rbytes);
00228             VsPlayerInterrupts(ief);
00229             if (rbytes < 1024) {
00230                 if (VsGetStatus() != VS_STATUS_RUNNING)
00231                     VsPlayerKick();
00232                 if (rbytes == 0) {
00233                     NutSleep(125);
00234                     continue;
00235                 }
00236             }
00237 
00238             /* Do not read pass metadata. */
00239             if (player.psi_metaint && rbytes > player.psi_mp3left)
00240                 rbytes = player.psi_mp3left;
00241 
00242             /*
00243              * Loop until MP3 buffer space is filled.
00244              */
00245             while (rbytes) {
00246 
00247                 /* Read data directly into the MP3 buffer. */
00248                 if ((got = NutTcpReceive(player.psi_sock, mp3buf, rbytes)) < 0) {
00249                     /* This is fatal. Return to idle state. */
00250                     printf("[RXFAIL]");
00251                     player.psi_status = PSI_IDLE;
00252                     break;
00253                 }
00254 
00255                 /* 
00256                  * Got some MP3 data. 
00257                  */
00258                 if (got) {
00259                     /* Commit the buffer. */
00260                     ief = VsPlayerInterrupts(0);
00261                     mp3buf = NutSegBufWriteCommit(got);
00262                     VsPlayerInterrupts(ief);
00263 
00264                     /* Reset timeout counter and reduce number of buffer bytes. */
00265                     to_cnt = 0;
00266                     rbytes -= got;
00267 
00268                     /* Process meta data. */
00269                     if (player.psi_metaint) {
00270                         player.psi_mp3left -= got;
00271                         if (player.psi_mp3left == 0) {
00272                             if (ProcessMetaData()) {
00273                                 printf("[METAFAIL]");
00274                                 //player.psi_status = PSI_IDLE;
00275                                 //break;
00276                             }
00277                             player.psi_mp3left = player.psi_metaint;
00278                         }
00279                     }
00280 
00281                     /* Start early with large buffers. */
00282                     if (VsGetStatus() != VS_STATUS_RUNNING) {
00283                         ief = VsPlayerInterrupts(0);
00284                         if ((NutSegBufUsed() > 2048 && player.psi_start) ||
00285                             (NutSegBufUsed() > BIGBUF_WATERMARK && NutSegBufAvailable() < BIGBUF_WATERMARK))
00286                             VsPlayerKick();
00287                         else
00288                             VsPlayerInterrupts(ief);
00289                     }
00290                     player.psi_start = 0;
00291                 }
00292 
00293                 /*
00294                  * Got no MP3 data. 
00295                  */
00296                 else {
00297                     printf("[T%u, %u]", to_cnt, NutHeapAvailable());
00298                     NutSleep(100);
00299                     if (to_cnt++ > MAX_WAITSTREAM) {
00300                         /* If timeouts reach our limit, go back to idle state. */
00301                         printf("[RXTO]");
00302                         player.psi_status = PSI_IDLE;
00303                         break;
00304                     }
00305                 }
00306 
00307                 /*
00308                  * If we won't yield the CPU, we may consume the complete
00309                  * TCP buffer before being stopped in NutTcpReceive. That
00310                  * would result in bumpy feeding.
00311                  */
00312                 NutThreadYield();
00313             }
00314 
00315             /* If play loop is not entered, we may omit the watchdog 
00316                update here and force a system reset. */
00317             NutThreadYield();
00318         }
00319         /* Flush decoder and wait until finished. */
00320         printf("[FLUSH]");
00321         VsPlayerFlush();
00322         while (VsGetStatus() == VS_STATUS_RUNNING) {
00323             NutSleep(63);
00324         }
00325 
00326         /* Reset the decoder. */
00327         printf("[RESET]");
00328         VsPlayerReset(0);
00329     }
00330 }
00331 
00338 int PlayerInit(void)
00339 {
00340     /* Init decoder. */
00341     if (VsPlayerInit() || VsPlayerReset(0))
00342         return -1;
00343 
00344     /* Start player thread. */
00345     if (NutThreadCreate("player", Player, 0, 512) == 0)
00346         return -1;
00347 
00348     return 0;
00349 }
00350 
00356 int PlayerStop(u_long tmo)
00357 {
00358     while (player.psi_status != PSI_IDLE) {
00359         printf("[STOP]");
00360         player.psi_status = PSI_STOP;
00361         NutEventPost(&player.psi_cmdevt);
00362         if (NutEventWait(&player.psi_stsevt, tmo)) {
00363             printf("[TOP]");
00364             return -1;
00365         }
00366     }
00367     printf("[STOPPED]");
00368     return 0;
00369 }
00370 
00376 int PlayerStart(TCPSOCKET * sock, u_long metaint, u_long tmo)
00377 {
00378     if (PlayerStop(tmo))
00379         return -1;
00380 
00381     /* Clear event queue and send start command. */
00382     NutEventBroadcast(&player.psi_stsevt);
00383     printf("[START]");
00384     player.psi_status = PSI_START;
00385     player.psi_sock = sock;
00386     player.psi_metaint = metaint;
00387     NutEventPost(&player.psi_cmdevt);
00388 
00389     /* The next event will be the result of our start command. */
00390     if (NutEventWait(&player.psi_stsevt, tmo) || player.psi_status != PSI_RUNNING) {
00391         printf("[TOS]");
00392         return -1;
00393     }
00394     return 0;
00395 }
00396 
00397 #endif /* __AVR__ */

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