|
@@ -4,22 +4,112 @@
|
|
|
|
|
|
|
|
#include "mp3stream.h"
|
|
#include "mp3stream.h"
|
|
|
|
|
|
|
|
|
|
+#include <arpa/inet.h>
|
|
|
|
|
+#include <sys/bankmem.h>
|
|
|
|
|
+#include <sys/heap.h>
|
|
|
#include <sys/thread.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!)
|
|
// Prototypes - Functions for internal use only! (They wont be visible outside this file!)
|
|
|
THREAD(Mp3Player, args);
|
|
THREAD(Mp3Player, args);
|
|
|
void setVolume(void);
|
|
void setVolume(void);
|
|
|
|
|
+int ProcessStreamMetaData(FILE *stream);
|
|
|
|
|
|
|
|
// Variables
|
|
// Variables
|
|
|
|
|
+static bool stream_connected = false;
|
|
|
static bool stream_stopped = 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");
|
|
printf("Mp3Player thread created. Device should start playing the stream.\n");
|
|
|
|
|
|
|
|
return true;
|
|
return true;
|
|
@@ -33,7 +123,6 @@ u_char volumeUp(void)
|
|
|
//else:
|
|
//else:
|
|
|
++VS_volume;
|
|
++VS_volume;
|
|
|
VS_volume = VS_volume % 17;
|
|
VS_volume = VS_volume % 17;
|
|
|
-
|
|
|
|
|
setVolume();
|
|
setVolume();
|
|
|
|
|
|
|
|
return VS_volume;
|
|
return VS_volume;
|
|
@@ -53,23 +142,163 @@ u_char volumeDown(void)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void setVolume(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)
|
|
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;
|
|
size_t rbytes = 0;
|
|
|
char *mp3buf;
|
|
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;
|
|
|
|
|
+}
|