📄 player.c
字号:
/* * Copyright (C) 2003 by egnite Software GmbH. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ * *//*! * $Log: player.c,v $ * Revision 1.2 2003/09/29 16:34:26 haraldkipp * Include file sequence changed * * Revision 1.1 2003/07/21 17:50:48 haraldkipp * First check in * */#include <sys/heap.h>#include <sys/event.h>#include <sys/timer.h>#include <sys/thread.h>#include <dev/vs1001k.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#include "player.h"#include <sys/bankmem.h>#define MAX_WAITSTREAM 20#define BIGBUF_WATERMARK 65535ULPLAYERINFO player;/* * Process embedded meta data. */static void ClearMetaData(void){ if (player.psi_metatitle) { free(player.psi_metatitle); player.psi_metatitle = 0; } if (player.psi_metaurl) { free(player.psi_metaurl); player.psi_metaurl = 0; }}/* * Process embedded meta data. */static int ProcessMetaData(void){ u_char blks = 0; u_short cnt; int got; int rc = 0; u_char to_cnt = 0; u_char *mbuf; u_char *mn1; u_char *mn2; u_char *md1; u_char *md2; /* * Wait for the lenght byte. */ while (player.psi_status == PSI_RUNNING) { if ((got = NutTcpReceive(player.psi_sock, &blks, 1)) == 1) break; if (got < 0 || to_cnt++ > MAX_WAITSTREAM) { printf("[NoLen]"); return -1; } } if (blks) { if (blks > 32) { printf("[Blks=%u]", blks); return -1; } cnt = blks * 16; if ((mbuf = malloc(cnt + 1)) == 0) { printf("[NoMem]"); return -1; } /* * Receive the metadata block. */ while (player.psi_status == PSI_RUNNING) { if ((got = NutTcpReceive(player.psi_sock, mbuf + rc, cnt)) < 0) { printf("[RxFail]"); return -1; } if (got) { to_cnt = 0; if ((cnt -= got) == 0) break; rc += got; mbuf[rc] = 0; } else if (to_cnt++ > MAX_WAITSTREAM) { printf("[RxTo]"); return -1; } } ClearMetaData(); printf("\nMeta='%s'\n", mbuf); mn1 = mbuf; while (mn1) { if ((mn2 = strchr(mn1, ';')) != 0) *mn2++ = 0; if ((md1 = strchr(mn1, '=')) != 0) { *md1++ = 0; while (*md1 == ' ' || *md1 == '\'') md1++; if ((md2 = strrchr(md1, '\'')) != 0) *md2 = 0; if (strcasecmp(mn1, "StreamTitle") == 0 && player.psi_metatitle == 0) { player.psi_metatitle = malloc(strlen(md1) + 1); strcpy(player.psi_metatitle, md1); } else if (strcasecmp(mn1, "StreamUrl") == 0 && player.psi_metaurl == 0) { player.psi_metaurl = malloc(strlen(md1) + 1); strcpy(player.psi_metaurl, md1); } } mn1 = mn2; } free(mbuf); player.psi_metaupdate = 1; } return 0;}/* * Background thread for playing stream. */THREAD(Player, arg){ size_t rbytes; u_char *mp3buf; u_char to_cnt = 0; int got; u_char ief; /* * Nut/OS threads run forever. */ for (;;) { /* * Idle loop. */ for (;;) { /* Broadcast idle status. */ printf("[IDLE]"); ClearMetaData(); player.psi_status = PSI_IDLE; NutEventBroadcast(&player.psi_stsevt); /* Wait for start event. */ NutEventWait(&player.psi_cmdevt, 0); printf("[EVT%u]", player.psi_status); if (player.psi_status == PSI_START) break; } /* Broadcast running event. */ printf("[RUN]"); player.psi_status = PSI_RUNNING; player.psi_mp3left = player.psi_metaint; NutEventBroadcast(&player.psi_stsevt); /* Reset decoder buffer. */ ief = VsPlayerInterrupts(0); NutSegBufReset(); VsPlayerInterrupts(ief); /* * Running loop. */ while (player.psi_status == PSI_RUNNING) { /* * Query number of byte available in MP3 buffer. If it is * zero, then the player may have stopped running. */ ief = VsPlayerInterrupts(0); mp3buf = NutSegBufWriteRequest(&rbytes); VsPlayerInterrupts(ief); if (rbytes < 1024) { if (VsGetStatus() != VS_STATUS_RUNNING) VsPlayerKick(); if (rbytes == 0) { NutSleep(125); continue; } } /* Do not read pass metadata. */ if (player.psi_metaint && rbytes > player.psi_mp3left) rbytes = player.psi_mp3left; /* * Loop until MP3 buffer space is filled. */ while (rbytes) { /* Read data directly into the MP3 buffer. */ if ((got = NutTcpReceive(player.psi_sock, mp3buf, rbytes)) < 0) { /* This is fatal. Return to idle state. */ printf("[RXFAIL]"); player.psi_status = PSI_IDLE; break; } /* * Got some MP3 data. */ if (got) { /* Commit the buffer. */ ief = VsPlayerInterrupts(0); mp3buf = NutSegBufWriteCommit(got); VsPlayerInterrupts(ief); /* Reset timeout counter and reduce number of buffer bytes. */ to_cnt = 0; rbytes -= got; /* Process meta data. */ if (player.psi_metaint) { player.psi_mp3left -= got; if (player.psi_mp3left == 0) { if (ProcessMetaData()) { printf("[METAFAIL]"); //player.psi_status = PSI_IDLE; //break; } player.psi_mp3left = player.psi_metaint; } } /* Start early with large buffers. */ if (VsGetStatus() != VS_STATUS_RUNNING) { ief = VsPlayerInterrupts(0); if ((NutSegBufUsed() > 2048 && player.psi_start) || (NutSegBufUsed() > BIGBUF_WATERMARK && NutSegBufAvailable() < BIGBUF_WATERMARK)) VsPlayerKick(); else VsPlayerInterrupts(ief); } player.psi_start = 0; } /* * Got no MP3 data. */ else { printf("[T%u, %u]", to_cnt, NutHeapAvailable()); NutSleep(100); if (to_cnt++ > MAX_WAITSTREAM) { /* If timeouts reach our limit, go back to idle state. */ printf("[RXTO]"); player.psi_status = PSI_IDLE; break; } } /* * If we won't yield the CPU, we may consume the complete * TCP buffer before being stopped in NutTcpReceive. That * would result in bumpy feeding. */ NutThreadYield(); } /* If play loop is not entered, we may omit the watchdog update here and force a system reset. */ NutThreadYield(); } /* Flush decoder and wait until finished. */ printf("[FLUSH]"); VsPlayerFlush(); while (VsGetStatus() == VS_STATUS_RUNNING) { NutSleep(63); } /* Reset the decoder. */ printf("[RESET]"); VsPlayerReset(0); }}/*! * \brief Initialize the MP3 player. * * Initializes the decoder and the decoder buffer and starts the * player background thread. */int PlayerInit(void){ /* Init decoder. */ if (VsPlayerInit() || VsPlayerReset(0)) return -1; /* Start player thread. */ if (NutThreadCreate("player", Player, 0, 512) == 0) return -1; return 0;}/*! * \brief Stop MP3 player. * * Force player into idle mode. */int PlayerStop(u_long tmo){ while (player.psi_status != PSI_IDLE) { printf("[STOP]"); player.psi_status = PSI_STOP; NutEventPost(&player.psi_cmdevt); if (NutEventWait(&player.psi_stsevt, tmo)) { printf("[TOP]"); return -1; } } printf("[STOPPED]"); return 0;}/*! * \brief Start MP3 player. * * If the player is currently running, it will be stopped first. */int PlayerStart(TCPSOCKET * sock, u_long metaint, u_long tmo){ if (PlayerStop(tmo)) return -1; /* Clear event queue and send start command. */ NutEventBroadcast(&player.psi_stsevt); printf("[START]"); player.psi_status = PSI_START; player.psi_sock = sock; player.psi_metaint = metaint; NutEventPost(&player.psi_cmdevt); /* The next event will be the result of our start command. */ if (NutEventWait(&player.psi_stsevt, tmo) || player.psi_status != PSI_RUNNING) { printf("[TOS]"); return -1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -