3 * Copyright (c) 2006 acmesystems.it - john@acmesystems.it
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19 * Feedback, Bugs... info@acmesystems.it
30 #include <sys/types.h>
31 #include <netinet/in.h>
32 #include <sys/socket.h>
39 typedef struct _MP3_STREAM {
40 unsigned char buf[MAX_PACKET_SIZE + 1];
42 unsigned char mp3_buffer[MAX_BUFFER_SIZE];
43 unsigned long int mp3_buffer_write_pos;
44 unsigned long int mp3_buffer_read_pos;
45 unsigned long int mp3_data_in_buffer;
46 unsigned char transmit_success;
47 unsigned int buffer_error;
49 unsigned int numbytes;
50 unsigned int metainterval;
53 static MP3_STREAM mp3_stream;
55 int connect_timeout (int sfd, struct sockaddr *addr, int addrlen,
56 struct timeval *timeout) {
58 int svlen = sizeof sv;
62 return connect (sfd, addr, addrlen);
64 if (getsockopt (sfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&sv, &svlen) < 0) {
67 if (setsockopt (sfd, SOL_SOCKET, SO_SNDTIMEO, timeout,sizeof *timeout) < 0) {
70 ret = connect (sfd, addr, addrlen);
71 setsockopt (sfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&sv, sizeof sv);
76 int mp3_stream_parse_url(unsigned char *url, unsigned char *ip,
77 unsigned char *path, unsigned int *port){
78 int len = strlen(url) - 1;
79 while(((url[len] == '\n')||(url[len] == ' ')) && (len > 0)){
84 printf("Parsing stream url : %s\n", url);
85 unsigned char *http = strstr(url, "http://");
89 unsigned char *p = strstr(url, ":");
96 unsigned char *p2 = strstr((p)?(p):(url), "/");
107 printf("ip -> %s\nport -> %d\npath -> %s\n", ip, *port, path);
113 int mp3_stream_get_url(unsigned char *url, unsigned int type,
114 unsigned char *ip, unsigned int *port, unsigned char *path){
115 if(type == STREAM_PLS){
116 if(mp3_pls_get_info(url, ip, path, port) == MP3_OK){
119 } else if(type == STREAM_URL){
120 if(mp3_stream_parse_url(url, ip, path, port) == MP3_OK){
127 int mp3_stream_setup(unsigned char *url, unsigned int type, unsigned char *ip,
128 unsigned char *path, unsigned int *port){
130 struct sockaddr_in their_addr;
131 unsigned int error = 0;
132 if(mp3_stream_get_url(url, type, ip, port, path) == MP3_ERROR){
136 mp3_stream.mp3_buffer_write_pos = 0;
137 mp3_stream.mp3_buffer_read_pos = 0;
138 mp3_stream.mp3_data_in_buffer = 0;
139 mp3_stream.transmit_success = 1;
140 mp3_stream.buffer_error = 0;
141 mp3_stream.metainterval = 0;
145 if ((he=gethostbyname(ip)) == NULL) {
146 perror("Error in gethostbyname. Wrong url/ip ?");
149 if ((mp3_stream.sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
150 perror("Error opening stream socket");
154 their_addr.sin_family = AF_INET;
155 their_addr.sin_port = htons(*port);
156 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
157 memset(&(their_addr.sin_zero), '\0', 8);
163 if (connect_timeout(mp3_stream.sockfd, (struct sockaddr *)&their_addr,
164 sizeof(struct sockaddr), &tv) == -1) {
169 unsigned char icy_request[1024];
171 "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: A.LP-MP3\r\nAccept: */*\r\nicy-metadata:0\r\n\r\n",
174 printf("Sending request :\n%s\n", icy_request);
175 send(mp3_stream.sockfd, icy_request, strlen(icy_request), 0);
176 mp3_stream.numbytes = 0;
177 while(mp3_stream.numbytes < MAX_PACKET_SIZE-1) {
178 if ((mp3_stream.numbytes += recv(mp3_stream.sockfd, &mp3_stream.buf[mp3_stream.numbytes], MAX_PACKET_SIZE - 1 - mp3_stream.numbytes, 0)) == -1) {
183 mp3_stream.buf[mp3_stream.numbytes] = '\0';
184 printf("numbytes = %d\n", mp3_stream.numbytes);
185 unsigned char *p = strstr(mp3_stream.buf, "\r\n\r\n");
190 printf("funky p error in stream.c\n");
192 printf("Received: \n%s\n", mp3_stream.buf);
193 if(((unsigned char*)strstr(mp3_stream.buf, "ICY 200 OK") != mp3_stream.buf) &&
194 ((unsigned char*)strstr(mp3_stream.buf, "HTTP/1.1 200 OK") != mp3_stream.buf) &&
195 ((unsigned char*)strstr(mp3_stream.buf, "HTTP/1.0 200 OK") != mp3_stream.buf)) {
198 int p_buf = p - mp3_stream.buf;
200 p2 = strstr(mp3_stream.buf, "icy-metaint:");
202 p2 = strstr(p2, ":");
204 unsigned char *p3 = strstr(p2, "\r");
206 mp3_stream.metainterval = atoi(p2);
207 printf("META INT == %d\n", mp3_stream.metainterval);
210 printf("starting to buffer\n");
211 memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos],
213 mp3_stream.mp3_buffer_write_pos += p_buf;
214 mp3_stream.mp3_data_in_buffer += p_buf;
216 while(mp3_stream.mp3_data_in_buffer + (unsigned long int)MAX_PACKET_SIZE
217 < (unsigned long int)MAX_BUFFER_SIZE){
218 if ((mp3_stream.numbytes=recv(mp3_stream.sockfd, mp3_stream.buf,
219 MAX_PACKET_SIZE-1, 0)) == -1) {
220 perror("disconnected");
221 printf("disconntected\n");
225 if(mp3_stream.numbytes == 0){
228 perror("disconnected");
229 printf("disconntected\n");
234 memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos],
235 mp3_stream.buf, mp3_stream.numbytes);
236 mp3_stream.mp3_buffer_write_pos += mp3_stream.numbytes;
237 mp3_stream.mp3_data_in_buffer += mp3_stream.numbytes;
238 printf("%ld ", mp3_stream.mp3_data_in_buffer);
243 mp3_stream.mp3_data.state = MP3_PLAYING;
244 while(mp3_stream.mp3_data_in_buffer >= 2 * MP3_CHUNK_SIZE){
245 memcpy(mp3_stream.mp3_data.mp3,
246 &mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_read_pos],
248 mp3_send_data_to_buffer(mp3_stream.mp3_data);
249 mp3_stream.mp3_buffer_read_pos += MP3_CHUNK_SIZE;
250 mp3_stream.mp3_data_in_buffer -= MP3_CHUNK_SIZE;
253 printf("Starting to play stream\n");
257 static int max_recv_errors = 10;
258 int mp3_stream_handle(void){
259 if(MAX_BUFFER_SIZE >= mp3_stream.mp3_data_in_buffer + MAX_PACKET_SIZE){
261 ufds.fd = mp3_stream.sockfd;
262 ufds.events = POLLIN|POLLHUP;
264 if(poll(&ufds, 1, 2000) > 0){
265 max_recv_errors = 10;
266 if ((mp3_stream.numbytes=recv(mp3_stream.sockfd, mp3_stream.buf, MAX_PACKET_SIZE-1, 0)) == -1) {
269 if((mp3_stream.numbytes != EAGAIN)&& (mp3_stream.numbytes != -1)){
270 if(mp3_stream.mp3_buffer_write_pos + mp3_stream.numbytes <= MAX_BUFFER_SIZE){
271 memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos],
272 mp3_stream.buf, mp3_stream.numbytes);
273 mp3_stream.mp3_buffer_write_pos += mp3_stream.numbytes;
274 mp3_stream.mp3_data_in_buffer += mp3_stream.numbytes;
275 if(mp3_stream.mp3_buffer_write_pos == MAX_BUFFER_SIZE){
276 mp3_stream.mp3_buffer_write_pos = 0;
279 unsigned int buffer_offset = MAX_BUFFER_SIZE - mp3_stream.mp3_buffer_write_pos;
280 memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos],
281 mp3_stream.buf, buffer_offset);
282 mp3_stream.mp3_buffer_write_pos =
283 mp3_stream.numbytes - buffer_offset;
284 memcpy(&mp3_stream.mp3_buffer[0], &mp3_stream.buf[buffer_offset],
285 mp3_stream.mp3_buffer_write_pos);
286 mp3_stream.mp3_data_in_buffer += mp3_stream.numbytes;
291 if(max_recv_errors == 0){
292 printf("recv error\n");
298 if(mp3_stream.mp3_data_in_buffer < MP3_CHUNK_SIZE){
299 printf("radio_buffer is empty\n");
300 mp3_stream.buffer_error ++;
301 if(mp3_stream.buffer_error > MAX_BUFFER_ERROR){
305 mp3_stream.buffer_error = 0;
307 if(mp3_stream.transmit_success){
308 if(MAX_BUFFER_SIZE >= mp3_stream.mp3_buffer_read_pos + MP3_CHUNK_SIZE){
309 memcpy(mp3_stream.mp3_data.mp3,
310 &mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_read_pos], MP3_CHUNK_SIZE);
311 mp3_stream.mp3_buffer_read_pos += MP3_CHUNK_SIZE;
312 mp3_stream.mp3_data_in_buffer -= MP3_CHUNK_SIZE;
313 if(mp3_stream.mp3_buffer_read_pos == MAX_BUFFER_SIZE){
314 mp3_stream.mp3_buffer_read_pos = 0;
318 unsigned int buffer_offset = MAX_BUFFER_SIZE - mp3_stream.mp3_buffer_read_pos;
319 memcpy(mp3_stream.mp3_data.mp3,
320 &mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_read_pos],
322 mp3_stream.mp3_buffer_read_pos = MP3_CHUNK_SIZE - buffer_offset;
323 memcpy(&mp3_stream.mp3_data.mp3[buffer_offset], mp3_stream.mp3_buffer,
324 mp3_stream.mp3_buffer_read_pos);
327 if(!mp3_send_data_to_buffer(mp3_stream.mp3_data)){
328 mp3_stream.transmit_success = 0;
330 mp3_stream.transmit_success = 1;
332 } while((mp3_stream.transmit_success)&&(mp3_stream.mp3_data_in_buffer > MP3_CHUNK_SIZE));
337 int mp3_stream_cleanup(void){
338 close(mp3_stream.sockfd);