Procházet zdrojové kódy

Add streaming to the mp3stream as an improvement of httpstream

Better thread handling makes it now possible to stop the stream
properly.
Jordy Sipkema před 9 roky
rodič
revize
224bd0c0e4
4 změnil soubory, kde provedl 256 přidání a 19 odebrání
  1. 1 1
      httpstream.c
  2. 5 1
      main.c
  3. 243 14
      mp3stream.c
  4. 7 3
      mp3stream.h

+ 1 - 1
httpstream.c

@@ -15,7 +15,7 @@
 
 #include <sys/confnet.h>
 
-#include <arpa/inet.h>
+
 #include <net/route.h>
 
 #include <dev/board.h>

+ 5 - 1
main.c

@@ -354,7 +354,11 @@ int main(void)
 		}
 
         if(KbGetKey() == KEY_01){
-            playStream("62.195.226.247", 80, "/test.mp3");
+            //> "62.195.226.247";
+            printf("KEY_01 DETECTED\n");
+            connectToStream(inet_addr("62.195.226.247"), 80, "/test.mp3");
+            play();
+            //playStream("62.195.226.247", 80, "/test.mp3");
         }
 
         if(KbGetKey() == KEY_DOWN)

+ 243 - 14
mp3stream.c

@@ -4,22 +4,112 @@
 
 #include "mp3stream.h"
 
+#include <arpa/inet.h>
+#include <sys/bankmem.h>
+#include <sys/heap.h>
 #include <sys/thread.h>
+#include <sys/timer.h>
 
+#include "vs10xx.h"
 
+#define OK       1
+#define NOK      0
+#define MSIZE    1024
+
+typedef struct _StreamArgs {
+    FILE *stream;
+} TStreamArgs;
 
 // Prototypes - Functions for internal use only! (They wont be visible outside this file!)
 THREAD(Mp3Player, args);
 void setVolume(void);
+int ProcessStreamMetaData(FILE *stream);
 
 // Variables
+static bool stream_connected = false;
 static bool stream_stopped = false;
-static bool stream_isplaying = false;
-static u_char VS_volume = 7; //[0-15]; (Default volume = 7 (50%) )
 
-bool play(FILE *stream)
+static u_char VS_volume = 7; //[0-16]; (Default volume = 7/16
+static u_long metaInt = 0;
+
+FILE *stream;
+
+
+bool connectToStream(u_long ipAddressStream, u_short port, char *radioUrl
+)
 {
-    NutThreadCreate("Mp3Player", Mp3Player, stream, 512);
+    TCPSOCKET *socket;
+    stream_connected = false;
+    bool result = true;
+    char* data;
+
+    socket = NutTcpCreateSocket();
+    if (NutTcpConnect(socket, ipAddressStream, port))
+    {
+        // An error has occurred.
+        printf("ConnectToSteam: Error creating tcp socket.");
+        NutSleep(5000);
+        result = false;
+        return result;
+    }
+
+    stream = _fdopen((int)socket, "r+b");
+
+    // Tell the console what we are doing.
+    printf("GET %s HTTP/1.0\r\n", radioUrl);
+
+    fprintf(stream, "GET %s HTTP/1.0\r\n", radioUrl);
+    fprintf(stream, "Host: %s\r\n", inet_ntoa(ipAddressStream));
+    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;
+
+    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;
+
+    // else:
+
+    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;
@@ -33,7 +123,6 @@ u_char volumeUp(void)
     //else:
     ++VS_volume;
     VS_volume = VS_volume % 17;
-
     setVolume();
 
     return VS_volume;
@@ -53,23 +142,163 @@ u_char volumeDown(void)
 }
 
 void setVolume(void){
-    VsSetVolume((127 - (VS_volume * 8)) % 128);
+    u_char volumeToSet = (127 - (VS_volume * 8)) % 128;
+    VsSetVolume(volumeToSet, volumeToSet);
 }
 
+void killPlayerThread(void)
+{
+    stream_stopped = true;
+}
 
 THREAD(Mp3Player, args)
+//void function(void* args) //TODO: REMOVE THIS, THIS IS ONLY TO TRICK CLION!
 {
-    FILE *stream = (FILE *)args;
+    // 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;
-    int result = false;
-    int nrBytesRead = 0;
-    unsigned char iflag;
+    u_char ief;
+    int got = 0;
+    u_long mp3left = metaInt;
+
+    // Init MP3-buffer. NutSegBuf is a global system buffer.
+    if (0 != NutSegBufInit(8192)){
+        // 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;
+            }
+        }
+    }
+
+    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) {
+                VsPlayerStop();
+                NutThreadExit();
+            }
+
+            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(;;)
 
-    //Whatevahhh
 }
 
-void killPlayerThread(void)
+int ProcessStreamMetaData(FILE *stream)
 {
-    stream_stopped = true;
-}
+    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("\nMeta='%s'\n", mbuf);
+        free(mbuf);
+    }
+    return 0;
+}

+ 7 - 3
mp3stream.h

@@ -5,12 +5,16 @@
 #ifndef MUTLI_OS_BUILD_MP3STREAM_H
 #define MUTLI_OS_BUILD_MP3STREAM_H
 
+#include "typedefs.h"
+
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+
 #include <stdio.h>
 #include <string.h>
 
-#include "typedefs.h"
-
-bool play(FILE *stream);
+bool play(void);
+bool connectToStream(u_long ipAddressStream, u_short port, char *radioUrl);
 
 u_char volumeUp(void);
 u_char volumeDown(void);