| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- //
- // Created by Jordy Sipkema on 28/03/16.
- //
- #include "mp3stream.h"
- #include <arpa/inet.h>
- #include <sys/bankmem.h>
- #include <sys/heap.h>
- #include <sys/thread.h>
- #include <sys/timer.h>
- #include "displayHandler.h"
- #include "vs10xx.h"
- #define OK 1
- #define NOK 0
- #define DEFAULT_VOLUME 7
- #define STREAMINFO_BUFF 48
- #define MSIZE 1024
- #define NUTSEGBUFFER 4096
- typedef struct _StreamArgs {
- FILE *stream;
- } TStreamArgs;
- // Prototypes - Functions for internal use only! (They wont be visible outside this file!)
- THREAD(Mp3Player, args);
- void stopMp3PlayerThread(void);
- int ProcessStreamMetaData(FILE *stream);
- // Variables
- static bool stream_isplaying = false;
- static bool stream_connected = false;
- static bool stream_stopped = false;
- static u_char VS_volume = DEFAULT_VOLUME; //[0-16]; (Default volume = 7/16
- static u_long metaInt = 0;
- static char VS_StreamInfo[STREAMINFO_BUFF] = " No info ";
- static char ScrollOffset = 0;
- FILE *stream;
- TCPSOCKET *socket;
- bool connectToStream(char *ipaddr, u_short port, char *radioUrl)
- {
- if (stream_connected == true)
- return false;
- stream_connected = false;
- bool result = true;
- char* data;
- socket = NutTcpCreateSocket();
- printf("Connecting to %s:%d%s\r\n", ipaddr, port, radioUrl);
- if (NutTcpConnect(socket, inet_addr(ipaddr), port))
- {
- // An error has occurred.
- printf("ConnectToStream: Error creating tcp socket.\n");
- NutSleep(5000);
- result = false;
- return result;
- }
- stream = _fdopen((int)socket, "r+b");
- fprintf(stream, "GET %s HTTP/1.0\r\n", radioUrl);
- fprintf(stream, "Host: %s\r\n", ipaddr);
- fprintf(stream, "User-Agent: Ethernut\r\n");
- fprintf(stream, "Accept: */*\r\n");
- fprintf(stream, "Icy-MetaData: 1\r\n");
- fprintf(stream, "Connection: close\r\n\r\n");
- fflush(stream);
- // Server will respond with a HTTP-header. Fetch it to the buffer.
- stream_connected = true;
- stream_stopped = false;
- data = (char *)malloc(MSIZE * sizeof(char));
- while (fgets(data, MSIZE, stream))
- {
- /*
- * Chop off the carriage return at the end of the line. If none
- * was found, then this line was probably too large for our buffer.
- */
- char *cp = strchr(data, '\r');
- if (cp == 0) continue; // Input buffer overflow.
- *cp = 0;
- /*
- * The header is terminated by an empty line.
- */
- if (*data == 0) break;
- if (strncmp(data, "icy-metaint:", 12) == 0)
- metaInt = atol(data + 12);
- printf("%s\n", data);
- }
- free(data);
- return result;
- }
- bool play()
- {
- if (stream_connected == false)
- return false;
- if (stream_isplaying == true)
- return false;
- // else:
- stream_isplaying == true;
- TStreamArgs *streamArgs = &(TStreamArgs){
- .stream = stream,
- //.metaint = metaInt
- };
- NutThreadCreate("Mp3Player", Mp3Player, streamArgs, 512);
- printf("Mp3Player thread created. Device should start playing the stream.\n");
- return true;
- }
- void volumeUp(void)
- {
- if (VS_volume >= 16)
- return VS_volume;
- //else:
- ++VS_volume;
- VS_volume = VS_volume % 17;
- setVolume();
- }
- void volumeDown(void)
- {
- if (VS_volume <= 0)
- return VS_volume;
- //else:
- --VS_volume;
- VS_volume = VS_volume % 17;
- setVolume();
- }
- void setVolumeManual(char level){
- u_char v_level = level * 16 / 100;
- VS_volume = v_level % 17;
- setVolume();
- setCurrentDisplay(DISPLAY_Volume, 5);
- }
- void setVolume(void){
- u_char volumeToSet = (128 - (VS_volume * 8)) % 129;
- VsSetVolume(volumeToSet, volumeToSet);
- printf("- VS_volume level: %d/16\n", VS_volume);
- }
- u_char getVolume(void){
- return VS_volume;
- }
- char* getStreamInfo(void){
- return VS_StreamInfo;
- }
- void killPlayerThread(void)
- {
- printf("Signal to stop the stream sent.\n");
- stream_stopped = true;
- }
- THREAD(Mp3Player, args)
- //void function(void* args) //TODO: REMOVE THIS, THIS IS ONLY TO TRICK CLION!
- {
- // Unpack the args passed to the thread initializer.
- TStreamArgs *streamArgs = (TStreamArgs *)args;
- FILE *stream = streamArgs->stream;
- int result = NOK;
- size_t rbytes = 0;
- char *mp3buf;
- u_char ief;
- int got = 0;
- u_long mp3left = metaInt;
- // Init MP3-buffer. NutSegBuf is a global system buffer.
- if (0 != NutSegBufInit(NUTSEGBUFFER)){
- // Reset the global buffer.
- ief = VsPlayerInterrupts(0);
- NutSegBufReset();
- VsPlayerInterrupts(ief);
- result = OK;
- }
- // Init the VS1003b hardware.
- if (result == OK){
- if (-1 == VsPlayerInit()) {
- if (-1 == VsPlayerReset(0)){
- result = NOK;
- }
- }
- }
- // Set the volume to the correct level
- setVolume();
- for(;;)
- {
- /*
- * Query the number of bytes available in the MP3 buffer.
- */
- ief = VsPlayerInterrupts(0);
- mp3buf = NutSegBufWriteRequest(&rbytes);
- VsPlayerInterrupts(ief);
- /*
- * If the player is not running, kick it.
- * This should only occur once.
- */
- if (VsGetStatus() != VS_STATUS_RUNNING) {
- puts("Player not running.");
- if (rbytes < 1024){
- puts("Kick player in 3 2 1..:");
- VsPlayerKick();
- }
- }
- /*
- * Do not read pass metadata.
- * This causes ugly hiccups.
- */
- if (metaInt && rbytes > mp3left){
- rbytes = mp3left;
- }
- /*
- * Read directly into the MP3 buffer.
- */
- while (rbytes) {
- if (stream_stopped == true) {
- stopMp3PlayerThread();
- }
- if ((got = fread(mp3buf, 1, rbytes, stream)) > 0) {
- ief = VsPlayerInterrupts(0);
- mp3buf = NutSegBufWriteCommit(got);
- VsPlayerInterrupts(ief);
- if (metaInt) {
- mp3left -= got;
- if (mp3left == 0) {
- ProcessStreamMetaData(stream);
- mp3left = metaInt;
- }
- }
- if (got < rbytes && got < 512) {
- printf("%lu buffered\n", NutSegBufUsed());
- NutSleep(250);
- }
- else {
- NutThreadYield();
- }
- } else {
- break;
- }
- rbytes -= got;
- }
- if (got <= 0) break;
- } // end for(;;)
- while (NutSegBufUsed() > 10){
- NutSleep(250);
- }
- stopMp3PlayerThread();
- }
- void stopMp3PlayerThread(void)
- {
- printf("Signal to stop the stream recieved\n.");
- stream_connected = false;
- stream_isplaying = false;
- VsPlayerStop();
- NutTcpCloseSocket(socket);
- NutThreadExit();
- }
- char getScrollOffset(void){
- return ScrollOffset;
- }
- void incrementScrollOffset(void)
- {
- size_t len = strlen(VS_StreamInfo);
- // Does it fit on the screen?
- if (len <= 16) {
- ScrollOffset = -1;
- return;
- }
- // Increment the offset
- char toSet = ScrollOffset;
- toSet = (++toSet % (len - 16 + 1));
- ScrollOffset = toSet;
- printf("Scrolloffset %d\n", ScrollOffset);
- }
- int ProcessStreamMetaData(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("Error: Metadata too large, %u blocks\n", blks);
- return -1;
- }
- cnt = blks * 16;
- if ((mbuf = malloc(cnt + 1)) == 0) {
- printf("Can't malloc memory for metadata parsing\n");
- 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;
- }
- printf("================================================ Func: ProcessStreamMetaData\n");
- printf("\nMeta='%s'\n", mbuf);
- char* found = strstr(mbuf, "StreamTitle=");
- if (found != 0){
- int i = 0;
- for (i; i < STREAMINFO_BUFF; i++){
- VS_StreamInfo[i] = ' ';
- }
- char* first = strstr(mbuf, "'") + 1;
- char* last = strstr(first, "'");
- size_t diff = last - first;
- if (diff > STREAMINFO_BUFF){ diff = STREAMINFO_BUFF; }
- strncpy(VS_StreamInfo, first, diff);
- VS_StreamInfo[diff + 1] = '\0';
- VS_StreamInfo[STREAMINFO_BUFF] = '\0';
- printf("Found: %s\n\n", VS_StreamInfo);
- }
- ScrollOffset = 0;
- int time = 5;
- if (strlen(VS_StreamInfo) > 16) { time = 10; }
- setCurrentDisplay(DISPLAY_StreamInfo, time);
- free(mbuf);
- }
- return 0;
- }
|