diff options
author | blogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-08-27 20:10:35 +0000 |
---|---|---|
committer | blogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-08-27 20:10:35 +0000 |
commit | e1c9572b15974ffa98eff8b8f4bd77444d44dbd9 (patch) | |
tree | e77ccd710367d8139ccc8be6145e15c42600060e /package/fonera-mp3 | |
parent | 45c87d131f673fa7cfa2abf68b937b50e06145c9 (diff) |
added libjson-c. added driver, webinterface and userspace daemon for the
fonera mp3-hack
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@8509 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/fonera-mp3')
31 files changed, 2916 insertions, 0 deletions
diff --git a/package/fonera-mp3/Makefile b/package/fonera-mp3/Makefile new file mode 100644 index 000000000..b807100b4 --- /dev/null +++ b/package/fonera-mp3/Makefile @@ -0,0 +1,58 @@ +# +# Copyright (C) 2006 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +# $Id: Makefile 8444 2007-08-20 16:12:24Z nbd $ + +include $(TOPDIR)/rules.mk + +PKG_NAME:=fonera-mp3d +PKG_RELEASE:=1 +PKG_VERSION:=1.0 +PKG_BUILD_DEPENDS:=json-c + +include $(INCLUDE_DIR)/package.mk + +define Package/fonera-mp3d + SECTION:=utils + CATEGORY:=Utilities + DEPENDS:=@LINUX_2_6_ATHEROS + TITLE:=Daemon for fonera-mp3 + DESCRIPTION:=Daemon to drive a vs1011X mp3 decoder attached to the \ + fonera gpio pins +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + $(TARGET_CONFIGURE_OPTS) \ + CFLAGS="$(TARGET_CFLAGS)" + $(MAKE) -C $(PKG_BUILD_DIR)/cgi \ + $(TARGET_CONFIGURE_OPTS) \ + CFLAGS="$(TARGET_CFLAGS) -I $(STAGING_DIR)/usr/include/json" \ + LDLIBS="$(STAGING_DIR)/usr/lib/libjson.a" + $(MAKE) -C $(PKG_BUILD_DIR)/cli \ + $(TARGET_CONFIGURE_OPTS) \ + CFLAGS="$(TARGET_CFLAGS)" +endef + +define Package/fonera-mp3d/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/mp3d $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/cli/mplay $(1)/usr/bin/ + $(INSTALL_DIR) $(1)/www/cgi-bin + $(INSTALL_DIR) $(1)/www/local + $(INSTALL_BIN) $(PKG_BUILD_DIR)/cgi/{stylesheet.css,json.js} $(1)/www/local + $(INSTALL_BIN) $(PKG_BUILD_DIR)/cgi/mp3.cgi $(1)/www/cgi-bin + ln -s mp3.cgi $(1)/www/cgi-bin/mp3_cmd.cgi + ln -s mp3.cgi $(1)/www/cgi-bin/mp3_json.cgi + ln -s mp3.cgi $(1)/www/cgi-bin/mp3_remote.cgi +endef + +$(eval $(call BuildPackage,fonera-mp3d)) diff --git a/package/fonera-mp3/src/Makefile b/package/fonera-mp3/src/Makefile new file mode 100644 index 000000000..350f84855 --- /dev/null +++ b/package/fonera-mp3/src/Makefile @@ -0,0 +1,24 @@ +PROGS = mp3d + +INSTDIR = $(prefix)/usr/bin +INSTMODE = 0755 +INSTOWNER = root +INSTGROUP = root + +OBJS = mp3_main.o lib/mp3_states.o lib/mp3_common.o lib/mp3_stream.o \ + lib/mp3_file.o lib/mp3_nix_socket.o lib/mp3_socket_parser.o \ + lib/mp3_misc.o lib/mp3_playtime.o lib/mp3_tcp_socket.o + +all: $(PROGS) +$(PROGS): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ + $(STRIP) $@ + +install: $(PROGS) + $(INSTALL) -d $(INSTDIR) + $(INSTALL) -m $(INSTMODE) -o $(INSTOWNER) -g $(INSTGROUP) $(PROGS) $(INSTDIR) + +clean: + rm -f $(PROGS) *.o core + rm -f lib/$(PROGS) lib/*.o liob/core + diff --git a/package/fonera-mp3/src/cgi/Makefile b/package/fonera-mp3/src/cgi/Makefile new file mode 100644 index 000000000..b8119c043 --- /dev/null +++ b/package/fonera-mp3/src/cgi/Makefile @@ -0,0 +1,13 @@ +PROGS = mp3.cgi + +OBJS = main.o + + +all: $(PROGS) +$(PROGS): + $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $(PROGS) main.c $(LDLIBS) + $(STRIP) $(PROGS) + +clean: + rm -f $(PROGS) *.o core + diff --git a/package/fonera-mp3/src/cgi/json.h b/package/fonera-mp3/src/cgi/json.h new file mode 100644 index 000000000..a5a3432b2 --- /dev/null +++ b/package/fonera-mp3/src/cgi/json.h @@ -0,0 +1,31 @@ +/* + * $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _json_h_ +#define _json_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bits.h" +#include "debug.h" +#include "linkhash.h" +#include "arraylist.h" +#include "json_util.h" +#include "json_object.h" +#include "json_tokener.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/package/fonera-mp3/src/cgi/json.js b/package/fonera-mp3/src/cgi/json.js new file mode 100644 index 000000000..721d5273e --- /dev/null +++ b/package/fonera-mp3/src/cgi/json.js @@ -0,0 +1,141 @@ +var alpmp3_playtime = 0; +var alpmp3_state = 0; +var alpmp3_ip = ""; +var obj_volume; +var obj_bass; +var obj_playtime; +var obj_sate; +var obj_filename; +var MP3Object; +var is_setup = 0; + +function alpmp3_ajax_new_data(){ + obj_bass.firstChild.nodeValue = MP3Object.alpmp3.bass; + obj_volume.firstChild.nodeValue = MP3Object.alpmp3.volume; + obj_state.firstChild.nodeValue = MP3Object.alpmp3.type; + obj_filename.firstChild.nodeValue = MP3Object.alpmp3.filename; + alpmp3_state = MP3Object.alpmp3.state; + if(Math.abs(alpmp3_playtime - MP3Object.alpmp3.playtime) > 1){ + alpmp3_playtime = MP3Object.alpmp3.playtime; + } +} + +function alpmp3_update_data(url){ + var data; + var http_request = new XMLHttpRequest(); + http_request.open("GET", url, true); + http_request.onreadystatechange = function () { + if (http_request.readyState == 4) { + if (http_request.status == 200) { + MP3Object = eval("(" + http_request.responseText + ")"); + alpmp3_ajax_new_data(); + } else { + alert("There was a problem with the URL."); + } + http_request = null; + } + } + http_request.send(null); + self.setTimeout("alpmp3_update_data('mp3_json.cgi');", 4000); +} + +function alpmp3_remote(cmd){ + var doit = ""; + switch(cmd){ + case 'volup': + if(MP3Object.alpmp3.volume < 30){ + MP3Object.alpmp3.volume++; + } + doit = "?vol=" + MP3Object.alpmp3.volume; + break; + case 'voldown': + if(MP3Object.alpmp3.volume > 0){ + MP3Object.alpmp3.volume--; + } + doit = "?vol=" + MP3Object.alpmp3.volume; + break; + case 'bassup': + if(MP3Object.alpmp3.bass < 30){ + MP3Object.alpmp3.bass++; + } + doit = "?bass=" + MP3Object.alpmp3.bass; + break; + case 'bassdown': + if(MP3Object.alpmp3.volume < 30){ + MP3Object.alpmp3.bass--; + } + doit = "?bass=" + MP3Object.alpmp3.bass; + break; + case 'stop': + doit = "?stop=1"; + break; + case 'start': + doit = "?start=1"; + break; + case 'next': + doit = "?next=1"; + break; + case 'back': + doit = "?back=1"; + break; + } + if(doit != ""){ + var http_request2 = new XMLHttpRequest(); + http_request2.open("GET", 'mp3_cmd.cgi'+doit, true); + http_request2.onreadystatechange = function () { + if (http_request2.readyState == 4) { + if (http_request2.status == 200) { + alpmp3_ajax_new_data(); + } else { + alert("There was a problem with the URL."); + } + http_request2 = null; + } + } + http_request2.send(null); + } + +} + +function alpmp3_timeout(){ + alpmp3_state = 0; + alert(alpmp3_playtime); +} + +function alpmp3_playtime_update(){ + self.setTimeout("alpmp3_playtime_update()", 1000); + if(alpmp3_state > 0){ + alpmp3_playtime ++; + } else { + alpmp3_playtime = 0; + } + var s = alpmp3_playtime; + var h = 0; + var m = 0; + while(s > 3599){ + h++; + s -= 3600; + } + while(s > 59){ + m++; + s -= 60; + } + ptime = ((m < 10) ? "0" : "") + m + ":" + ((s < 10) ? "0" : "") + s; + if(h > 0){ + ptime = ((h < 10) ? "0" : "") + h + ":" + ptime; + } + obj_playtime.firstChild.nodeValue = ptime; +} + +function alpmp3_setup($ip){ + if(is_setup == 0){ + obj_volume = document.getElementById("alpmp3_volume"); + obj_bass = document.getElementById("alpmp3_bass"); + obj_state = document.getElementById("alpmp3_state"); + obj_filename = document.getElementById("alpmp3_filename"); + obj_playtime = document.getElementById("alpmp3_playtime"); + is_setup = 1; + } + self.setTimeout("alpmp3_update_data('mp3_json.cgi');", 4000); + self.setTimeout("alpmp3_playtime_update()", 1000); +} diff --git a/package/fonera-mp3/src/cgi/main.c b/package/fonera-mp3/src/cgi/main.c new file mode 100644 index 000000000..0499e0eee --- /dev/null +++ b/package/fonera-mp3/src/cgi/main.c @@ -0,0 +1,237 @@ +/* +* FOXMP3 +* Copyright (c) 2007 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netdb.h> + +#include <json.h> + +#define SOCKET_PATH "/tmp/foxmp3" + +void print_http_header(){ + printf("Content-type: text/html\n\n"); +} + +int read_parameter(char *name, char *value, int maxlen){ + char *pos1, *pos2; + char *query_string = getenv("QUERY_STRING"); + int success = 0; + + if(query_string){ + pos1 = strstr(query_string, name); + if(pos1){ + pos1 += strlen(name) + 1; + pos2 = strstr(pos1, "&"); + if(pos2){ + *pos2 = '\0'; + } + if(strlen(pos1) >= maxlen){ + pos1[maxlen] = '\0'; + } + strcpy(value, pos1); + success = 1; + } + } + return success; +} + + +int issue_command(unsigned char *str){ + int s, t, len; + struct sockaddr_un remote; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + exit(1); + } + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCKET_PATH); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + if (connect(s, (struct sockaddr *)&remote, len) == -1) { + return 1; + } + if (send(s, str, strlen(str), 0) == -1) { + return 1; + } + unsigned char loop = 1; + while(loop){ + if ((t=recv(s, str, 2048, 0)) > 0) { + str[t] = '\0'; + if((strstr(str, "OK\n")) || (strstr(str, "ERROR\n"))){ + loop = 0; + } + } else { + return 1; + } + } + close(s); + return 0; +} + +void handle_cmd(){ + unsigned char param[128]; + unsigned char cmd[256]; + int i; + *cmd = '\0'; + if(read_parameter("vol", param, 128)){ + i = atoi(param); + i = 120 - (i * 4); + sprintf(cmd, "VOLUME %d", i); + } + if(read_parameter("bass", param, 128)){ + i = atoi(param); + sprintf(cmd, "BASS %d", i); + } + if(read_parameter("start", param, 128)){ + sprintf(cmd, "START"); + } + if(read_parameter("stop", param, 128)){ + sprintf(cmd, "STOP"); + } + if(read_parameter("next", param, 128)){ + sprintf(cmd, "NEXT"); + } + if(read_parameter("back", param, 128)){ + sprintf(cmd, "BACK"); + } + if(*cmd){ + issue_command(cmd); + } +} + +void print_html_remote(){ + char name[128]; + gethostname(name, 128); + printf("<html><head><title>foxmp3 - %s - remote</title><link rel=\"stylesheet\" href=\"../local/stylesheet.css\" type=\"text/css\" /><script src=\"../local/json.js\" type=\"text/javascript\"></script></head><body onload=\"alpmp3_setup();\">"); + printf("<center><p id=alpmp3_remote>"); + printf("<table width=50%%>"); + printf("<tr class=cellhead><th colspan=3 id=cell align=center>FOXMP3 - %s </td></tr>", name); + printf("<tr class=cellone><td>Action</td><td colspan=2 id=alpmp3_state>0</td></tr>"); + printf("<tr class=celltwo><td>Filename</td><td colspan=2 id=alpmp3_filename>0</td></tr>"); + printf("<tr class=cellone><td>Playtime</td><td colspan=2 id=alpmp3_playtime>0</td></tr>"); + printf("<tr class=celltwo><td>Volume</td><td id=alpmp3_volume>0</td><td><a href=\"#\" onclick=\"javascript:alpmp3_remote('volup');\">Up</a> <a href=\"#\" onclick=\"javascript:alpmp3_remote('voldown')\">Down</a></td></tr>"); + printf("<tr class=cellone><td width=20%%>Bass</td><td id=alpmp3_bass>0</td><td><a href=\"#\" onclick=\"javascript:alpmp3_remote('bassup');\" class=browse>Up</a> <a href=\"#\" onclick=\"javascript:alpmp3_remote('bassdown')\" class=browse>Down</a></td></tr>"); + printf("<tr class=cellhead><th colspan=3 id=cell align=center><a href=\"#\" onclick=\"javascript:alpmp3_remote('start');\">Start</a> <a href=\"#\" onclick=\"javascript:alpmp3_remote('stop');\">Stop</a> <a href=\"#\" onclick=\"javascript:alpmp3_remote('back');\">Back</a> <a href=\"#\" onclick=\"javascript:alpmp3_remote('next');\">Next</a> </td></tr>"); + printf("</table>"); + printf("</p></center>"); + printf("</body></html>"); +} + + + +void print_json_info(){ + unsigned char str[2048]; + sprintf(str, "STATE"); + if(issue_command(str) == 0){ + int state = 0; + int volume = 0; + int bass = 0; + int playtime = 0; + unsigned char filename[1024]; + unsigned char *p1, *p2; + + memset(filename, 0, 1024); + p1 = str; + while(p1){ + p2 = strstr(p1, "\n"); + if(p2){ + *p2 = '\0'; + p2 ++; + // printf("parsing %s\n", p1); + if(strncmp(p1, "VOLUME", strlen("VOLUME")) == 0){ + volume = atoi(&p1[strlen("VOLUME") + 1]); + if(volume > 120) + volume = 120; + volume = 120 - volume; + volume /= 4; + //printf("vol = %d\n", volume); + } else if(strncmp(p1, "BASS", strlen("BASS")) == 0){ + bass = atoi(&p1[strlen("BASS") + 1]); + //printf("bass = %d\n", bass); + } else if(strncmp(p1, "PLAYTIME", strlen("PLAYTIME")) == 0){ + playtime = atoi(&p1[strlen("PLAYTIME") + 1]); + //printf("playtime = %d\n", playtime); + } else if(strncmp(p1, "STATE", strlen("STATE")) == 0){ + if(strstr(p1, "MP3_STATE_IDLE")){ + state = 0; + } else if(strstr(p1, "MP3_STATE_FILE")){ + state = 1; + } else if(strstr(p1, "MP3_STATE_STREAM")){ + state = 2; + } + //printf("state = %d\n", state); + } else if(strncmp(p1, "STREAM", strlen("STREAM")) == 0){ + strcpy(filename, &p1[strlen("STREAM") + 1]); + //printf("filename = %s\n", filename); + } else if(strncmp(p1, "FILE", strlen("FILE")) == 0){ + strcpy(filename, &p1[strlen("FILE") + 1]); + //printf("filename = %s\n", filename); + } + + p1 = p2; + } else { + p1 = 0; + } + } + + struct json_object *alpmp3 = json_object_new_object(); + json_object_object_add(alpmp3, "state", json_object_new_int(state)); + switch(state){ + case 1: + json_object_object_add(alpmp3, "type", json_object_new_string("file")); + break; + case 2: + json_object_object_add(alpmp3, "type", json_object_new_string("stream")); + break; + default: + json_object_object_add(alpmp3, "type", json_object_new_string("idle")); + break; + } + json_object_object_add(alpmp3, "volume", json_object_new_int(volume)); + json_object_object_add(alpmp3, "bass", json_object_new_int(bass)); + json_object_object_add(alpmp3, "playtime", json_object_new_int(playtime)); + json_object_object_add(alpmp3, "filename", json_object_new_string(filename)); + struct json_object *jo = json_object_new_object(); + json_object_object_add(jo, "alpmp3", alpmp3); + printf("\n%s\n", json_object_to_json_string(jo)); + } +} + +int main(int argc, char **argv){ + print_http_header(); + + if(strstr(argv[0], "mp3_remote.cgi")){ + print_html_remote(); + } else if(strstr(argv[0], "mp3_json.cgi")){ + print_json_info(); + } else if(strstr(argv[0], "mp3_cmd.cgi")){ + handle_cmd(); + } else { + printf("Unknown command"); + } + return 0; +} diff --git a/package/fonera-mp3/src/cgi/stylesheet.css b/package/fonera-mp3/src/cgi/stylesheet.css new file mode 100644 index 000000000..d58d47e24 --- /dev/null +++ b/package/fonera-mp3/src/cgi/stylesheet.css @@ -0,0 +1,31 @@ +body {
+ background-color:#FFFFFF;
+}
+
+font { font-family: Verdana, Arial, Helvetica, sans-serif }
+td { font-family: Arial, Helvetica, sans-serif; font-size: 12px }
+th { font-family: Arial, Helvetica, sans-serif }
+P { font-family: Arial, Helvetica, sans-serif }
+hr { height: 0px; border-top-width: 1px;}
+TH.surlink { font-family: Arial, Helvetica, sans-serif; color: #000000 }
+
+TH { background-color: #99CCCC; height: 0px; font-size: 11px; line-height : 100%; font-weight: bold; color: #000000 }
+TR.cellone { background-color: #FFFFCC; height: 16px; font-size: 12px; line-height : 100%; color: #000000 }
+TR.celltwo { background-color: #FFFF99; height: 16px; font-size: 12px; line-height : 100%; color: #000000 }
+TR.cellhead { background-color: #FFFF44; height: 16px; font-size: 12px; line-height : 100%; color: #000000 }
+
+.copyright { font-family: Verdana, Arial, Helvetica, sans-serif; color: #000000; font-size: 10px; letter-spacing: -1px;}
+.copyright a { color: #CC0000; text-decoration: none;}
+.copyright a:hover { color: #FF0000; text-decoration: underline;}
+
+.error_table { border-spacing:0px;border: 1px solid #000000;}
+.error_t {color:#000000;background-color:#FFFFDD;border-spacing:0px;border: 0px}
+
+a { color: #0000FF; text-decoration: underline;}
+a:hover { color: #FF0000; text-decoration: none;}
+.box {
+ background-color: #FFFFFF;
+ border: 1px solid #999900;
+ font-family: Verdana;
+ font-size: 10px;
+ }
diff --git a/package/fonera-mp3/src/cli/Makefile b/package/fonera-mp3/src/cli/Makefile new file mode 100644 index 000000000..e6aa0df92 --- /dev/null +++ b/package/fonera-mp3/src/cli/Makefile @@ -0,0 +1,26 @@ + +PROGS = mplay + +INSTDIR = $(prefix)/usr/bin +INSTMODE = 0755 +INSTOWNER = root +INSTGROUP = root + +OBJS = main.o + +all: $(PROGS) +$(PROGS): + $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o mplay main.c + $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o mplay_tcp main_tcp.c + gcc -o mplay_tcp_native main_tcp.c + $(STRIP) mplay + $(STRIP) mplay_tcp + +install: $(PROGS) + $(INSTALL) -d $(INSTDIR) + $(INSTALL) -m $(INSTMODE) -o $(INSTOWNER) -g $(INSTGROUP) $(PROGS) $(INSTDIR) + $(INSTALL) -m $(INSTMODE) -o $(INSTOWNER) -g $(INSTGROUP) $(PROGS)_tcp $(INSTDIR) + +clean: + rm -f $(PROGS) *.o core + diff --git a/package/fonera-mp3/src/cli/main.c b/package/fonera-mp3/src/cli/main.c new file mode 100644 index 000000000..abea0a61e --- /dev/null +++ b/package/fonera-mp3/src/cli/main.c @@ -0,0 +1,108 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> + +#define SOCKET_PATH "/tmp/foxmp3" + + +void print_usage(void){ + printf("mp3_play COMANND PARAMETERS\n"); + printf(" Commands :\n"); + printf(" PLAY filename\n"); + printf(" STREAM url [URL OF STREAM]\n"); + printf(" STREAM pls [URL PLS FILE]\n"); + printf(" VOLUME [0-255]\n"); + printf(" STOP\n"); + printf(" STATE\n"); + printf(" BASS [0-255]\n"); +} + +void issue_command(unsigned char *str){ + int s, t, len; + struct sockaddr_un remote; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("socket"); + exit(1); + } + printf("Connecting to mp3d ...\n"); + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCKET_PATH); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + if (connect(s, (struct sockaddr *)&remote, len) == -1) { + perror("connect"); + exit(1); + } + printf("Connected ...\n\nSending command -> \n%s\n\n", str); + if (send(s, str, strlen(str), 0) == -1) { + perror("send"); + exit(1); + } + unsigned char loop = 1; + while(loop){ + if ((t=recv(s, str, 2048, 0)) > 0) { + str[t] = '\0'; + printf("The answer was -> \n%s\n", str); + if((strstr(str, "OK")) || (strstr(str, "ERROR"))){ + loop = 0; + } + } else { + if (t < 0){ + perror("recv"); + } else { + printf("Server closed connection\n"); + }; + } + } + close(s); +} + +int main(int argc, char **argv){ + unsigned char buffer[2048]; + buffer[0] = '\0'; + if(argc > 1){ + if(((!strcmp(argv[1], "STOP")) || (!strcmp(argv[1], "STATE"))) + && (argc == 2)){ + sprintf(buffer, "%s", argv[1]); + } else if(((!strcmp(argv[1], "PLAY")) || (!strcmp(argv[1], "VOLUME")) + || (!strcmp(argv[1], "BASS"))) && (argc == 3)){ + sprintf(buffer, "%s %s", argv[1], argv[2]); + } else if((!strcmp(argv[1], "STREAM")) && (argc == 4) + && ((!strcmp(argv[2], "url")) || (!strcmp(argv[2], "pls")))){ + sprintf(buffer, "%s %s %s", argv[1], argv[2], + argv[3]); + } + }; + if(buffer[0] != '\0'){ + issue_command(buffer); + } else { + print_usage(); + }; + return 0; +} diff --git a/package/fonera-mp3/src/cli/main_tcp.c b/package/fonera-mp3/src/cli/main_tcp.c new file mode 100644 index 000000000..02fc41ea4 --- /dev/null +++ b/package/fonera-mp3/src/cli/main_tcp.c @@ -0,0 +1,118 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <netdb.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> + +#define SOCKET_PORT 369 + + +void print_usage(void){ + printf("mp3_play_tcp IP COMANND PARAMETERS\n"); + printf(" Commands :\n"); + printf(" PLAY filename\n"); + printf(" STREAM url [URL OF STREAM]\n"); + printf(" STREAM pls [URL PLS FILE]\n"); + printf(" VOLUME [0-255]\n"); + printf(" STOP\n"); + printf(" STATE\n"); + printf(" BASS [0-255]\n"); +} + +void issue_command(unsigned char *str, unsigned char *ip){ + int s, t, len; + struct sockaddr_in remote; + struct hostent *he; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("socket"); + exit(1); + } + + printf("Connecting to FOXMP3 on IP/DNS : %s ...\n", ip); + if((he=gethostbyname(ip)) == NULL) { + herror("gethostbyname"); + exit(1); + } + if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + perror("socket"); + exit(1); + } + remote.sin_family = AF_INET; + remote.sin_port = htons(SOCKET_PORT); + remote.sin_addr = *((struct in_addr *)he->h_addr); + memset(&(remote.sin_zero), '\0', 8); + + if (connect(s, (struct sockaddr *)&remote, + sizeof(struct sockaddr)) == -1) { + perror("connect"); + exit(1); + } + printf("Connected ...\n\nSending command -> \n%s\n\n", str); + if (send(s, str, strlen(str), 0) == -1) { + perror("send"); + exit(1); + } + if ((t=recv(s, str, 2048, 0)) > 0) { + str[t] = '\0'; + printf("The answer was -> \n%s\n", str); + } else { + if (t < 0){ + perror("recv"); + } else { + printf("Server closed connection\n"); + }; + exit(1); + } + close(s); +} + +int main(int argc, char **argv){ + unsigned char buffer[2048]; + buffer[0] = '\0'; + if(argc > 2){ + if(((!strcmp(argv[2], "STOP")) || (!strcmp(argv[2], "STATE"))) + && (argc == 3)){ + sprintf(buffer, "%s", argv[2]); + } else if(((!strcmp(argv[2], "PLAY")) || (!strcmp(argv[2], "VOLUME")) + || (!strcmp(argv[2], "BASS"))) && (argc == 4)){ + sprintf(buffer, "%s %s", argv[2], argv[3]); + } else if((!strcmp(argv[2], "STREAM")) && (argc == 5) + && ((!strcmp(argv[3], "url")) || (!strcmp(argv[3], "pls")))){ + sprintf(buffer, "%s %s %s", argv[2], argv[3], + argv[4]); + } + }; + if(buffer[0] != '\0'){ + issue_command(buffer, argv[1]); + } else { + print_usage(); + }; + return 0; +} diff --git a/package/fonera-mp3/src/lib/mp3.h b/package/fonera-mp3/src/lib/mp3.h new file mode 100644 index 000000000..77db813c9 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3.h @@ -0,0 +1,35 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include "mp3_file.h" +#include "mp3_stream.h" +#include "mp3_nix_socket.h" +#include "mp3_tcp_socket.h" +#include "mp3_common.h" +#include "mp3_statemachine.h" +#include "mp3_socket_parser.h" +#include "mp3_misc.h" +#include "mp3_playtime.h" +#include "mp3_states.h" + +void state_event(int event, EVENT_PARAM *param); +EVENT_PARAM* state_new_event(unsigned char *text, int numeric); diff --git a/package/fonera-mp3/src/lib/mp3_common.c b/package/fonera-mp3/src/lib/mp3_common.c new file mode 100644 index 000000000..3cdb0b8fc --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_common.c @@ -0,0 +1,121 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <fcntl.h> + +#include "mp3.h" + +static int mp3_fd; +static int mp3_frequency_val = CRYSTAL12288; +unsigned int volume = 0x3030; + +int mp3_open_port(unsigned char *port_name){ + int fd; + if ((fd = open(port_name, O_RDWR)) < 0) { + printf("Error whilst opening %s\n", port_name); + return -1; + } + return fd; +}; + +void mp3_set_frequency(unsigned int crystal_frequency){ + mp3_frequency_val = crystal_frequency; +}; + +int mp3_init(void){ + mp3_fd = mp3_open_port("/dev/mp3"); + if(mp3_fd < 1){ + return 0; + }; + ioctl(mp3_fd, IOCTL_MP3_INIT, mp3_frequency_val); + return 1; +}; + +void mp3_shutdown(void){ + close(mp3_fd); +}; + +void mp3_bass(unsigned char t_freq, unsigned char t_amp, + unsigned char b_freq, unsigned char b_amp){ + unsigned int val; + if(t_amp > 0xf){ + t_amp = 0xf; + }; + if(b_amp > 0xf){ + b_amp = 0xf; + }; + val = t_amp; + val <<= 4; + val += t_freq; + val <<= 4; + val += b_amp; + val <<= 4; + val += b_freq; + ioctl(mp3_fd, IOCTL_MP3_BASS, val); +}; + +void mp3_reset(void){ + ioctl(mp3_fd, IOCTL_MP3_CLEARBUFFER, 0); + ioctl(mp3_fd, IOCTL_MP3_RESET, mp3_frequency_val); + ioctl(mp3_fd, IOCTL_MP3_SETVOLUME, volume); +}; + +unsigned char mp3_send_data_to_buffer(MP3_DATA mp3_data){ + return write(mp3_fd, (void*)&mp3_data, sizeof(MP3_DATA)); +}; + +unsigned char mp3_play(void){ + return ioctl(mp3_fd, IOCTL_MP3_PLAY, 0); +}; + +void mp3_stop(void){ + ioctl(mp3_fd, IOCTL_MP3_CLEARBUFFER, 0); +}; + +void mp3_beep(unsigned char freq, unsigned int ms){ + MP3_BEEP mp3_beep_; + mp3_beep_.freq = freq; + mp3_beep_.ms = ms; + ioctl(mp3_fd, IOCTL_MP3_BEEP, &mp3_beep_); +}; + +void mp3_set_volume(unsigned char left, unsigned char right){ + volume = left; + volume <<= 8; + volume += right; + + ioctl(mp3_fd, IOCTL_MP3_SETVOLUME, volume); +}; + +unsigned char mp3_buffer_finished(void){ + return ioctl(mp3_fd, IOCTL_MP3_END_REACHED, 0); +}; + +unsigned char mp3_get_audio_data(AUDIO_DATA *audio_data){ + return ioctl(mp3_fd, IOCTL_MP3_GETAUDIODATA, audio_data); +}; + + diff --git a/package/fonera-mp3/src/lib/mp3_common.h b/package/fonera-mp3/src/lib/mp3_common.h new file mode 100644 index 000000000..d1eb0fa56 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_common.h @@ -0,0 +1,72 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#define MP3_CHUNK_SIZE 4096 +#define MP3_BUFFERING 0 +#define MP3_PLAYING 1 +#define MP3_BUFFER_FINISHED 2 +#define MP3_PLAY_FINISHED 3 + +typedef struct _MP3_DATA{ + unsigned char mp3[MP3_CHUNK_SIZE]; + unsigned char state; +} MP3_DATA; + + +#define IOCTL_MP3_INIT 0x01 +#define IOCTL_MP3_RESET 0x02 +#define IOCTL_MP3_SETVOLUME 0x03 +#define IOCTL_MP3_GETVOLUME 0x04 +typedef struct _AUDIO_DATA{ + unsigned int bitrate; + unsigned int sample_rate; + unsigned char is_stereo; +}AUDIO_DATA; +#define IOCTL_MP3_GETAUDIODATA 0x05 + +#define IOCTL_MP3_CLEARBUFFER 0x06 +#define IOCTL_MP3_PLAY 0x07 +typedef struct _MP3_BEEP{ + unsigned char freq; + unsigned int ms; +} MP3_BEEP; +#define IOCTL_MP3_BEEP 0x08 +#define IOCTL_MP3_END_REACHED 0x09 + +#define IOCTL_MP3_BASS 0x10 + +#define CRYSTAL12288 0x9800 +#define CRYSTAL24576 0x0 + +#define MP3_OK 0 +#define MP3_ERROR 1 +#define MP3_END 2 + +void mp3_reset(void); +unsigned char mp3_send_data_to_buffer(MP3_DATA mp3_data); +unsigned char mp3_buffer_finished(void); +unsigned char mp3_play(void); +void mp3_stop(void); +int mp3_init(void); +void mp3_bass(unsigned char t_freq, unsigned char t_amp, + unsigned char b_freq, unsigned char b_amp); +void mp3_set_volume(unsigned char left, unsigned char right); diff --git a/package/fonera-mp3/src/lib/mp3_file.c b/package/fonera-mp3/src/lib/mp3_file.c new file mode 100644 index 000000000..2dbed0ffc --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_file.c @@ -0,0 +1,191 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> + +#include "mp3.h" + + +#define MP3_PRE_BUFFER_COUNT ((128 * 1024) / MP3_CHUNK_SIZE) + + +typedef struct _MP3_FILE { + unsigned char filename[2048]; + MP3_DATA mp3_data; + FILE *fd; + unsigned char file_end_found; + MP3_FILE_ID3 *id3; +} MP3_FILE; + +static MP3_FILE mp3_file; + +void mp3_load_id3(FILE *fp){ + unsigned char *buf = malloc(1024); + + mp3_file.id3->album[0] = '\0'; + mp3_file.id3->artist[0] = '\0'; + mp3_file.id3->track[0] = '\0'; + + + fgets(buf, 1024, fp); + if( (buf[0] == 'I') && + (buf[1] == 'D') && + (buf[2] == '3')){ + unsigned int id3_size; + unsigned int i; + unsigned int id3_version = buf[3]; + id3_version <<= 8; + id3_version += buf[4]; + + id3_size = 0; + + for(i = 0; i<4; i++){ + id3_size += buf[5 + i]; + id3_size <<= 7; + }; + if(id3_version>>8 == 3){ + unsigned int id3_pos = 10; + unsigned int id3_tag_size; + unsigned char tag_name[5]; + unsigned char tag_data[257]; + tag_name[4] = '\0'; + tag_data[256] = '\0'; + unsigned int count = 0; + while(count < 10){ + strncpy(tag_name, &buf[id3_pos], 4); + id3_tag_size = buf[id3_pos + 4]; + id3_tag_size <<= 8; + id3_tag_size = buf[id3_pos + 5]; + id3_tag_size <<= 8; + id3_tag_size = buf[id3_pos + 6]; + id3_tag_size <<= 8; + id3_tag_size = buf[id3_pos + 7]; + if(id3_tag_size == 0){ + break; + }; + if(id3_tag_size > 256){ + memcpy(&tag_data[0], &buf[id3_pos + 11] , 256); + } else { + memcpy(&tag_data[0], &buf[id3_pos + 11] , + id3_tag_size -1); + tag_data[id3_tag_size-1] = '\0'; + }; + id3_pos += 10 + id3_tag_size; + if(strcmp(tag_name, "TPE1") == 0){ + strncpy(mp3_file.id3->artist, tag_data, 255); + }; + if(strcmp(tag_name, "TALB") == 0){ + strncpy(mp3_file.id3->album, tag_data, 255); + }; + if(strcmp(tag_name, "TIT2") == 0){ + strncpy(mp3_file.id3->track, tag_data, 255); + }; + if(id3_pos >= id3_size){ + break; + }; + count ++; + }; + }; + printf("ID3 tag found Version 2.%d.%d / size %d\n%s -- %s -- %s\n", + id3_version>>8, + id3_version&0xff, + id3_size, + mp3_file.id3->artist, + mp3_file.id3->album, + mp3_file.id3->track); + } else { + printf("No ID3 Tag was found\n"); + }; + free(buf); +}; + + +int mp3_file_setup(unsigned char *filename, MP3_FILE_ID3 *id3){ + unsigned int i; + mp3_file.id3 = id3; + mp3_file.file_end_found = 0; + strcpy(mp3_file.filename, filename); + mp3_file.fd = fopen(mp3_file.filename, "rb"); + if(!mp3_file.fd){ + mp3_file.fd = 0; + printf("error opening file %s\n", mp3_file.filename); + return MP3_ERROR; + }; + printf("File %s opened Ok\n", mp3_file.filename); + printf("Reading id3 tag\n"); + mp3_load_id3(mp3_file.fd); + fseek(mp3_file.fd, 0, SEEK_SET); + + mp3_reset(); + + printf("Buffering MP3 Data\n"); + mp3_file.mp3_data.state = MP3_BUFFERING; + for(i = 0; i < MP3_PRE_BUFFER_COUNT - 1; i++){ + fread(mp3_file.mp3_data.mp3, MP3_CHUNK_SIZE, 1, mp3_file.fd); + mp3_file.mp3_data.state = MP3_PLAYING; + mp3_send_data_to_buffer(mp3_file.mp3_data); + }; + + printf("Starting to play file : %s\n", mp3_file.filename); + return MP3_OK; +}; + +int mp3_file_handle(void){ + unsigned char transmit_success = 1; + if (!feof(mp3_file.fd)) { + fread(mp3_file.mp3_data.mp3, MP3_CHUNK_SIZE, 1, mp3_file.fd); + transmit_success = 0; + while(!transmit_success){ + if(!mp3_send_data_to_buffer(mp3_file.mp3_data)){ + usleep(1); + transmit_success = 0; + } else { + transmit_success = 1; + }; + }; + return MP3_OK; + } else { + if(!mp3_file.file_end_found){ + mp3_file.mp3_data.state = MP3_BUFFER_FINISHED; + mp3_send_data_to_buffer(mp3_file.mp3_data); + printf("File end reached. Wait till kernel buffer has cleared.\n"); + mp3_file.file_end_found = 1; + }; + if(!mp3_buffer_finished()){ + return MP3_OK; + } else { + return MP3_END; + }; + }; +}; + +int mp3_file_cleanup(void){ + if(mp3_file.fd){ + fclose(mp3_file.fd); + }; + return MP3_OK; +}; diff --git a/package/fonera-mp3/src/lib/mp3_file.h b/package/fonera-mp3/src/lib/mp3_file.h new file mode 100644 index 000000000..1bff35209 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_file.h @@ -0,0 +1,31 @@ +/* +* a.lp_mp3 - Open Source Atmel AVR / Fox Board based MP3 Players +* Copyright (c) 2003-2006 K. John '2B|!2B' Crispin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs.... mail john{AT}phrozen.org +* +*/ + +typedef struct _MP3_FILE_ID3 { + unsigned char album[256]; + unsigned char artist[256]; + unsigned char track[256]; +} MP3_FILE_ID3; + +int mp3_file_setup(unsigned char *filename, MP3_FILE_ID3 *id3); +int mp3_file_handle(void); +int mp3_file_cleanup(void); diff --git a/package/fonera-mp3/src/lib/mp3_misc.c b/package/fonera-mp3/src/lib/mp3_misc.c new file mode 100644 index 000000000..9fba30fbb --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_misc.c @@ -0,0 +1,129 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "mp3.h" + +#define TMP_PLS_NAME "/var/tmp.pls" + +char* mp3_shell_run(char *filename, char **args, char *buffer, int length){ + int fd1[2], fd2[2], l; + if((pipe(fd1) !=0) || (pipe(fd2)!=0)){ + return NULL; + } + if (fork() == 0){ + close(fd1[1]); + close(fd2[0]); + if ((dup2(fd1[0], STDIN_FILENO) == -1) + || (dup2(fd2[1], STDOUT_FILENO) == -1)){ + exit(0); + } + close(fd1[0]); + close(fd2[1]); + execvp(filename, args); + printf("ERROR running : %s\n", filename); + exit(0); + } + memset(buffer,'\0',length); + close(fd1[0]); + close(fd2[1]); + close(fd1[1]); + wait(NULL); + if((l = read(fd2[0], buffer, length -1)) == -1){ + printf("read failed"); + return NULL; + } + buffer[l] = '\0'; + close (fd2[2]); + return buffer; +} + +int mp3_pls_get_info(unsigned char *pls_url, unsigned char *url, + unsigned char *path, unsigned int *port){ + int ret = MP3_ERROR; + char *exec_args[6]; + int i; + remove(TMP_PLS_NAME); + for (i = 0; i < 5; i++){ + exec_args[i] = malloc(2048); + } + exec_args[0][0] = '\0'; + strcpy(exec_args[1], "wget"); + strcpy(exec_args[2], pls_url); + strcpy(exec_args[3], "-O"); + strcpy(exec_args[4], TMP_PLS_NAME); + exec_args[5] = NULL; + printf("Getting pls file --> %s \n", exec_args[2]); + if(mp3_shell_run("wget", &exec_args[1], + exec_args[0], 2048)){ + struct stat s; + stat(TMP_PLS_NAME, &s); + if(s.st_size > 0){ + FILE *fp = fopen(TMP_PLS_NAME, "r"); + if(fp > 0){ + unsigned char *data = malloc(2048); + *url = '\0'; + while((!*url) && (!feof(fp))){ + if(fgets(data, 2048, fp) != NULL){ + if(strstr(data, "File")){ + unsigned char *t = strstr(data, "="); + if(t){ + t++; + if(mp3_stream_parse_url(t, url, + path, port) != MP3_OK){ + *url = '\0'; + } + } + } + } + } + fclose(fp); + free(data); + if(*url){ + ret = MP3_OK; + } + } + } + } else { + printf("WGET error\n"); + } + for (i = 0; i < 5; i++){ + free(exec_args[i]); + } + if(ret == MP3_OK){ + printf("Found file valid file in pls\n"); + } else { + printf("Error whilst parsing pls\n"); + } + return ret; +} + + + diff --git a/package/fonera-mp3/src/lib/mp3_misc.h b/package/fonera-mp3/src/lib/mp3_misc.h new file mode 100644 index 000000000..512192112 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_misc.h @@ -0,0 +1,26 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + + +char* mp3_shell_run(char *filename, char **args, char *buffer, int length); +int mp3_pls_get_info(unsigned char *pls_url, unsigned char *url, + unsigned char *path, unsigned int *port); diff --git a/package/fonera-mp3/src/lib/mp3_nix_socket.c b/package/fonera-mp3/src/lib/mp3_nix_socket.c new file mode 100644 index 000000000..964690d64 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_nix_socket.c @@ -0,0 +1,166 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <sys/socket.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/poll.h> +#include <stdarg.h> +#include <fcntl.h> +#include "mp3.h" + +#define SOCKET_PATH "/tmp/foxmp3" + +typedef struct _MP3_NIX_SOCKET { + fd_set master; + fd_set clients; + int max; + int listener; +} MP3_NIX_SOCKET; + +static MP3_NIX_SOCKET mp3_nix_socket; + +int mp3_nix_socket_setup(void){ + struct sockaddr_un myaddr; + int yes=1; + int len; + FD_ZERO(&mp3_nix_socket.master); + FD_ZERO(&mp3_nix_socket.clients); + + if ((mp3_nix_socket.listener = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("socket"); + return MP3_ERROR; + } + if (setsockopt(mp3_nix_socket.listener, SOL_SOCKET, + SO_REUSEADDR, &yes, sizeof(int)) == -1) { + perror("setsockopt"); + return MP3_ERROR; + } + myaddr.sun_family = AF_UNIX; + strcpy(myaddr.sun_path, SOCKET_PATH); + unlink(myaddr.sun_path); + len = strlen(myaddr.sun_path) + sizeof(myaddr.sun_family); + if (bind(mp3_nix_socket.listener, (struct sockaddr *)&myaddr, len) == -1) { + perror("bind"); + return MP3_ERROR; + } + if (listen(mp3_nix_socket.listener, 3) == -1) { + perror("listen"); + return MP3_ERROR; + } + FD_SET(mp3_nix_socket.listener, &mp3_nix_socket.master); + mp3_nix_socket.max = mp3_nix_socket.listener; + + return MP3_OK; +}; + +int mp3_nix_socket_handle(void){ + struct sockaddr_un remoteaddr; + socklen_t addrlen; + int i; + int newfd; + char buf[1024]; + int nbytes; + char buf_out[1024]; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + mp3_nix_socket.clients = mp3_nix_socket.master; + + if (select(mp3_nix_socket.max + 1, &mp3_nix_socket.clients, + NULL, NULL, &tv) == -1) { + // sometimes the select is interrupted, because of the alarm signal used by the playtime counter + //perror("error whilst selecting socket"); + return MP3_ERROR; + } + for(i = 0; i <= mp3_nix_socket.max; i++) { + if (FD_ISSET(i, &mp3_nix_socket.clients)) { + if (i == mp3_nix_socket.listener) { + addrlen = sizeof(remoteaddr); + if ((newfd = accept(mp3_nix_socket.listener, + (struct sockaddr *)&remoteaddr, + &addrlen)) == -1) { + perror("error whilst accepting socket"); + return MP3_ERROR; + } else { + FD_SET(newfd, &mp3_nix_socket.master); + if (newfd > mp3_nix_socket.max) { + mp3_nix_socket.max = newfd; + } + fcntl(newfd, F_SETFL, O_NONBLOCK); + printf("New socket client on %d\n", newfd); + } + } else { + if ((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0) { + if (nbytes == 0) { + printf("selectserver: socket hung up %d\n", i); + close(i); + FD_CLR(i, &mp3_nix_socket.master); + } else { + printf("error whilst receiving socket %d\n", i); + } + } else { + buf[nbytes] = '\0'; + printf("Got data : %s\n", buf); + mp3_parser_incoming(buf,buf_out); + if(*buf_out != '\0'){ + send(i, buf_out, strlen(buf_out), 0); + } + } + } + } + } + return MP3_OK; +} + +void mp3_nix_socket_write(unsigned char *data, ...){ + unsigned int i; + unsigned char t[2048]; + va_list ap; + + // clear possible dead sockets + mp3_nix_socket_handle(); + memset(t, 0, 2048); + va_start(ap, data); + vsprintf(t, data, ap); + va_end(ap); + printf("Sending data --> %s\n", t); + for(i = 0; i <= mp3_nix_socket.max; i++) { + if (FD_ISSET(i, &mp3_nix_socket.master)) { + if (i != mp3_nix_socket.listener) { + printf("Sending on socket %d\n", i); + send(i, t, strlen(t), 0); + } + } + } + printf("Finished sending\n"); +} + +int mp3_nix_socket_cleanup(void){ + return MP3_OK; +}; + diff --git a/package/fonera-mp3/src/lib/mp3_nix_socket.h b/package/fonera-mp3/src/lib/mp3_nix_socket.h new file mode 100644 index 000000000..d97f82ce6 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_nix_socket.h @@ -0,0 +1,25 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ +int mp3_nix_socket_setup(void); +int mp3_nix_socket_handle(void); +int mp3_nix_socket_cleanup(void); +void mp3_nix_socket_write(unsigned char *data, ...); diff --git a/package/fonera-mp3/src/lib/mp3_playtime.c b/package/fonera-mp3/src/lib/mp3_playtime.c new file mode 100644 index 000000000..89325943f --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_playtime.c @@ -0,0 +1,61 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + + +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include "mp3.h" + + +static MP3_PLAYTIME *mp3_playtime; + +void sig_alarm_handler(int sig){ + alarm(1); + mp3_playtime->playtime++; + mp3_playtime->playtime_secs++; + if(mp3_playtime->playtime_secs > 59){ + mp3_playtime->playtime_mins++; + mp3_playtime->playtime_secs = 0; + } + state_generic_event(MP3_EVENT_GENERIC_PLAYTIME, 0, NULL); +}; + +void mp3_playtime_init(MP3_PLAYTIME *playtime){ + mp3_playtime = playtime; + signal(SIGALRM, sig_alarm_handler); +}; + +void mp3_playtime_start(void){ + mp3_playtime->playtime = 0; + mp3_playtime->playtime_secs = 0; + mp3_playtime->playtime_mins = 0; + alarm(1); + state_generic_event(MP3_EVENT_GENERIC_PLAYTIME, 0, NULL); +}; + +void mp3_playtime_stop(void){ + alarm(0); + mp3_playtime->playtime = 0; + mp3_playtime->playtime_secs = 0; + mp3_playtime->playtime_mins = 0; +}; diff --git a/package/fonera-mp3/src/lib/mp3_playtime.h b/package/fonera-mp3/src/lib/mp3_playtime.h new file mode 100644 index 000000000..618d1224f --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_playtime.h @@ -0,0 +1,33 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + + +typedef struct _MP3_PLAYTIME { + unsigned int playtime; + unsigned int playtime_secs; + unsigned int playtime_mins; +} MP3_PLAYTIME; + +void mp3_playtime_init(MP3_PLAYTIME *playtime); +void mp3_playtime_start(void); +void mp3_playtime_stop(void); + diff --git a/package/fonera-mp3/src/lib/mp3_socket_parser.c b/package/fonera-mp3/src/lib/mp3_socket_parser.c new file mode 100644 index 000000000..1702282e8 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_socket_parser.c @@ -0,0 +1,104 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "mp3.h" + +#define TOKEN_MAX 16 +#define TOKEN_SIZE 256 + +static unsigned char mp3_parser_tokens[TOKEN_MAX][TOKEN_SIZE]; + +int mp3_parser_tokenize(unsigned char *in){ + int i = 0; + char *token = in; + char *tmp; + do { + tmp = strstr(token, " "); + if(tmp){ + *tmp = '\0'; + strcpy(mp3_parser_tokens[i], token); + tmp++; + token = tmp; + } else { + strcpy(mp3_parser_tokens[i], token); + }; + i++; + }while((i < TOKEN_MAX) && (tmp)); + return i; +}; + +extern int state_current; +void mp3_parser_incoming(unsigned char *in, unsigned char *out){ + int c = mp3_parser_tokenize(in); + int ret = 0; + int t1; + if(c){ + printf("Parsing command from frontend app -> %s --- %d tokens\n", in, c); + if((!strcmp(mp3_parser_tokens[0], "PLAY")) && (c == 2)){ + state_event(MP3_EVENT_FILE, state_new_event(mp3_parser_tokens[1], 0)); + ret = 1; + } else if((!strcmp(mp3_parser_tokens[0], "STREAM")) + && (c == 3)){ + if(!strcmp(mp3_parser_tokens[1], "pls")){ + state_event(MP3_EVENT_STREAM, state_new_event(mp3_parser_tokens[2], STREAM_PLS)); + ret = 1; + } else if(!strcmp(mp3_parser_tokens[1], "url")){ + state_event(MP3_EVENT_STREAM, state_new_event(mp3_parser_tokens[2], STREAM_URL)); + ret = 1; + } + } else if((!strcmp(mp3_parser_tokens[0], "VOLUME")) + && (c == 2)){ + t1 = atoi(mp3_parser_tokens[1]); + state_generic_event(MP3_EVENT_GENERIC_VOLUME, t1, NULL); + ret = 1; + } else if((!strcmp(mp3_parser_tokens[0], "STOP")) + && (c == 1)){ + state_event(MP3_EVENT_STOP, NULL); + ret = 1; + } else if((!strcmp(mp3_parser_tokens[0], "STATE")) + && (c == 1)){ + state_generic_event(MP3_EVENT_GENERIC_STATE, 0, out); + return; + } else if((!strcmp(mp3_parser_tokens[0], "BASS")) + && (c == 2)){ + t1 = atoi(mp3_parser_tokens[1]); + state_generic_event(MP3_EVENT_GENERIC_BASS, t1, NULL); + ret = 1; + } + if(ret){ + sprintf(out, "OK\n"); + printf("Command parsed ok.\n"); + } else { + + sprintf(out, "ERROR\n"); + printf("Command parsed with error.\n"); + }; + } else { + printf("Got command from frontend with 0 tokens.\n"); + }; +}; + + diff --git a/package/fonera-mp3/src/lib/mp3_socket_parser.h b/package/fonera-mp3/src/lib/mp3_socket_parser.h new file mode 100644 index 000000000..ebb517939 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_socket_parser.h @@ -0,0 +1,24 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +void mp3_parser_incoming(unsigned char *in, unsigned char *out); + diff --git a/package/fonera-mp3/src/lib/mp3_statemachine.h b/package/fonera-mp3/src/lib/mp3_statemachine.h new file mode 100644 index 000000000..072bb380c --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_statemachine.h @@ -0,0 +1,26 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + + +void mp3_init_statemachine(); +void mp3_statemachine_main_loop(); + diff --git a/package/fonera-mp3/src/lib/mp3_states.c b/package/fonera-mp3/src/lib/mp3_states.c new file mode 100644 index 000000000..f6f03eb87 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_states.c @@ -0,0 +1,224 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/poll.h> +#include <signal.h> +#include "mp3.h" + +typedef struct _MP3_STATE { + struct { + unsigned char volume; + unsigned char bass; + unsigned char treble; + } decoder; + struct { + unsigned char name[2048]; + MP3_FILE_ID3 id3; + } file; + struct { + unsigned char url[2048]; + unsigned char path[256]; + unsigned int port; + } stream; + MP3_PLAYTIME playtime; + } MP3_STATE; + +static MP3_STATE mp3_state; + +void state_startup_enter(int state_last, int event, EVENT_PARAM *param){ + mp3_state.decoder.volume = 0x30; + mp3_state.decoder.bass = 1; + mp3_state.file.name[0] = '\0'; + mp3_state.stream.url[0] = '\0'; + mp3_state.stream.path[0] = '\0'; + mp3_state.stream.port = 0; + mp3_playtime_init(&mp3_state.playtime); + mp3_init(); + mp3_nix_socket_setup(); + mp3_tcp_socket_setup(); +}; + +void state_idle_enter(int state_last, int event, EVENT_PARAM *param){ + mp3_stop(); + mp3_playtime_stop(); +}; + +void state_file_startup_enter(int state_last, int event, EVENT_PARAM *param){ + if(mp3_file_setup(param->text, &mp3_state.file.id3) == MP3_OK){ + strcpy(mp3_state.file.name, param->text); + } else { + state_event(MP3_EVENT_ERROR, NULL); + }; +}; + +void state_file_startup_leave(int state_new, int event){ + if(state_new == MP3_STATE_FILE_HANDLE){ + mp3_play(); + mp3_playtime_start(); + mp3_nix_socket_write("START FILE\n"); + }; +}; + +void state_file_handle_enter(int state_last, int event, EVENT_PARAM *param){ + int ret = mp3_file_handle(); + if(ret == MP3_ERROR){ + state_event(MP3_EVENT_ERROR, NULL); + }; + if(ret == MP3_END){ + state_event(MP3_EVENT_END, NULL); + }; + +}; + +void state_file_handle_leave(int state_new, int event){ + if(state_new != MP3_STATE_FILE_HANDLE){ + mp3_playtime_stop(); + mp3_file_cleanup(); + mp3_nix_socket_write("STOP FILE\n"); + }; +}; + +void state_stream_startup_enter(int state_last, int event, EVENT_PARAM *param){ + if(mp3_stream_setup(param->text, param->numeric, mp3_state.stream.url, + mp3_state.stream.path, &mp3_state.stream.port) != MP3_OK){ + state_event(MP3_EVENT_ERROR, NULL); + }; +}; + +void state_stream_startup_leave(int state_new, int event){ + if(state_new == MP3_STATE_STREAM_HANDLE){ + mp3_play(); + mp3_playtime_start(); + mp3_nix_socket_write("START STREAM\n"); + }; +}; + +void state_stream_handle_enter(int state_last, int event, EVENT_PARAM *param){ + if(mp3_stream_handle() == MP3_ERROR){ + state_event(MP3_EVENT_ERROR, NULL); + } +}; + +void state_stream_handle_leave(int state_new, int event){ + if(state_new != MP3_STATE_STREAM_HANDLE){ + mp3_stream_cleanup(); + mp3_playtime_stop(); + mp3_nix_socket_write("STOP STREAM\n"); + } +}; + +extern STATE states[MAX_STATE_COUNT]; +void state_error_enter(int state_last, int event, EVENT_PARAM *param){ + if(param){ + printf("Error in state %s -> %s\n", states[state_last].name, param->text); + mp3_nix_socket_write("ERROR Error in state %s -> %s\n", states[state_last].name, param->text); + } else { + printf("Unknown error in state %s\n", states[state_last].name); + }; +}; + +void state_shutdown_enter(int state_last, int event, EVENT_PARAM *param){ + printf("Entering state SHUTDOWN ...\n"); + printf("Shutting down player ...\n"); + mp3_nix_socket_cleanup(); + mp3_tcp_socket_cleanup(); + printf("Quitting statemachine ...\n"); + exit(0); +}; +extern int state_current; +void state_generic_event(unsigned int event, unsigned char in_int, + unsigned char *out_uchar){ + switch(event){ + case MP3_EVENT_GENERIC_VOLUME: + mp3_state.decoder.volume = in_int; + mp3_set_volume(mp3_state.decoder.volume, + mp3_state.decoder.volume); + mp3_nix_socket_write("VOLUME %d\n", mp3_state.decoder.volume); + break; + case MP3_EVENT_GENERIC_BASS: + mp3_state.decoder.bass = in_int; + mp3_bass(8, mp3_state.decoder.treble, + 8, mp3_state.decoder.bass); + mp3_nix_socket_write("BASS %d\n", mp3_state.decoder.bass); + break; + case MP3_EVENT_GENERIC_STATE: + out_uchar[0] = '\0'; + sprintf(out_uchar, "%sVOLUME %d\n", + out_uchar, mp3_state.decoder.volume); + sprintf(out_uchar, "%sBASS %d\n", + out_uchar, mp3_state.decoder.bass); + sprintf(out_uchar, "%sTREBLE %d\n", + out_uchar, mp3_state.decoder.treble); + sprintf(out_uchar, "%sPLAYTIME %d\n", + out_uchar, + (mp3_state.playtime.playtime_mins * 60) + mp3_state.playtime.playtime_secs); + switch(state_current){ + case MP3_STATE_IDLE: + sprintf(out_uchar, "%sSTATE MP3_STATE_IDLE\n", out_uchar); + break; + case MP3_STATE_FILE_START: + case MP3_STATE_FILE_HANDLE: + sprintf(out_uchar, "%sFILE %s\n", out_uchar, + mp3_state.file.name); + if(strlen(mp3_state.file.id3.artist)){ + sprintf(out_uchar, "%sID3_ARTIST %s\n", + out_uchar, + mp3_state.file.id3.artist); + }; + if(strlen(mp3_state.file.id3.album)){ + sprintf(out_uchar, "%sID3_ALBUM %s\n", + out_uchar, + mp3_state.file.id3.album); + }; + if(strlen(mp3_state.file.id3.album)){ + sprintf(out_uchar, "%sID3_TRACK %s\n", + out_uchar, + mp3_state.file.id3.track); + }; + sprintf(out_uchar, "%sSTATE MP3_STATE_FILE\n", out_uchar); + break; + case MP3_STATE_STREAM_START: + case MP3_STATE_STREAM_HANDLE: + sprintf(out_uchar, "%sSTREAM %s:%d%s\n", out_uchar, + mp3_state.stream.url, + mp3_state.stream.port, + mp3_state.stream.path); + sprintf(out_uchar, "%sSTATE MP3_STATE_STREAM\n", out_uchar); + break; + default: + sprintf(out_uchar, "STATE Unkonwn\n"); + break; + }; + sprintf(out_uchar, "%sOK\n", out_uchar); + break; + case MP3_EVENT_GENERIC_PLAYTIME: + // printf("%02d:%02d\n", mp3_state.playtime.playtime_mins, + // mp3_state.playtime.playtime_secs); + break; + default: + break; + }; +}; + diff --git a/package/fonera-mp3/src/lib/mp3_states.h b/package/fonera-mp3/src/lib/mp3_states.h new file mode 100644 index 000000000..073c28bb1 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_states.h @@ -0,0 +1,114 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +typedef struct _EVENT { + unsigned char *name; +} EVENT; + +typedef struct _EVENT_PARAM { + int numeric; + unsigned char *text; +} EVENT_PARAM; + +typedef void (*STATE_ENTER)(int state_last, int event, EVENT_PARAM *param); +typedef void (*STATE_LEAVE)(int state_new, int event); + +typedef struct _STATE { + unsigned char *name; + STATE_ENTER enter; + STATE_LEAVE leave; +} STATE; + +typedef struct _TRANSITION { + int old_state; + int event; + int new_state; +} TRANSITION; + +// a = id, b = name, c = enter, d = leave +#define STATE_ADD(a, b, c, d) { \ + if((a > 0) && (a < MAX_STATE_COUNT)){ \ + states[a].name = strdup(b); \ + states[a].enter = c; \ + states[a].leave = d; \ + } \ + } + +// a = old, b = event, c = new +#define TRANSITION_ADD(a, b, c) { \ + if((transition_count >= 0) && \ + (transition_count < MAX_TRANSITION_COUNT)){ \ + transitions[transition_count].old_state = a; \ + transitions[transition_count].event = b; \ + transitions[transition_count].new_state = c; \ + transition_count++; \ + } \ + } + +// a = id, b = name +#define EVENT_ADD(a, b) { \ + if((a > 0) && (a < MAX_EVENT_COUNT)){ \ + events[a].name = strdup(b); \ + } \ + } +#define MAX_EVENT_COUNT 20 +#define MAX_STATE_COUNT 20 +#define MAX_TRANSITION_COUNT 60 + +#define MP3_STATE_NONE 0 +#define MP3_STATE_STARTUP 1 +#define MP3_STATE_IDLE 2 +#define MP3_STATE_FILE_START 3 +#define MP3_STATE_FILE_HANDLE 4 +#define MP3_STATE_STREAM_START 5 +#define MP3_STATE_STREAM_HANDLE 6 +#define MP3_STATE_ERROR 7 +#define MP3_STATE_SHUTDOWN 8 +#define MP3_STATE_DEFAULT 9 + +#define MP3_EVENT_TIMEOUT 1 +#define MP3_EVENT_FILE 2 +#define MP3_EVENT_STREAM 3 +#define MP3_EVENT_STOP 4 +#define MP3_EVENT_ERROR 5 +#define MP3_EVENT_SHUTDOWN 6 +#define MP3_EVENT_END 7 + +#define MP3_EVENT_GENERIC_VOLUME 0 +#define MP3_EVENT_GENERIC_STATE 1 +#define MP3_EVENT_GENERIC_BASS 2 +#define MP3_EVENT_GENERIC_PLAYTIME 3 + +void state_startup_enter(int state_last, int event, EVENT_PARAM *param); +void state_idle_enter(int state_last, int event, EVENT_PARAM *param); +void state_file_startup_enter(int state_last, int event, EVENT_PARAM *param); +void state_file_startup_leave(int state_new, int event); +void state_file_handle_enter(int state_last, int event, EVENT_PARAM *param); +void state_file_handle_leave(int state_new, int event); +void state_stream_startup_enter(int state_last, int event, EVENT_PARAM *param); +void state_stream_startup_leave(int state_last, int event); +void state_stream_handle_enter(int state_last, int event, EVENT_PARAM *param); +void state_stream_handle_leave(int state_new, int event); +void state_error_enter(int state_last, int event, EVENT_PARAM *param); +void state_shutdown_enter(int state_last, int event, EVENT_PARAM *param); +void state_generic_event(unsigned int event, unsigned char in_int, + unsigned char *out_uchar); diff --git a/package/fonera-mp3/src/lib/mp3_stream.c b/package/fonera-mp3/src/lib/mp3_stream.c new file mode 100644 index 000000000..0dd3437e3 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_stream.c @@ -0,0 +1,340 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <netdb.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/time.h> +#include <sys/poll.h> + +#include "mp3.h" + +typedef struct _MP3_STREAM { + unsigned char buf[MAX_PACKET_SIZE + 1]; + int sockfd; + unsigned char mp3_buffer[MAX_BUFFER_SIZE]; + unsigned long int mp3_buffer_write_pos; + unsigned long int mp3_buffer_read_pos; + unsigned long int mp3_data_in_buffer; + unsigned char transmit_success; + unsigned int buffer_error; + MP3_DATA mp3_data; + unsigned int numbytes; + unsigned int metainterval; +} MP3_STREAM; + +static MP3_STREAM mp3_stream; + +int connect_timeout (int sfd, struct sockaddr *addr, int addrlen, + struct timeval *timeout) { + struct timeval sv; + int svlen = sizeof sv; + int ret; + + if (!timeout) { + return connect (sfd, addr, addrlen); + }; + if (getsockopt (sfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&sv, &svlen) < 0) { + return -1; + }; + if (setsockopt (sfd, SOL_SOCKET, SO_SNDTIMEO, timeout,sizeof *timeout) < 0) { + return -1; + }; + ret = connect (sfd, addr, addrlen); + setsockopt (sfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&sv, sizeof sv); + + return ret; +} + +int mp3_stream_parse_url(unsigned char *url, unsigned char *ip, + unsigned char *path, unsigned int *port){ + int len = strlen(url) - 1; + while(((url[len] == '\n')||(url[len] == ' ')) && (len > 0)){ + url[len] = '\0'; + len--; + }; + ip[0] = '\0'; + printf("Parsing stream url : %s\n", url); + unsigned char *http = strstr(url, "http://"); + *port = 80; + if(http){ + url = http + 7; + unsigned char *p = strstr(url, ":"); + if(p){ + *p = '\0'; + p ++; + strcpy(ip, url); + *port = atoi(p); + } + unsigned char *p2 = strstr((p)?(p):(url), "/"); + if(p2){ + strcpy(path, p2); + *p2 = '\0'; + if(!p){ + strcpy(ip, url); + } + + } else { + strcpy(path, "/"); + }; + printf("ip -> %s\nport -> %d\npath -> %s\n", ip, *port, path); + return MP3_OK; + }; + return MP3_ERROR; +}; + +int mp3_stream_get_url(unsigned char *url, unsigned int type, + unsigned char *ip, unsigned int *port, unsigned char *path){ + if(type == STREAM_PLS){ + if(mp3_pls_get_info(url, ip, path, port) == MP3_OK){ + return MP3_OK; + }; + } else if(type == STREAM_URL){ + if(mp3_stream_parse_url(url, ip, path, port) == MP3_OK){ + return MP3_OK; + }; + }; + return MP3_ERROR; +}; + +int mp3_stream_setup(unsigned char *url, unsigned int type, unsigned char *ip, + unsigned char *path, unsigned int *port){ + struct hostent *he; + struct sockaddr_in their_addr; + unsigned int error = 0; + if(mp3_stream_get_url(url, type, ip, port, path) == MP3_ERROR){ + return MP3_ERROR; + }; + + mp3_stream.mp3_buffer_write_pos = 0; + mp3_stream.mp3_buffer_read_pos = 0; + mp3_stream.mp3_data_in_buffer = 0; + mp3_stream.transmit_success = 1; + mp3_stream.buffer_error = 0; + mp3_stream.metainterval = 0; + + mp3_reset(); + + if ((he=gethostbyname(ip)) == NULL) { + perror("Error in gethostbyname. Wrong url/ip ?"); + return MP3_ERROR; + } + if ((mp3_stream.sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + perror("Error opening stream socket"); + return MP3_ERROR; + } + + their_addr.sin_family = AF_INET; + their_addr.sin_port = htons(*port); + their_addr.sin_addr = *((struct in_addr *)he->h_addr); + memset(&(their_addr.sin_zero), '\0', 8); + + struct timeval tv; + tv.tv_sec = 4; + tv.tv_usec = 0; + + if (connect_timeout(mp3_stream.sockfd, (struct sockaddr *)&their_addr, + sizeof(struct sockaddr), &tv) == -1) { + perror("connect"); + return MP3_ERROR; + } + + unsigned char icy_request[1024]; + sprintf(icy_request, + "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: A.LP-MP3\r\nAccept: */*\r\nicy-metadata:0\r\n\r\n", + path, + ip); + printf("Sending request :\n%s\n", icy_request); + send(mp3_stream.sockfd, icy_request, strlen(icy_request), 0); + //wait 200 ms ??!? some icecast servers seem to not push data to us fast enough ?!?!? + poll(0,0,200); + if ((mp3_stream.numbytes=recv(mp3_stream.sockfd, mp3_stream.buf, MAX_PACKET_SIZE-1, 0)) == -1) { + perror("recv"); + return MP3_ERROR; + } + mp3_stream.buf[mp3_stream.numbytes] = '\0'; + printf("numbytes = %d\n", mp3_stream.numbytes); + printf("------\n%s\n---------\n", mp3_stream.buf); + unsigned char *p = strstr(mp3_stream.buf, "\r\n\r\n"); + if(p) { + *p = '\0'; + p += 4; + } else { + printf("funky p error in stream.c\n"); + } + printf("Received: \n%s\n", mp3_stream.buf); + if(((unsigned char*)strstr(mp3_stream.buf, "ICY 200 OK") != mp3_stream.buf) && + ((unsigned char*)strstr(mp3_stream.buf, "HTTP/1.1 200 OK") != mp3_stream.buf) && + ((unsigned char*)strstr(mp3_stream.buf, "HTTP/1.0 200 OK") != mp3_stream.buf)) { + return MP3_ERROR; + }; + int p_buf = p - mp3_stream.buf; + unsigned char *p2; + p2 = strstr(mp3_stream.buf, "icy-metaint:"); + if(p2){ + p2 = strstr(p2, ":"); + p2++; + unsigned char *p3 = strstr(p2, "\r"); + *p3 = '\0'; + mp3_stream.metainterval = atoi(p2); + printf("META INT == %d\n", mp3_stream.metainterval); + } + + printf("starting to buffer\n"); + memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos], + p, p_buf); + mp3_stream.mp3_buffer_write_pos += p_buf; + mp3_stream.mp3_data_in_buffer += p_buf; + + while(mp3_stream.mp3_data_in_buffer + (unsigned long int)MAX_PACKET_SIZE + < (unsigned long int)MAX_BUFFER_SIZE){ + if ((mp3_stream.numbytes=recv(mp3_stream.sockfd, mp3_stream.buf, + MAX_PACKET_SIZE-1, 0)) == -1) { + perror("disconnected"); + printf("disconntected\n"); + return MP3_ERROR; + } + + if(mp3_stream.numbytes == 0){ + sleep(1); + if(++error > 3){ + perror("disconnected"); + printf("disconntected\n"); + return MP3_ERROR; + } + } + + memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos], + mp3_stream.buf, mp3_stream.numbytes); + mp3_stream.mp3_buffer_write_pos += mp3_stream.numbytes; + mp3_stream.mp3_data_in_buffer += mp3_stream.numbytes; + printf("%ld ", mp3_stream.mp3_data_in_buffer); + fflush(stdout); + + }; + printf("\n"); + mp3_stream.mp3_data.state = MP3_PLAYING; + while(mp3_stream.mp3_data_in_buffer >= 2 * MP3_CHUNK_SIZE){ + memcpy(mp3_stream.mp3_data.mp3, + &mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_read_pos], + MP3_CHUNK_SIZE); + mp3_send_data_to_buffer(mp3_stream.mp3_data); + mp3_stream.mp3_buffer_read_pos += MP3_CHUNK_SIZE; + mp3_stream.mp3_data_in_buffer -= MP3_CHUNK_SIZE; + }; + + printf("Starting to play stream\n"); + return MP3_OK; +} + +static int max_recv_errors = 10; +int mp3_stream_handle(void){ + if(MAX_BUFFER_SIZE >= mp3_stream.mp3_data_in_buffer + MAX_PACKET_SIZE){ + struct pollfd ufds; + ufds.fd = mp3_stream.sockfd; + ufds.events = POLLIN|POLLHUP; + + if(poll(&ufds, 1, 2000) > 0){ + max_recv_errors = 10; + if ((mp3_stream.numbytes=recv(mp3_stream.sockfd, mp3_stream.buf, MAX_PACKET_SIZE-1, 0)) == -1) { + perror("recv"); + } + if((mp3_stream.numbytes != EAGAIN)&& (mp3_stream.numbytes != -1)){ + if(mp3_stream.mp3_buffer_write_pos + mp3_stream.numbytes <= MAX_BUFFER_SIZE){ + memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos], + mp3_stream.buf, mp3_stream.numbytes); + mp3_stream.mp3_buffer_write_pos += mp3_stream.numbytes; + mp3_stream.mp3_data_in_buffer += mp3_stream.numbytes; + if(mp3_stream.mp3_buffer_write_pos == MAX_BUFFER_SIZE){ + mp3_stream.mp3_buffer_write_pos = 0; + }; + } else { + unsigned int buffer_offset = MAX_BUFFER_SIZE - mp3_stream.mp3_buffer_write_pos; + memcpy(&mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_write_pos], + mp3_stream.buf, buffer_offset); + mp3_stream.mp3_buffer_write_pos = + mp3_stream.numbytes - buffer_offset; + memcpy(&mp3_stream.mp3_buffer[0], &mp3_stream.buf[buffer_offset], + mp3_stream.mp3_buffer_write_pos); + mp3_stream.mp3_data_in_buffer += mp3_stream.numbytes; + }; + }; + } else { + max_recv_errors--; + if(max_recv_errors == 0){ + printf("recv error\n"); + return MP3_ERROR; + }; + }; + } + + if(mp3_stream.mp3_data_in_buffer < MP3_CHUNK_SIZE){ + printf("radio_buffer is empty\n"); + mp3_stream.buffer_error ++; + if(mp3_stream.buffer_error > MAX_BUFFER_ERROR){ + return MP3_ERROR; + }; + } else { + mp3_stream.buffer_error = 0; + do{ + if(mp3_stream.transmit_success){ + if(MAX_BUFFER_SIZE >= mp3_stream.mp3_buffer_read_pos + MP3_CHUNK_SIZE){ + memcpy(mp3_stream.mp3_data.mp3, + &mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_read_pos], MP3_CHUNK_SIZE); + mp3_stream.mp3_buffer_read_pos += MP3_CHUNK_SIZE; + mp3_stream.mp3_data_in_buffer -= MP3_CHUNK_SIZE; + if(mp3_stream.mp3_buffer_read_pos == MAX_BUFFER_SIZE){ + mp3_stream.mp3_buffer_read_pos = 0; + }; + + } else { + unsigned int buffer_offset = MAX_BUFFER_SIZE - mp3_stream.mp3_buffer_read_pos; + memcpy(mp3_stream.mp3_data.mp3, + &mp3_stream.mp3_buffer[mp3_stream.mp3_buffer_read_pos], + buffer_offset); + mp3_stream.mp3_buffer_read_pos = MP3_CHUNK_SIZE - buffer_offset; + memcpy(&mp3_stream.mp3_data.mp3[buffer_offset], mp3_stream.mp3_buffer, + mp3_stream.mp3_buffer_read_pos); + }; + } + if(!mp3_send_data_to_buffer(mp3_stream.mp3_data)){ + mp3_stream.transmit_success = 0; + } else { + mp3_stream.transmit_success = 1; + }; + } while((mp3_stream.transmit_success)&&(mp3_stream.mp3_data_in_buffer > MP3_CHUNK_SIZE)); + }; + return MP3_OK; +}; + +int mp3_stream_cleanup(void){ + close(mp3_stream.sockfd); + return MP3_OK; +} diff --git a/package/fonera-mp3/src/lib/mp3_stream.h b/package/fonera-mp3/src/lib/mp3_stream.h new file mode 100644 index 000000000..d8e09ba5e --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_stream.h @@ -0,0 +1,34 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#define MAX_PACKET_SIZE 1500 +#define MAX_BUFFER_SIZE (64*2048) +#define MAX_BUFFER_ERROR 128 + +#define STREAM_URL 0 +#define STREAM_PLS 1 +int mp3_stream_setup(unsigned char *url, unsigned int type, unsigned char *ip, + unsigned char *path, unsigned int *port); +int mp3_stream_handle(void); +int mp3_stream_cleanup(void); +int mp3_stream_parse_url(unsigned char *url, unsigned char *ip, + unsigned char *path, unsigned int *port); diff --git a/package/fonera-mp3/src/lib/mp3_tcp_socket.c b/package/fonera-mp3/src/lib/mp3_tcp_socket.c new file mode 100644 index 000000000..89c8997fe --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_tcp_socket.c @@ -0,0 +1,145 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/wait.h> +#include <signal.h> +#include <sys/poll.h> + +#include "mp3.h" + +#define SOCKET_PORT 369 +#define BACKLOG 10 + +typedef struct _MP3_TCP_SOCKET { + fd_set master; + fd_set clients; + int max; + int listener; +} MP3_TCP_SOCKET; + +static MP3_TCP_SOCKET mp3_tcp_socket; + +int mp3_tcp_socket_setup(void){ + struct sockaddr_in myaddr; + int yes=1; + FD_ZERO(&mp3_tcp_socket.master); + FD_ZERO(&mp3_tcp_socket.clients); + + if ((mp3_tcp_socket.listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + perror("socket"); + return MP3_ERROR; + } + if (setsockopt(mp3_tcp_socket.listener, SOL_SOCKET, + SO_REUSEADDR, &yes, sizeof(int)) == -1) { + perror("setsockopt"); + return MP3_ERROR; + } + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(SOCKET_PORT); + myaddr.sin_addr.s_addr = INADDR_ANY; + memset(&(myaddr.sin_zero), '\0', 8); + if (bind(mp3_tcp_socket.listener, (struct sockaddr *)&myaddr, sizeof(struct sockaddr)) == -1) { + perror("bind"); + return MP3_ERROR; + } + if (listen(mp3_tcp_socket.listener, 3) == -1) { + perror("listen"); + return MP3_ERROR; + } + FD_SET(mp3_tcp_socket.listener, &mp3_tcp_socket.master); + mp3_tcp_socket.max = mp3_tcp_socket.listener; + printf("Started tcp socket on port %d\n", SOCKET_PORT); + return MP3_OK; +}; + +int mp3_tcp_socket_handle(void){ + struct sockaddr_in remoteaddr; + socklen_t addrlen; + int i; + int newfd; + char buf[1024]; + int nbytes; + char buf_out[1024]; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + mp3_tcp_socket.clients = mp3_tcp_socket.master; + + if (select(mp3_tcp_socket.max + 1, &mp3_tcp_socket.clients, + NULL, NULL, &tv) == -1) { + return MP3_ERROR; + } + for(i = 0; i <= mp3_tcp_socket.max; i++) { + if (FD_ISSET(i, &mp3_tcp_socket.clients)) { + if (i == mp3_tcp_socket.listener) { + addrlen = sizeof(remoteaddr); + if ((newfd = accept(mp3_tcp_socket.listener, + (struct sockaddr *)&remoteaddr, + &addrlen)) == -1) { + perror("error whilst accepting socket"); + return MP3_ERROR; + } else { + printf("New TCP connection from %s\n", + inet_ntoa(remoteaddr.sin_addr)); + FD_SET(newfd, &mp3_tcp_socket.master); + if (newfd > mp3_tcp_socket.max) { + mp3_tcp_socket.max = newfd; + } + } + } else { + if ((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0) { + if (nbytes == 0) { + perror("selectserver: socket hung up\n"); + } else { + perror("error whilst receiving socket"); + } + close(i); + FD_CLR(i, &mp3_tcp_socket.master); + } else { + buf[nbytes] = '\0'; + printf("Got data : %s\n", buf); + mp3_parser_incoming(buf,buf_out); + if(*buf_out != '\0'){ + send(i, buf_out, strlen(buf_out), 0); + } + close(i); + FD_CLR(i, &mp3_tcp_socket.master); + } + } + } + } + return MP3_OK; +}; + +int mp3_tcp_socket_cleanup(void){ + return MP3_OK; +}; + diff --git a/package/fonera-mp3/src/lib/mp3_tcp_socket.h b/package/fonera-mp3/src/lib/mp3_tcp_socket.h new file mode 100644 index 000000000..f4b5dc422 --- /dev/null +++ b/package/fonera-mp3/src/lib/mp3_tcp_socket.h @@ -0,0 +1,24 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ +int mp3_tcp_socket_setup(void); +int mp3_tcp_socket_handle(void); +int mp3_tcp_socket_cleanup(void); diff --git a/package/fonera-mp3/src/mp3_main.c b/package/fonera-mp3/src/mp3_main.c new file mode 100644 index 000000000..f1f21d677 --- /dev/null +++ b/package/fonera-mp3/src/mp3_main.c @@ -0,0 +1,204 @@ +/* +* FOXMP3 +* Copyright (c) 2006 acmesystems.it - john@acmesystems.it +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA +* +* Feedback, Bugs... info@acmesystems.it +* +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/poll.h> +#include <signal.h> +#include "lib/mp3.h" + +STATE states[MAX_STATE_COUNT]; +static EVENT events[MAX_EVENT_COUNT]; +static TRANSITION transitions[MAX_TRANSITION_COUNT]; +static int transition_count = 0; +int state_current = MP3_STATE_STARTUP; +static int state_previous = MP3_STATE_NONE; +static int shutdown = 0; + +void state_setup(void){ + EVENT_ADD(MP3_EVENT_TIMEOUT, "Timeout"); + EVENT_ADD(MP3_EVENT_FILE, "File"); + EVENT_ADD(MP3_EVENT_STREAM, "Stream"); + EVENT_ADD(MP3_EVENT_STOP, "Stop"); + EVENT_ADD(MP3_EVENT_ERROR, "Error"); + EVENT_ADD(MP3_EVENT_SHUTDOWN, "Shutdown"); + EVENT_ADD(MP3_EVENT_END, "End"); + + STATE_ADD(MP3_STATE_STARTUP, "Startup", state_startup_enter, NULL); + STATE_ADD(MP3_STATE_IDLE, "Idle", state_idle_enter, NULL); + STATE_ADD(MP3_STATE_FILE_START, "File startup", state_file_startup_enter, state_file_startup_leave); + STATE_ADD(MP3_STATE_FILE_HANDLE, "File handle", state_file_handle_enter, state_file_handle_leave); + STATE_ADD(MP3_STATE_STREAM_START, "Stream start", state_stream_startup_enter, state_stream_startup_leave); + STATE_ADD(MP3_STATE_STREAM_HANDLE, "Stream handle", state_stream_handle_enter, state_stream_handle_leave); + STATE_ADD(MP3_STATE_ERROR, "Error", state_error_enter, NULL); + STATE_ADD(MP3_STATE_SHUTDOWN, "Shutdown", state_shutdown_enter, NULL); + + TRANSITION_ADD(MP3_STATE_STARTUP, MP3_EVENT_TIMEOUT, MP3_STATE_IDLE); + + TRANSITION_ADD(MP3_STATE_IDLE, MP3_EVENT_TIMEOUT, MP3_STATE_IDLE); + TRANSITION_ADD(MP3_STATE_IDLE, MP3_EVENT_FILE, MP3_STATE_FILE_START); + TRANSITION_ADD(MP3_STATE_IDLE, MP3_EVENT_STREAM, MP3_STATE_STREAM_START); + + TRANSITION_ADD(MP3_STATE_FILE_START, MP3_EVENT_TIMEOUT, MP3_STATE_FILE_HANDLE); + TRANSITION_ADD(MP3_STATE_FILE_START, MP3_EVENT_ERROR, MP3_STATE_ERROR); + + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_TIMEOUT, MP3_STATE_FILE_HANDLE); + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_END, MP3_STATE_IDLE); + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_ERROR, MP3_STATE_ERROR); + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_FILE, MP3_STATE_FILE_START); + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_STOP, MP3_STATE_IDLE); + TRANSITION_ADD(MP3_STATE_FILE_HANDLE, MP3_EVENT_STREAM, MP3_STATE_STREAM_START); + + TRANSITION_ADD(MP3_STATE_STREAM_START, MP3_EVENT_TIMEOUT, MP3_STATE_STREAM_HANDLE); + TRANSITION_ADD(MP3_STATE_STREAM_START, MP3_EVENT_ERROR, MP3_STATE_ERROR); + + TRANSITION_ADD(MP3_STATE_STREAM_HANDLE, MP3_EVENT_TIMEOUT, MP3_STATE_STREAM_HANDLE); + TRANSITION_ADD(MP3_STATE_STREAM_HANDLE, MP3_EVENT_STOP, MP3_STATE_IDLE); + TRANSITION_ADD(MP3_STATE_STREAM_HANDLE, MP3_EVENT_ERROR, MP3_STATE_ERROR); + TRANSITION_ADD(MP3_STATE_STREAM_HANDLE, MP3_EVENT_FILE, MP3_STATE_FILE_START); + TRANSITION_ADD(MP3_STATE_STREAM_HANDLE, MP3_EVENT_STREAM, MP3_STATE_STREAM_START); + + TRANSITION_ADD(MP3_STATE_ERROR, MP3_EVENT_TIMEOUT, MP3_STATE_IDLE); + + TRANSITION_ADD(MP3_STATE_DEFAULT, MP3_EVENT_ERROR, MP3_STATE_ERROR); + TRANSITION_ADD(MP3_STATE_DEFAULT, MP3_EVENT_SHUTDOWN, MP3_STATE_SHUTDOWN); + state_startup_enter(0, 0, NULL); +}; + +void state_transition(int transition, int event, EVENT_PARAM *param){ + state_previous = state_current; + state_current = transitions[transition].new_state; + if(state_previous != state_current){ + printf("\n -- Transition %s -> %s\n", + states[state_previous].name, + states[state_current].name); + }; + if(states[state_previous].leave != NULL) + states[state_previous].leave(state_current, event); + if(states[state_current].enter != NULL) + states[state_current].enter(state_previous, event, param); + if(param){ + if(param->text){ + free(param->text); + }; + free(param); + }; +}; + +void state_event(int event, EVENT_PARAM *param){ + int i = 0; + if(event != MP3_EVENT_TIMEOUT){ + printf("\n -- Got event %s (%d) in state %s (%d)\n", + events[event].name, + event, + states[state_current].name, + state_current); + }; + for(i = 0; i < transition_count; i++){ + if((transitions[i].old_state == state_current) + && (transitions[i].event == event)){ + state_transition(i, event, param); + return; + }; + }; + for(i = 0; i < transition_count; i++){ + if((transitions[i].old_state == MP3_STATE_DEFAULT) + && (transitions[i].event == event)){ + state_transition(i, event, param); + return; + }; + }; + if(param){ + if(param->text){ + free(param->text); + }; + free(param); + }; + printf("Event %s not handled in state %s\n", events[event].name, states[state_current].name); +}; + +void state_mainloop(void){ + while(1){ + if(shutdown){ + state_event(MP3_EVENT_SHUTDOWN, NULL); + }; + mp3_nix_socket_handle(); + mp3_tcp_socket_handle(); + if(state_current == MP3_STATE_IDLE){ + poll(0, 0, 200); + } else { + poll(0, 0, 1); + }; + state_event(MP3_EVENT_TIMEOUT, NULL); + }; +}; + +EVENT_PARAM* state_new_event(unsigned char *text, int numeric){ + EVENT_PARAM *p = (EVENT_PARAM*)malloc(sizeof(EVENT_PARAM)); + if(text){ + p->text = strdup(text); + } else { + p->text = NULL; + }; + p->numeric = numeric; + return p; +}; + +void sig_handler(int sig){ + shutdown = 1; +}; + +int main(int argc, char **argv) { + unsigned char daemonize = 1; + + printf("\n\n"); + printf("ALPMP3 - MP3 Statemachine v1.0\n"); + + if(argc > 1){ + if(!strcmp(argv[1], "--no-daemon")){ + daemonize = 0; + } else { + printf("I am now going to daemonize. If you want me to stay in "); + printf("the foreground, add the parameter --no-daemon.\n"); + }; + }; + + if(daemonize){ + daemon(0, 0); + printf("----------------------------------------\n\n"); + printf("Made by openwrt.org (blogic@openwrt.org)\n"); + printf("\n"); + }; + + signal(SIGINT, sig_handler); + + state_setup(); + state_mainloop(); + + return 0; +} + + + + |