| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- /*
- * Copyright (C) 2003 by egnite Software GmbH
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- */
- /*!
- * $Id: scanner.c 4115 2012-04-12 21:06:13Z olereinhardt $
- */
- #include <dev/board.h>
- #include <sys/heap.h>
- #include <sys/thread.h>
- #include <sys/timer.h>
- #include <netinet/tcp.h>
- #include <arpa/inet.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include "scanner.h"
- #ifdef DEV_ETHER
- /*
- * Get line from naked TCP stream.
- */
- static int GetLine(TCPSOCKET * sock, char * line, uint16_t size)
- {
- int rc = 0;
- uint8_t to_cnt = 0;
- int got;
- char *cp = line;
- if (size > 0) {
- for (;;) {
- if ((got = NutTcpReceive(sock, cp, 1)) <= 0) {
- if (got == 0 && to_cnt++ < 10)
- continue;
- rc = got;
- printf("[GL-TO]");
- break;
- }
- if (*cp == '\n') {
- *cp = 0;
- break;
- }
- if (*cp != '\r' && rc < (int) size) {
- rc++;
- cp++;
- }
- }
- }
- return rc;
- }
- static int PutString(TCPSOCKET * sock, char * str)
- {
- uint16_t len = strlen(str);
- uint16_t n;
- int c;
- for (n = 0; n < len; n += c)
- if ((c = NutTcpSend(sock, str + n, len - n)) < 0)
- return -1;
- return len;
- }
- /*!
- * \brief Process header from server.
- */
- int ScanStreamHeader(TCPSOCKET * sock, RADIOSTATION * rsp)
- {
- int rc = -1;
- char *line = malloc(256);
- char *cp;
- /*
- * Send the HTTP request.
- */
- strcpy(line, "GET /");
- if (rsp->rs_url)
- strcat(line, rsp->rs_url);
- strcat(line, " HTTP/1.0\r\n");
- PutString(sock, line);
- sprintf(line, "Host: %s\r\n", inet_ntoa(rsp->rs_ip));
- PutString(sock, line);
- PutString(sock, "User-Agent: WinampMPEG/2.7\r\n" "Accept: */*\r\n" "Icy-MetaData: 1\r\n" "Connection: close\r\n\r\n");
- if (rsp->rs_name) {
- free(rsp->rs_name);
- rsp->rs_name = 0;
- }
- if (rsp->rs_genre) {
- free(rsp->rs_genre);
- rsp->rs_genre = 0;
- }
- rsp->rs_metaint = 0;
- /*
- * Receive the HTTP header.
- */
- if (GetLine(sock, line, 256) > 5) {
- printf("%s\n", line);
- if (strncmp(line, "ICY", 3) == 0) {
- if (atoi(line + 4) == 200) {
- for (;;) {
- if ((rc = GetLine(sock, line, 256)) <= 0) {
- break;
- }
- if (strncmp(line, "icy-name:", 9) == 0) {
- cp = line + 9;
- while (*cp && *cp == ' ')
- cp++;
- if (*cp && rsp->rs_name == 0) {
- rsp->rs_name = malloc(strlen(cp) + 1);
- strcpy(rsp->rs_name, cp);
- printf("%s\n", cp);
- }
- } else if (strncmp(line, "icy-genre:", 10) == 0) {
- cp = line + 10;
- while (*cp && *cp == ' ')
- cp++;
- if (*cp && rsp->rs_genre == 0) {
- rsp->rs_genre = malloc(strlen(cp) + 1);
- strcpy(rsp->rs_genre, cp);
- }
- } else if (strncmp(line, "icy-metaint:", 12) == 0)
- rsp->rs_metaint = atol(line + 12);
- else if (strncmp(line, "icy-br:", 7) == 0)
- rsp->rs_bitrate = atol(line + 7);
- }
- } else
- puts(line);
- }
- }
- free(line);
- printf("\n%s %ukbps %s ", inet_ntoa(rsp->rs_ip), rsp->rs_bitrate, rsp->rs_name);
- return rc;
- }
- /*
- * Process embedded meta data.
- */
- static char *ReadMetaTitle(TCPSOCKET * sock, uint32_t iv)
- {
- uint8_t blks = 0;
- uint16_t cnt;
- int got;
- int rc = 0;
- char *title = 0;
- char *buf;
- char *mn1;
- char *mn2;
- char *md1;
- char *md2;
- /* Allocate temporary buffer. */
- if ((buf = malloc(512 + 1)) == 0) {
- return 0;
- }
- for (cnt = 512; iv; iv -= got) {
- if (iv < 512)
- cnt = iv;
- if ((got = NutTcpReceive(sock, buf, cnt)) <= 0)
- break;
- }
- if (iv == 0) {
- /* Get the number of meta data blocks. */
- if ((got = NutTcpReceive(sock, &blks, 1)) == 1) {
- if (blks && blks <= 32) {
- /* Receive the metadata block. */
- for (cnt = blks * 16; cnt; cnt -= got) {
- if ((got = NutTcpReceive(sock, buf + rc, cnt)) < 0)
- break;
- rc += got;
- buf[rc] = 0;
- }
- if (cnt == 0) {
- mn1 = buf;
- while (mn1) {
- if ((mn2 = strchr(mn1, ';')) != 0)
- *mn2++ = 0;
- if ((md1 = strchr(mn1, '=')) != 0) {
- *md1++ = 0;
- while (*md1 == ' ' || *md1 == '\'')
- md1++;
- if ((md2 = strrchr(md1, '\'')) != 0)
- *md2 = 0;
- if (strcasecmp(mn1, "StreamTitle") == 0) {
- title = malloc(strlen(md1) + 1);
- strcpy(title, md1);
- break;
- }
- }
- mn1 = mn2;
- }
- }
- } else
- printf("[ML=%u]", blks);
- }
- } else
- puts("[SMFAIL]");
- free(buf);
- return title;
- }
- /*
- * Background thread for playing stream.
- */
- THREAD(Scanner, arg)
- {
- TCPSOCKET *sock;
- RADIOSTATION *rsp;
- uint8_t rs;
- uint32_t rx_to = 10000UL;
- NutThreadSetPriority(128);
- NutSleep(10000);
- for (;;) {
- for (rs = 0; rs < MAXNUM_STATIONS; rs++) {
- NutSleep(2000);
- if (rs == radio.rc_rstation || rs == radio.rc_cstation)
- continue;
- rsp = &station[rs];
- if (rsp->rs_ip == 0 || rsp->rs_port == 0 || radio.rc_off) {
- continue;
- }
- /* Delay if this isn't the first connection. */
- if (rsp->rs_name) {
- printf("%d bytes free\n", NutHeapAvailable());
- NutSleep(30000);
- }
- /* Create a socket. */
- if ((sock = NutTcpCreateSocket()) == 0) {
- break;
- }
- NutTcpSetSockOpt(sock, SO_RCVTIMEO, &rx_to, sizeof(rx_to));
- /* Connect the stream server. */
- printf("[Scan %s:%u]\n", inet_ntoa(rsp->rs_ip), rsp->rs_port);
- if (NutTcpConnect(sock, rsp->rs_ip, rsp->rs_port) == 0) {
- /* Process header from server. */
- if (ScanStreamHeader(sock, rsp) == 0) {
- if (rsp->rs_scantitle) {
- free(rsp->rs_scantitle);
- rsp->rs_scantitle = 0;
- }
- if (rsp->rs_metaint) {
- if ((rsp->rs_scantitle = ReadMetaTitle(sock, rsp->rs_metaint)) != 0) {
- printf("%03u: %s\n", rs, rsp->rs_scantitle);
- rsp->rs_scandead = 0;
- } else
- rsp->rs_scandead = 1;
- } else
- rsp->rs_scandead = 0;
- } else
- rsp->rs_scandead = 1;
- } else {
- rsp->rs_scandead = 1;
- printf("[SERR=%d]\n", NutTcpError(sock));
- }
- NutTcpCloseSocket(sock);
- }
- }
- NutSleep(30000);
- }
- /*!
- * \brief Initialize the MP3 player.
- *
- * Initializes the decoder and the decoder buffer and starts the
- * player background thread.
- */
- int ScannerInit(void)
- {
- /* Start scanner thread. */
- if (NutThreadCreate("scanner", Scanner, 0, 512) == 0)
- return -1;
- return 0;
- }
- #endif /* DEV_ETHER */
|