scanner.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * Copyright (C) 2003 by egnite Software GmbH
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the copyright holders nor the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  26. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  27. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  28. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  29. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. *
  32. * For additional information see http://www.ethernut.de/
  33. */
  34. /*!
  35. * $Id: scanner.c 4115 2012-04-12 21:06:13Z olereinhardt $
  36. */
  37. #include <dev/board.h>
  38. #include <sys/heap.h>
  39. #include <sys/thread.h>
  40. #include <sys/timer.h>
  41. #include <netinet/tcp.h>
  42. #include <arpa/inet.h>
  43. #include <stdlib.h>
  44. #include <stdio.h>
  45. #include <string.h>
  46. #include "scanner.h"
  47. #ifdef DEV_ETHER
  48. /*
  49. * Get line from naked TCP stream.
  50. */
  51. static int GetLine(TCPSOCKET * sock, char * line, uint16_t size)
  52. {
  53. int rc = 0;
  54. uint8_t to_cnt = 0;
  55. int got;
  56. char *cp = line;
  57. if (size > 0) {
  58. for (;;) {
  59. if ((got = NutTcpReceive(sock, cp, 1)) <= 0) {
  60. if (got == 0 && to_cnt++ < 10)
  61. continue;
  62. rc = got;
  63. printf("[GL-TO]");
  64. break;
  65. }
  66. if (*cp == '\n') {
  67. *cp = 0;
  68. break;
  69. }
  70. if (*cp != '\r' && rc < (int) size) {
  71. rc++;
  72. cp++;
  73. }
  74. }
  75. }
  76. return rc;
  77. }
  78. static int PutString(TCPSOCKET * sock, char * str)
  79. {
  80. uint16_t len = strlen(str);
  81. uint16_t n;
  82. int c;
  83. for (n = 0; n < len; n += c)
  84. if ((c = NutTcpSend(sock, str + n, len - n)) < 0)
  85. return -1;
  86. return len;
  87. }
  88. /*!
  89. * \brief Process header from server.
  90. */
  91. int ScanStreamHeader(TCPSOCKET * sock, RADIOSTATION * rsp)
  92. {
  93. int rc = -1;
  94. char *line = malloc(256);
  95. char *cp;
  96. /*
  97. * Send the HTTP request.
  98. */
  99. strcpy(line, "GET /");
  100. if (rsp->rs_url)
  101. strcat(line, rsp->rs_url);
  102. strcat(line, " HTTP/1.0\r\n");
  103. PutString(sock, line);
  104. sprintf(line, "Host: %s\r\n", inet_ntoa(rsp->rs_ip));
  105. PutString(sock, line);
  106. PutString(sock, "User-Agent: WinampMPEG/2.7\r\n" "Accept: */*\r\n" "Icy-MetaData: 1\r\n" "Connection: close\r\n\r\n");
  107. if (rsp->rs_name) {
  108. free(rsp->rs_name);
  109. rsp->rs_name = 0;
  110. }
  111. if (rsp->rs_genre) {
  112. free(rsp->rs_genre);
  113. rsp->rs_genre = 0;
  114. }
  115. rsp->rs_metaint = 0;
  116. /*
  117. * Receive the HTTP header.
  118. */
  119. if (GetLine(sock, line, 256) > 5) {
  120. printf("%s\n", line);
  121. if (strncmp(line, "ICY", 3) == 0) {
  122. if (atoi(line + 4) == 200) {
  123. for (;;) {
  124. if ((rc = GetLine(sock, line, 256)) <= 0) {
  125. break;
  126. }
  127. if (strncmp(line, "icy-name:", 9) == 0) {
  128. cp = line + 9;
  129. while (*cp && *cp == ' ')
  130. cp++;
  131. if (*cp && rsp->rs_name == 0) {
  132. rsp->rs_name = malloc(strlen(cp) + 1);
  133. strcpy(rsp->rs_name, cp);
  134. printf("%s\n", cp);
  135. }
  136. } else if (strncmp(line, "icy-genre:", 10) == 0) {
  137. cp = line + 10;
  138. while (*cp && *cp == ' ')
  139. cp++;
  140. if (*cp && rsp->rs_genre == 0) {
  141. rsp->rs_genre = malloc(strlen(cp) + 1);
  142. strcpy(rsp->rs_genre, cp);
  143. }
  144. } else if (strncmp(line, "icy-metaint:", 12) == 0)
  145. rsp->rs_metaint = atol(line + 12);
  146. else if (strncmp(line, "icy-br:", 7) == 0)
  147. rsp->rs_bitrate = atol(line + 7);
  148. }
  149. } else
  150. puts(line);
  151. }
  152. }
  153. free(line);
  154. printf("\n%s %ukbps %s ", inet_ntoa(rsp->rs_ip), rsp->rs_bitrate, rsp->rs_name);
  155. return rc;
  156. }
  157. /*
  158. * Process embedded meta data.
  159. */
  160. static char *ReadMetaTitle(TCPSOCKET * sock, uint32_t iv)
  161. {
  162. uint8_t blks = 0;
  163. uint16_t cnt;
  164. int got;
  165. int rc = 0;
  166. char *title = 0;
  167. char *buf;
  168. char *mn1;
  169. char *mn2;
  170. char *md1;
  171. char *md2;
  172. /* Allocate temporary buffer. */
  173. if ((buf = malloc(512 + 1)) == 0) {
  174. return 0;
  175. }
  176. for (cnt = 512; iv; iv -= got) {
  177. if (iv < 512)
  178. cnt = iv;
  179. if ((got = NutTcpReceive(sock, buf, cnt)) <= 0)
  180. break;
  181. }
  182. if (iv == 0) {
  183. /* Get the number of meta data blocks. */
  184. if ((got = NutTcpReceive(sock, &blks, 1)) == 1) {
  185. if (blks && blks <= 32) {
  186. /* Receive the metadata block. */
  187. for (cnt = blks * 16; cnt; cnt -= got) {
  188. if ((got = NutTcpReceive(sock, buf + rc, cnt)) < 0)
  189. break;
  190. rc += got;
  191. buf[rc] = 0;
  192. }
  193. if (cnt == 0) {
  194. mn1 = buf;
  195. while (mn1) {
  196. if ((mn2 = strchr(mn1, ';')) != 0)
  197. *mn2++ = 0;
  198. if ((md1 = strchr(mn1, '=')) != 0) {
  199. *md1++ = 0;
  200. while (*md1 == ' ' || *md1 == '\'')
  201. md1++;
  202. if ((md2 = strrchr(md1, '\'')) != 0)
  203. *md2 = 0;
  204. if (strcasecmp(mn1, "StreamTitle") == 0) {
  205. title = malloc(strlen(md1) + 1);
  206. strcpy(title, md1);
  207. break;
  208. }
  209. }
  210. mn1 = mn2;
  211. }
  212. }
  213. } else
  214. printf("[ML=%u]", blks);
  215. }
  216. } else
  217. puts("[SMFAIL]");
  218. free(buf);
  219. return title;
  220. }
  221. /*
  222. * Background thread for playing stream.
  223. */
  224. THREAD(Scanner, arg)
  225. {
  226. TCPSOCKET *sock;
  227. RADIOSTATION *rsp;
  228. uint8_t rs;
  229. uint32_t rx_to = 10000UL;
  230. NutThreadSetPriority(128);
  231. NutSleep(10000);
  232. for (;;) {
  233. for (rs = 0; rs < MAXNUM_STATIONS; rs++) {
  234. NutSleep(2000);
  235. if (rs == radio.rc_rstation || rs == radio.rc_cstation)
  236. continue;
  237. rsp = &station[rs];
  238. if (rsp->rs_ip == 0 || rsp->rs_port == 0 || radio.rc_off) {
  239. continue;
  240. }
  241. /* Delay if this isn't the first connection. */
  242. if (rsp->rs_name) {
  243. printf("%d bytes free\n", NutHeapAvailable());
  244. NutSleep(30000);
  245. }
  246. /* Create a socket. */
  247. if ((sock = NutTcpCreateSocket()) == 0) {
  248. break;
  249. }
  250. NutTcpSetSockOpt(sock, SO_RCVTIMEO, &rx_to, sizeof(rx_to));
  251. /* Connect the stream server. */
  252. printf("[Scan %s:%u]\n", inet_ntoa(rsp->rs_ip), rsp->rs_port);
  253. if (NutTcpConnect(sock, rsp->rs_ip, rsp->rs_port) == 0) {
  254. /* Process header from server. */
  255. if (ScanStreamHeader(sock, rsp) == 0) {
  256. if (rsp->rs_scantitle) {
  257. free(rsp->rs_scantitle);
  258. rsp->rs_scantitle = 0;
  259. }
  260. if (rsp->rs_metaint) {
  261. if ((rsp->rs_scantitle = ReadMetaTitle(sock, rsp->rs_metaint)) != 0) {
  262. printf("%03u: %s\n", rs, rsp->rs_scantitle);
  263. rsp->rs_scandead = 0;
  264. } else
  265. rsp->rs_scandead = 1;
  266. } else
  267. rsp->rs_scandead = 0;
  268. } else
  269. rsp->rs_scandead = 1;
  270. } else {
  271. rsp->rs_scandead = 1;
  272. printf("[SERR=%d]\n", NutTcpError(sock));
  273. }
  274. NutTcpCloseSocket(sock);
  275. }
  276. }
  277. NutSleep(30000);
  278. }
  279. /*!
  280. * \brief Initialize the MP3 player.
  281. *
  282. * Initializes the decoder and the decoder buffer and starts the
  283. * player background thread.
  284. */
  285. int ScannerInit(void)
  286. {
  287. /* Start scanner thread. */
  288. if (NutThreadCreate("scanner", Scanner, 0, 512) == 0)
  289. return -1;
  290. return 0;
  291. }
  292. #endif /* DEV_ETHER */