Files
C-RK/week 4/player.c
T
2016-03-30 22:54:22 +02:00

345 lines
6.7 KiB
C

#define LOG_MODULE LOG_PLAYER_MODULE
#include <stdio.h>
#include <string.h>
#include <sys/thread.h>
#include <sys/timer.h>
#include <sys/version.h>
#include <dev/irqreg.h>
#include <arpa/inet.h>
#include <net/route.h>
#include <pro/dhcp.h>
#include <pro/sntp.h>
#include <sys/confnet.h>
#include <dev/board.h>
#include <pro/httpd.h>
#include <pro/asp.h>
#include <pro/discover.h>
#include <dev/nicrtl.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include "player.h"
#include "vs10xx.h"
#include "streamer.h"
#include "settings.h"
#include <sys/bankmem.h>
#define OK 1
#define NOK 0
int stopped = 1;
int stopstream = 0;
char* MetaData;
int initPlayer(void)
{
MetaData = (char *) calloc(128, sizeof(char));
SetBass(GetBass());
SetTreble(GetTreble());
SetVolume(GetVolume());
return OK;
}
char* GetMetaData(void)
{
return MetaData;
}
int isStreaming()
{
return !stopped;
}
int ProcessMetaData(FILE *stream)
{
u_char blks = 0;
u_short cnt;
int got;
int rc = 0;
u_char *mbuf;
/*
* Wait for the lenght byte.
*/
got = fread(&blks, 1, 1, stream);
if(got != 1) {
return -1;
}
if (blks) {
if (blks > 32) {
printf("[PLAYER] Error: Metadata too large, %u blocks\n", blks);
return -1;
}
cnt = blks * 16;
if ((mbuf = malloc(cnt + 1)) == 0) {
return -1;
}
/*
* Receive the metadata block.
*/
for (;;) {
if ((got = fread(mbuf + rc, 1, cnt, stream)) <= 0) {
return -1;
}
if ((cnt -= got) == 0) {
break;
}
rc += got;
mbuf[rc] = 0;
}
memset(&MetaData[0], 0, sizeof(MetaData));
int count = 0;
int copy = 0;
int startval = 0;
int stopval = 0;
for(;;)
{
if(mbuf[count] == '\'' && copy == 1)
{
copy = 0;
stopval = count-1;
break;
}
if(mbuf[count] == '\'' && copy == 0)
{
startval = count+1;
copy = 1;
}
count++;
}
int len = stopval - startval;
len = len > 127 ? 127 : len;
strncpy(MetaData, (char*) &mbuf[startval], len);
free(mbuf);
}
return 0;
}
int stop(void)
{
if(stopped == 1)
return 0;
printf("[PLAYER] Stopping other stream\n");
stopstream = 1;
while(!stopped) { NutSleep(5); };
printf("[PLAYER] Stream stopped\n");
//Give thread time to clean up
NutSleep(100);
strcpy(MetaData, "");
return 1;
}
int play(u_long ip, u_short port, u_char *path)
{
stop(); //Stop any old threads
FILE *stream;
TCPSOCKET *sock = 0;
u_long metaint;
stream = ConnectStation(sock, ip, port, path, &metaint); //Connect to a stream
if(!stream)
{
printf("[PLAYER] Not stream\n");
return NOK;
}
//Package 3 variables in a struct to pass them to the thread.
StreamData *arguments = malloc(sizeof(StreamData));
arguments->stream = stream;
arguments->sock = sock;
arguments->metaint = metaint;
//Start thread with packaged arguments
NutThreadCreate("Streamer", StreamPlayer, arguments, 512);
//Await thread start
NutSleep(20);
//Clear the packege
free(arguments);
return OK;
}
THREAD(StreamPlayer, arg)
{
NutThreadSetPriority(1); // high prio
printf("[PLAYER] Play thread created. Device is playing stream now !\n");
StreamData* f = (StreamData *) arg;
FILE* stream = f->stream;
TCPSOCKET* sock = f->sock;
u_long metaint = f->metaint;
size_t rbytes;
u_char *mp3buf;
u_char ief;
int got = 0;
u_long last;
u_long mp3left = metaint;
int endstream = 0;
/*
* Initialize the MP3 buffer. The NutSegBuf routines provide a global
* system buffer, which works with banked and non-banked systems.
*/
if (NutSegBufInit(8192) == 0) {
printf("[PLAYER] Error: MP3 buffer init failed\n");
NutThreadExit();
}
/*
* Initialize the MP3 decoder hardware.
*/
if (VsPlayerReset(0)) {
printf("[PLAYER] Error: MP3 hardware init failed\n");
NutThreadExit();
}
stopped = 0;
/*
* Reset the MP3 buffer.
*/
ief = VsPlayerInterrupts(0);
NutSegBufReset();
VsPlayerInterrupts(ief);
last = NutGetSeconds();
for (;;) {
if(stopstream)
{
break;
}
/*
* Query number of byte available in MP3 buffer.
*/
ief = VsPlayerInterrupts(0);
mp3buf = (u_char*) NutSegBufWriteRequest(&rbytes);
VsPlayerInterrupts(ief);
/*
* If the player is not running, kick it.
*/
if (VsGetStatus() != VS_STATUS_RUNNING) {
printf("[PLAYER] Not running\n");
if(rbytes < 1024 || NutGetSeconds() - last > 4UL) {
last = NutGetSeconds();
printf("[PLAYER] Kick player\n");
VsPlayerKick();
}
}
/*
* Do not read pass metadata.
*/
if (metaint && rbytes > mp3left) {
rbytes = mp3left;
}
/*
* Read data directly into the MP3 buffer.
*/
while (rbytes) {
if ((got = fread(mp3buf, 1, rbytes, stream)) > 0) {
ief = VsPlayerInterrupts(0);
mp3buf = (u_char *) NutSegBufWriteCommit(got);
VsPlayerInterrupts(ief);
if (metaint) {
mp3left -= got;
if (mp3left == 0) {
ProcessMetaData(stream);
mp3left = metaint;
}
}
if(got < rbytes && got < 512) {
//printf("%lu buffered\n", NutSegBufUsed());
NutSleep(250);
}
else {
NutThreadYield();
}
} else {
printf("[PLAYER] Failed to read from stream, closing\n");
break;
}
rbytes -= got;
}
if(got <= 0) {
endstream++;
printf("[PLAYER] Stream ending, %d tries left\n", 3 - endstream);
if(endstream >= 3)
{
printf("[PLAYER] End of stream, closing\n");
break;
}
}
else
endstream = 0;
}
VsPlayerStop(); //Stop the audio
while (VsGetStatus() == VS_STATUS_RUNNING) {
NutSleep(50); //Wait until player has really stopped
}
fclose(stream); //Close stream
NutTcpCloseSocket(sock); //Close socket
strcpy(MetaData, ""); //Clear meta data
stopstream = 0; //Clear stop flag
stopped = 1; //Mark thread as stopped
printf("[PLAYER] End of play thread\n");
NutThreadExit(); //Clean up thread and exit
for(;;)
{
printf("[PLAYER] PLAY THREAD NOT STOPPED\n");
NutThreadYield();
}
}