player.c

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

© 2000-2010 by contributors - visit http://www.ethernut.de/