mp3stream.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. //
  2. // Created by Jordy Sipkema on 28/03/16.
  3. //
  4. #include "mp3stream.h"
  5. #include <arpa/inet.h>
  6. #include <sys/bankmem.h>
  7. #include <sys/heap.h>
  8. #include <sys/thread.h>
  9. #include <sys/timer.h>
  10. #include "vs10xx.h"
  11. #define OK 1
  12. #define NOK 0
  13. #define DEFAULT_VOLUME 7
  14. #define MSIZE 1024
  15. #define NUTSEGBUFFER 4096
  16. typedef struct _StreamArgs {
  17. FILE *stream;
  18. } TStreamArgs;
  19. // Prototypes - Functions for internal use only! (They wont be visible outside this file!)
  20. THREAD(Mp3Player, args);
  21. int ProcessStreamMetaData(FILE *stream);
  22. // Variables
  23. static bool stream_connected = false;
  24. static bool stream_stopped = false;
  25. static u_char VS_volume = DEFAULT_VOLUME; //[0-16]; (Default volume = 7/16
  26. static u_long metaInt = 0;
  27. FILE *stream;
  28. TCPSOCKET *socket;
  29. bool connectToStream(u_long ipAddressStream, u_short port, char *radioUrl
  30. )
  31. {
  32. stream_connected = false;
  33. bool result = true;
  34. char* data;
  35. socket = NutTcpCreateSocket();
  36. if (NutTcpConnect(socket, inet_addr("62.195.226.247"), port))
  37. {
  38. // An error has occurred.
  39. printf("ConnectToStream: Error creating tcp socket.\n");
  40. NutSleep(5000);
  41. result = false;
  42. return result;
  43. }
  44. stream = _fdopen((int)socket, "r+b");
  45. // Tell the console what we are doing.
  46. printf("GET %s HTTP/1.0\r\n", radioUrl);
  47. fprintf(stream, "GET %s HTTP/1.0\r\n", radioUrl);
  48. fprintf(stream, "Host: %s\r\n", inet_ntoa(ipAddressStream));
  49. fprintf(stream, "User-Agent: Ethernut\r\n");
  50. fprintf(stream, "Accept: */*\r\n");
  51. fprintf(stream, "Icy-MetaData: 1\r\n");
  52. fprintf(stream, "Connection: close\r\n\r\n");
  53. fflush(stream);
  54. // Server will respond with a HTTP-header. Fetch it to the buffer.
  55. stream_connected = true;
  56. stream_stopped = false;
  57. data = (char *)malloc(MSIZE * sizeof(char));
  58. while (fgets(data, MSIZE, stream))
  59. {
  60. /*
  61. * Chop off the carriage return at the end of the line. If none
  62. * was found, then this line was probably too large for our buffer.
  63. */
  64. char *cp = strchr(data, '\r');
  65. if (cp == 0) continue; // Input buffer overflow.
  66. *cp = 0;
  67. /*
  68. * The header is terminated by an empty line.
  69. */
  70. if (*data == 0) break;
  71. if (strncmp(data, "icy-metaint:", 12) == 0)
  72. metaInt = atol(data + 12);
  73. printf("%s\n", data);
  74. }
  75. free(data);
  76. return result;
  77. }
  78. bool play()
  79. {
  80. if (stream_connected == false)
  81. return false;
  82. // else:
  83. TStreamArgs *streamArgs = &(TStreamArgs){
  84. .stream = stream,
  85. //.metaint = metaInt
  86. };
  87. NutThreadCreate("Mp3Player", Mp3Player, streamArgs, 512);
  88. printf("Mp3Player thread created. Device should start playing the stream.\n");
  89. return true;
  90. }
  91. u_char volumeUp(void)
  92. {
  93. if (VS_volume >= 16)
  94. return VS_volume;
  95. //else:
  96. ++VS_volume;
  97. VS_volume = VS_volume % 17;
  98. setVolume();
  99. return VS_volume;
  100. }
  101. u_char volumeDown(void)
  102. {
  103. if (VS_volume <= 0)
  104. return VS_volume;
  105. //else:
  106. --VS_volume;
  107. VS_volume = VS_volume % 17;
  108. setVolume();
  109. return VS_volume;
  110. }
  111. void setVolume(void){
  112. u_char volumeToSet = (128 - (VS_volume * 8)) % 129;
  113. VsSetVolume(volumeToSet, volumeToSet);
  114. printf("- VS_volume level: %d/16\n", VS_volume);
  115. }
  116. void killPlayerThread(void)
  117. {
  118. printf("Signal to stop the stream sent.\n");
  119. stream_stopped = true;
  120. }
  121. THREAD(Mp3Player, args)
  122. //void function(void* args) //TODO: REMOVE THIS, THIS IS ONLY TO TRICK CLION!
  123. {
  124. // Unpack the args passed to the thread initializer.
  125. TStreamArgs *streamArgs = (TStreamArgs *)args;
  126. FILE *stream = streamArgs->stream;
  127. int result = NOK;
  128. size_t rbytes = 0;
  129. char *mp3buf;
  130. u_char ief;
  131. int got = 0;
  132. u_long mp3left = metaInt;
  133. // Init MP3-buffer. NutSegBuf is a global system buffer.
  134. if (0 != NutSegBufInit(NUTSEGBUFFER)){
  135. // Reset the global buffer.
  136. ief = VsPlayerInterrupts(0);
  137. NutSegBufReset();
  138. VsPlayerInterrupts(ief);
  139. result = OK;
  140. }
  141. // Init the VS1003b hardware.
  142. if (result == OK){
  143. if (-1 == VsPlayerInit()) {
  144. if (-1 == VsPlayerReset(0)){
  145. result = NOK;
  146. }
  147. }
  148. }
  149. for(;;)
  150. {
  151. /*
  152. * Query the number of bytes available in the MP3 buffer.
  153. */
  154. ief = VsPlayerInterrupts(0);
  155. mp3buf = NutSegBufWriteRequest(&rbytes);
  156. VsPlayerInterrupts(ief);
  157. /*
  158. * If the player is not running, kick it.
  159. * This should only occur once.
  160. */
  161. if (VsGetStatus() != VS_STATUS_RUNNING) {
  162. puts("Player not running.");
  163. if (rbytes < 1024){
  164. puts("Kick player in 3 2 1..:");
  165. VsPlayerKick();
  166. }
  167. }
  168. /*
  169. * Do not read pass metadata.
  170. * This causes ugly hiccups.
  171. */
  172. if (metaInt && rbytes > mp3left){
  173. rbytes = mp3left;
  174. }
  175. /*
  176. * Read directly into the MP3 buffer.
  177. */
  178. while (rbytes) {
  179. if (stream_stopped == true) {
  180. printf("Signal to stop the stream recieved\n.");
  181. stream_connected = false;
  182. VsPlayerStop();
  183. NutTcpCloseSocket(socket);
  184. NutThreadExit();
  185. }
  186. if ((got = fread(mp3buf, 1, rbytes, stream)) > 0) {
  187. ief = VsPlayerInterrupts(0);
  188. mp3buf = NutSegBufWriteCommit(got);
  189. VsPlayerInterrupts(ief);
  190. if (metaInt) {
  191. mp3left -= got;
  192. if (mp3left == 0) {
  193. ProcessStreamMetaData(stream);
  194. mp3left = metaInt;
  195. }
  196. }
  197. if (got < rbytes && got < 512) {
  198. printf("%lu buffered\n", NutSegBufUsed());
  199. NutSleep(250);
  200. }
  201. else {
  202. NutThreadYield();
  203. }
  204. } else {
  205. break;
  206. }
  207. rbytes -= got;
  208. }
  209. if (got <= 0) break;
  210. } // end for(;;)
  211. }
  212. int ProcessStreamMetaData(FILE *stream)
  213. {
  214. u_char blks = 0;
  215. u_short cnt;
  216. int got;
  217. int rc = 0;
  218. u_char *mbuf;
  219. /*
  220. * Wait for the lenght byte.
  221. */
  222. got = fread(&blks, 1, 1, stream);
  223. if(got != 1) {
  224. return -1;
  225. }
  226. if (blks) {
  227. if (blks > 32) {
  228. printf("Error: Metadata too large, %u blocks\n", blks);
  229. return -1;
  230. }
  231. cnt = blks * 16;
  232. if ((mbuf = malloc(cnt + 1)) == 0) {
  233. printf("Can't malloc memory for metadata parsing\n");
  234. return -1;
  235. }
  236. /*
  237. * Receive the metadata block.
  238. */
  239. for (;;) {
  240. if ((got = fread(mbuf + rc, 1, cnt, stream)) <= 0) {
  241. return -1;
  242. }
  243. if ((cnt -= got) == 0) {
  244. break;
  245. }
  246. rc += got;
  247. mbuf[rc] = 0;
  248. }
  249. printf("\nMeta='%s'\n", mbuf);
  250. free(mbuf);
  251. }
  252. return 0;
  253. }