httpstream.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. //
  2. // Created by janco on 10-3-16.
  3. //
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <sys/thread.h>
  7. #include <sys/timer.h>
  8. #include <sys/version.h>
  9. #include <dev/irqreg.h>
  10. #include "vs10xx.h"
  11. #include <sys/socket.h>
  12. #include <netinet/tcp.h>
  13. #include <sys/confnet.h>
  14. #include <arpa/inet.h>
  15. #include <net/route.h>
  16. #include <dev/board.h>
  17. #include <pro/httpd.h>
  18. #include <pro/dhcp.h>
  19. #include <pro/asp.h>
  20. #include <pro/discover.h>
  21. #include <dev/nicrtl.h>
  22. #include "ntp.h"
  23. #include "httpstream.h"
  24. #define MAX_HEADERLINE 512
  25. bool isStreaming;
  26. TCPSOCKET *sock;
  27. u_short mss = 1460;
  28. u_long rx_to = 3000;
  29. u_short tcpbufsiz = 8760;
  30. FILE *stream;
  31. u_long metaint;
  32. THREAD(Stream, args)
  33. {
  34. if(stream) {
  35. PlayMp3Stream(stream, metaint);
  36. }
  37. stopStream();
  38. NutThreadExit();
  39. }
  40. void playStream(u_long ipaddr, u_short port, char *radiourl){
  41. if(isStreaming != true){
  42. isStreaming = true;
  43. ConnectStation(sock, ipaddr, port, radiourl, &metaint);
  44. NutThreadCreate("Stream", Stream, NULL, 1024);
  45. }
  46. }
  47. void stopStream(){
  48. isStreaming = false;
  49. fclose(stream);
  50. NutTcpCloseSocket(sock);
  51. }
  52. bool HttpIsStreaming(){
  53. return isStreaming;
  54. }
  55. void ConnectStation(TCPSOCKET *sock, u_long ip, u_short port, char *radiourl, u_long *metaint){
  56. int rc;
  57. u_char *line;
  58. u_char *cp;
  59. /*
  60. * Connect the TCP server.
  61. */
  62. if ((sock = NutTcpCreateSocket()) == 0)
  63. printf("Probleem bij het creereen van tcp socket");
  64. if (NutTcpSetSockOpt(sock, TCP_MAXSEG, &mss, sizeof(mss)))
  65. printf("Probleem bij het creereen van tcp socket");
  66. if (NutTcpSetSockOpt(sock, SO_RCVTIMEO, &rx_to, sizeof(rx_to)))
  67. printf("Probleem bij het creereen van tcp socket");
  68. if (NutTcpSetSockOpt(sock, SO_RCVBUF, &tcpbufsiz, sizeof(tcpbufsiz)))
  69. printf("Probleem bij het creereen van tcp socket");
  70. printf("Connecting %s:%u...", inet_ntoa(ip), port);
  71. if ((rc = NutTcpConnect(sock, ip, port))) {
  72. printf("Error: Connect failed with %d\n", ip);
  73. return 0;
  74. }
  75. puts("OK");
  76. if ((stream = _fdopen((int) sock, "r+b")) == 0) {
  77. printf("Error: Can't create stream");
  78. return 0;
  79. }
  80. /*
  81. * Send the HTTP request.
  82. */
  83. printf("GET %s HTTP/1.0\n\n", radiourl);
  84. fprintf(stream, "GET %s HTTP/1.0\r\n", radiourl);
  85. fprintf(stream, "Host: %s\r\n", inet_ntoa(ip));
  86. fprintf(stream, "User-Agent: Ethernut\r\n");
  87. fprintf(stream, "Accept: */*\r\n");
  88. fprintf(stream, "Icy-MetaData: 1\r\n");
  89. fprintf(stream, "Connection: close\r\n");
  90. fputs("\r\n", stream);
  91. fflush(stream);
  92. /*
  93. * Receive the HTTP header.
  94. */
  95. line = malloc(MAX_HEADERLINE);
  96. while(fgets(line, MAX_HEADERLINE, stream)) {
  97. /*
  98. * Chop off the carriage return at the end of the line. If none
  99. * was found, then this line was probably too large for our buffer.
  100. */
  101. cp = strchr(line, '\r');
  102. if(cp == 0) {
  103. printf("Warning: Input buffer overflow");
  104. continue;
  105. }
  106. *cp = 0;
  107. /*
  108. * The header is terminated by an empty line.
  109. */
  110. if(*line == 0) {
  111. break;
  112. }
  113. if(strncmp(line, "icy-metaint:", 12) == 0) {
  114. *metaint = atol(line + 12);
  115. }
  116. printf("%s\n", line);
  117. }
  118. putchar('\n');
  119. free(line);
  120. }
  121. int ProcessMetaData(FILE *stream)
  122. {
  123. u_char blks = 0;
  124. u_short cnt;
  125. int got;
  126. int rc = 0;
  127. u_char *mbuf;
  128. /*
  129. * Wait for the lenght byte.
  130. */
  131. got = fread(&blks, 1, 1, stream);
  132. if(got != 1) {
  133. return -1;
  134. }
  135. if (blks) {
  136. if (blks > 32) {
  137. printf("Error: Metadata too large, %u blocks\n", blks);
  138. return -1;
  139. }
  140. cnt = blks * 16;
  141. if ((mbuf = malloc(cnt + 1)) == 0) {
  142. return -1;
  143. }
  144. /*
  145. * Receive the metadata block.
  146. */
  147. for (;;) {
  148. if ((got = fread(mbuf + rc, 1, cnt, stream)) <= 0) {
  149. return -1;
  150. }
  151. if ((cnt -= got) == 0) {
  152. break;
  153. }
  154. rc += got;
  155. mbuf[rc] = 0;
  156. }
  157. printf("\nMeta='%s'\n", mbuf);
  158. free(mbuf);
  159. }
  160. return 0;
  161. }
  162. void PlayMp3Stream(FILE *stream, u_long metaint)
  163. {
  164. size_t rbytes;
  165. u_char *mp3buf;
  166. u_char ief;
  167. int got = 0;
  168. u_long last;
  169. u_long mp3left = metaint;
  170. /*
  171. * Initialize the MP3 buffer. The NutSegBuf routines provide a global
  172. * system buffer, which works with banked and non-banked systems.
  173. */
  174. if (NutSegBufInit(8192) == 0) {
  175. puts("Error: MP3 buffer init failed");
  176. return;
  177. }
  178. /*
  179. * Initialize the MP3 decoder hardware.
  180. */
  181. if (VsPlayerReset(0)) {
  182. puts("Error: MP3 hardware init failed");
  183. return;
  184. }
  185. /*
  186. * Reset the MP3 buffer.
  187. */
  188. ief = VsPlayerInterrupts(0);
  189. NutSegBufReset();
  190. VsPlayerInterrupts(ief);
  191. last = NutGetSeconds();
  192. while (isStreaming == true) {
  193. /*
  194. * Query number of byte available in MP3 buffer.
  195. */
  196. ief = VsPlayerInterrupts(0);
  197. mp3buf = NutSegBufWriteRequest(&rbytes);
  198. VsPlayerInterrupts(ief);
  199. /*
  200. * If the player is not running, kick it.
  201. */
  202. if (VsGetStatus() != VS_STATUS_RUNNING) {
  203. puts("Not running");
  204. if(rbytes < 1024 || NutGetSeconds() - last > 4UL) {
  205. last = NutGetSeconds();
  206. puts("Kick player");
  207. VsPlayerKick();
  208. }
  209. }
  210. /*
  211. * Do not read pass metadata.
  212. */
  213. if (metaint && rbytes > mp3left) {
  214. rbytes = mp3left;
  215. }
  216. /*
  217. * Read data directly into the MP3 buffer.
  218. */
  219. while (rbytes && (isStreaming == true)) {
  220. if ((got = fread(mp3buf, 1, rbytes, stream)) > 0) {
  221. ief = VsPlayerInterrupts(0);
  222. mp3buf = NutSegBufWriteCommit(got);
  223. VsPlayerInterrupts(ief);
  224. if (metaint) {
  225. mp3left -= got;
  226. if (mp3left == 0) {
  227. ProcessMetaData(stream);
  228. mp3left = metaint;
  229. }
  230. }
  231. if(got < rbytes && got < 512) {
  232. printf("%lu buffered\n", NutSegBufUsed());
  233. NutSleep(250);
  234. }
  235. else {
  236. NutThreadYield();
  237. }
  238. } else {
  239. break;
  240. }
  241. rbytes -= got;
  242. }
  243. if(got <= 0) {
  244. break;
  245. }
  246. }
  247. }