/* * holyshout.c * * holyshout (Broadcasting utility for icecast or shoutcast) * * Author: JunSeon Oh * Date : $Date: 2003/11/25 07:43:07 $ * * $Revision: 1.6 $ * * Copyright(C) 2000 JunSeon Oh. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* SCSS/RCS Id */ #ifndef lint static char rcsid[]="@(#)$Id: holyshout.c,v 1.6 2003/11/25 07:43:07 hollywar Exp $"; #endif /* lint */ #include "holyshout.h" /* Global variables */ char **play_list , **pointer_list , listfile[0xff]; int play_list_num=0 , shuffle=0 , encode=0, nal=0 ; struct timeval lastint, shoutstart; lame_global_flags *gf ; int main(int argc , char **argv) { int playlist = 0 , loop=0 , check=0 , ch ; struct hostent *host ; shout_t *conn; signal (SIGINT, s1gnal); signal (SIGHUP, s1gnal); /* Shout default informaton descriptions. But , It can change using Options. do not change that. */ gf = lame_init() ; shout_init(); conn = shout_new(); shout_set_name(conn, "AP_"PROGRAM_NAME"_"VERSION); shout_set_mount(conn, "default"); shout_set_description(conn, "HOLYSHOUT"); shout_set_host(conn, "http://www.icecast.org"); /* Get arguments options */ while ((ch = getopt(argc, argv, "P:p:h:l:f:m:b:g:d:n:u:s:izr")) != -1) { switch (ch) { case 'P': shout_set_port(conn, atoi(optarg)) ; check++ ; break ; case 'p': shout_set_password(conn, optarg); check++ ; break ; case 'l': playlist=2 ; check++ ; strcpy(listfile,optarg) ; break ; case 'z': shuffle=1 ; break ; case 'f': playlist=1 ; check++ ; strcpy(listfile,optarg) ; break ; case 'i': shout_set_public(conn, 1); break ; case 'm': shout_set_mount(conn, optarg); break ; case 'g': shout_set_genre(conn, optarg); break ; case 'd': shout_set_description(conn, optarg); break ; case 'u': shout_set_url(conn, optarg); break ; case 'n': shout_set_name(conn, optarg); break ; case 'r': loop=1 ; break ; case 's': lame_set_mode(gf, atoi(optarg)); break ; case 'b': check++ ; if (!strcmp(optarg,"auto") || !strcmp(optarg,"AUTO")) encode=0; else { /* * XXX conn.bitrate=atoi(optarg); lame_set_brate(gf, conn.bitrate); encode=1; */ } break ; case '?': default: usage(); break ; } } /* check the require options */ if (argc < 8 ) usage() ; if (check != 4) usage() ; argc -= optind; argv += optind; if (argc < 1 ) usage() ; /* find a address , if the address is a dns , lookup ip */ if (isdigit(argv[argc-1][0])) { shout_set_host(conn, argv[argc-1]); } else { if (argv[argc-1] == NULL) { puts("You must specify server name"); exit(0); } else if (!strcmp(argv[argc-1],"")) { puts("You must specify server name"); exit(0); } else if (strstr(argv[argc-1],"http://")) { host = gethostbyname(&argv[argc-1][7]) ; } else { host = gethostbyname(argv[argc-1]) ; } if (host==NULL) { printf("Can't resolv %s\n",argv[argc-1]) ; exit(0); } shout_set_host(conn, (char *)inet_ntoa(*((struct in_addr *)host->h_addr))) ; if (shout_get_host(conn) == NULL) { printf("Can't resolv %s\n",argv[argc-1]) ; exit(0); } } /* connect to shoutcast (icecast) server. */ shout_open(conn); if(shout_get_connected(conn) == SHOUTERR_CONNECTED) { printf("Connected.\n"); } else { printf("Couldn't connect %s:%d (Error Code %d)\n", shout_get_host(conn), shout_get_port(conn), shout_get_errno(conn)); /* if the server is a shoutcast , automatic retry using -i */ if (shout_get_errno(conn)==3) { printf("Automatic retry using old icy header using -i option.\n"); shout_close(conn) ; shout_set_public(conn, 1); if (shout_get_connected(conn) == SHOUTERR_CONNECTED) { printf("Connected.\n"); } else { printf("Couldn't connect %s:%d (Error Code %d)\n", shout_get_host(conn), shout_get_port(conn), shout_get_error(conn)); exit(0); } } else { exit(0) ; } } puts("Initializing."); /* Now playing */ while(1) { if (playlist==2) { int j = 0 ; init_playlist(PL_INIT) ; if (shuffle==1) init_playlist(PL_SHUFFLE) ; for (j=0 ; j= buff_size) { ret = shout_send_raw(conn, buff, buf_loc); if (ret) { fprintf(stderr,"SEND_ERROR : %s...\n", shout_get_error(conn)); break; } shout_sync(conn); buf_loc=0 ; if (buff_size < MAX_BUF) buff_size += INC_BUF ; } if (imp3 > 0) { bcopy(mp3buffer,&buff[buf_loc],imp3) ; buf_loc += imp3 ; } } while(iread) ; if (buf_loc > 0) { ret = shout_send(conn, buff, buf_loc); shout_sync(conn); } imp3=lame_encode_finish(gf,mp3buffer,(int)sizeof(mp3buffer)); lame_close(gf) ; puts("") ; return 0 ; } int init_playlist(int type) { if (type==PL_INIT) { FILE *fp ; int i=0; char buf[0xff] ; // get the playlist count // if (!(fp = fopen(listfile,"r"))) { printf("Can't open file %s\n",listfile) ; exit(0); } play_list_num=0 ; while( (fgets(buf,0xff,fp))) { if (!mp3_extension_compare(buf)) continue ; play_list_num++ ; } fclose(fp) ; // memory allocation play list // if (!(play_list = malloc (sizeof(char*)*play_list_num))){ fprintf(stderr,"malloc failed") ; exit(0); } // memory allocation pointer // if (!(pointer_list = malloc (sizeof(char*)*play_list_num))){ fprintf(stderr,"malloc failed") ; exit(0); } // get the list // if (!(fp = fopen(listfile,"r"))) { printf("Can't open file %s\n",listfile) ; exit(0); } i=0; while( (fgets(buf,0xff,fp))) { if (!mp3_extension_compare(buf)) continue ; buf[strlen(buf)-1] = '\0' ; play_list[i] = malloc(sizeof(char)*strlen(buf)+1) ; strcpy(play_list[i],buf) ; pointer_list[i] = play_list[i] ; i++ ; } fclose(fp) ; fprintf(stderr,"%d songs init done.\n",play_list_num) ; return 0 ; } else if (type==PL_SHUFFLE) { int rand1 , rand2 , j ; char *tmp_pointer ; struct timeval tfs; gettimeofday(&tfs, (struct timezone *) 0) ; /* NOTE - Shuffling Algorithm srandomdev() is a freebsd only random device function. if you have a error with this line please change function to srandom(tfs.tv_usec). it is a local microseconds seed. if your system is very very very ugly!! , please use a srand(tfs.tv_use) and random() to rand() */ srandomdev() ; for (j=0 ; j<=play_list_num*4 ; j++) { rand1 = random()%play_list_num ; rand2 = random()%play_list_num ; if (rand1 != rand2) { tmp_pointer = pointer_list[rand1] ; pointer_list[rand1] = pointer_list[rand2] ; pointer_list[rand2] = tmp_pointer ; } else { j--; } } fprintf(stderr,"Shuffling done.\n") ; //fprintf(stderr,"Shuffling done (%d times).\n",play_list_num*4) ; return 0 ; } else if (type==PL_FREE) { int i ; for (i=0 ;i0) { ret = shout_send(conn,buff,read) ; if (ret) { fprintf(stderr,"SEND_ERROR : %s...\n",shout_get_error(conn)) ; break ; } shout_sync(conn) ; } else break ; fprintf(stderr,"\rSend: %-.2f %%",((float) total / (float)file_size)*100) ; } puts("") ; return 0 ; } void s1gnal(const int sig) { switch(sig) { case SIGINT: { struct timeval tv; gettimeofday (&tv, NULL); if (((tv.tv_sec + tv.tv_usec / 1000000.0) - 0.4) < (lastint.tv_sec + lastint.tv_usec / 1000000.0)) { exit(0); } gettimeofday (&lastint, NULL); fflush (stdout); //fprintf(stderr,"Caught signal SIGINT. skipped to next song! \n"); puts(""); fflush (stdout); nal=1 ; } break ; case SIGHUP : { init_playlist(PL_FREE) ; init_playlist(PL_INIT) ; fprintf(stderr,"Caught signal SIGHUP. Rehashing playlist! \n"); if (shuffle==1) init_playlist(PL_SHUFFLE) ; } } } int mp3_extension_compare (char *data) { char *i, *j ; char *code ; /* Data is null or space line */ if (data[0]=='\0' || data[0]=='\n' || data[0]=='\r') return 0 ; code = (char *)malloc ((strlen(data)+1) * sizeof (char) ); for (j=code, i=data; *i!='\0'; i++, j++) { if (*i != ' ') *j = tolower(*i); else *j = ' ' ; } *j = '\0'; if (strstr(code,".mp3")) { free(code) ; return 1; } else { free(code) ; return 0 ; } } void usage(void) { printf("* "); printf(PROGRAM_NAME); printf(" "); printf(VERSION); printf(" *"); printf("\n\n") ; puts("Useage: holyshout [options] hostname\n"); puts("* required options ( you must choose one -l or -f ) *"); puts(" -P - Connect to port on server."); puts(" -p - Use specified password."); puts(" -l - Use specified file as a playlist."); puts(" -f - Use specified file."); puts(" -b - Encoding specified bitrate"); puts(" - 16/32/52/64/128 or auto (not encoding)"); puts(""); puts("* optional options *"); puts(" -g - Use specified genre "); puts(" -n - Use specified name "); puts(" -d - Use specified description "); puts(" -u - Use specified url "); puts(" -m - Use specified mount point"); puts(" -s - 0 = stero,1 = jstero ,2 = dual,3 = mono"); puts(" -r - go on forever (loop)"); puts(" -i - Use old icy headers (for shoutcast)"); puts(" -z - Shuffle play") ; puts(""); exit(0); } /* | $Id: holyshout.c,v 1.6 2003/11/25 07:43:07 hollywar Exp $ | | | Local Variables: | mode: c | mode: font-lock | version-control: t | delete-old-versions: t | End: | | -*- End-Of-File -*- */