Пример #1
0
int
streamPlaylist(shout_t *shout, const char *fileName)
{
	const char	*song;
	char		 lastSong[PATH_MAX];

	if (playlist == NULL) {
		if (pezConfig->fileNameIsProgram) {
			if ((playlist = playlist_program(fileName)) == NULL)
				return (0);
		} else {
			if ((playlist = playlist_read(fileName)) == NULL)
				return (0);
			if (vFlag && playlist_get_num_items(playlist) == 0)
				printf("%s: Warning: Playlist '%s' is empty\n",
				       __progname, fileName);
		}
	} else {
		/*
		 * XXX: This preserves traditional behavior, however,
		 *      rereading the playlist after each walkthrough seems a
		 *      bit more logical.
		 */
		playlist_rewind(playlist);
	}

	if (!pezConfig->fileNameIsProgram && pezConfig->shuffle)
		playlist_shuffle(playlist);

	while ((song = playlist_get_next(playlist)) != NULL) {
		strlcpy(lastSong, song, sizeof(lastSong));
		if (!streamFile(shout, song))
			return (0);
		if (quit)
			break;
		if (rereadPlaylist) {
			rereadPlaylist = rereadPlaylist_notify = 0;
			if (pezConfig->fileNameIsProgram)
				continue;
			printf("%s: Rereading playlist\n", __progname);
			if (!playlist_reread(&playlist))
				return (0);
			if (pezConfig->shuffle)
				playlist_shuffle(playlist);
			else {
				playlist_goto_entry(playlist, lastSong);
				playlist_skip_next(playlist);
			}
			continue;
		}
	}

	return (1);
}
Пример #2
0
int
playlist_reread(playlist_t **plist)
{
	playlist_t	*new_pl, *pl;

	if (plist == NULL || *plist == NULL) {
		printf("%s: playlist_reread(): Internal error: NULL argument\n",
		       __progname);
		exit(1);
	}

	pl = *plist;

	if (pl->program)
		return (0);

	if ((new_pl = playlist_read(pl->filename)) == NULL)
		return (0);

	playlist_free(&pl);
	*plist = new_pl;

	return (1);
}
Пример #3
0
int
main(int argc, char *argv[])
{
	int		 c;
	char		*configFile = NULL;
	char		*host = NULL;
	unsigned short	 port = 0;
	char		*mount = NULL;
	shout_t 	*shout;
	extern char	*optarg;
	extern int	 optind;
#ifdef HAVE_SIGNALS
	struct sigaction act;
	unsigned int	 i;
#endif

#ifdef XALLOC_DEBUG
	xalloc_initialize_debug(2, NULL);
#else
	xalloc_initialize();
#endif /* XALLOC_DEBUG */
	playlist_init();
	shout_init();

	__progname = getProgname(argv[0]);
	pezConfig = getEZConfig();

	mFlag = 0;
	nFlag = 0;
	qFlag = 0;
	vFlag = 0;

	while ((c = local_getopt(argc, argv, "c:hmnqsVv")) != -1) {
		switch (c) {
		case 'c':
			if (configFile != NULL) {
				printf("Error: multiple -c arguments given\n");
				usage();
				return (ez_shutdown(2));
			}
			configFile = xstrdup(optarg);
			break;
		case 'h':
			usage();
			usageHelp();
			return (ez_shutdown(0));
		case 'm':
			mFlag = 1;
			break;
		case 'n':
			nFlag = 1;
			break;
		case 'q':
			qFlag = 1;
			break;
		case 's':
			sFlag = 1;
			break;
		case 'V':
			printf("%s\n", PACKAGE_STRING);
			return (ez_shutdown(0));
		case 'v':
			vFlag++;
			break;
		case '?':
			usage();
			return (ez_shutdown(2));
		default:
			break;
		}
	}
	argc -= optind;
	argv += optind;

	if (sFlag) {
		playlist_t	*pl;
		const char	*entry;

		switch (argc) {
		case 0:
			pl = playlist_read(NULL);
			if (pl == NULL)
				return (ez_shutdown(1));
			break;
		case 1:
			pl = playlist_read(argv[0]);
			if (pl == NULL)
				return (ez_shutdown(1));
			break;
		default:
			printf("Error: Too many arguments.\n");
			return (ez_shutdown(2));
		}

		playlist_shuffle(pl);
		while ((entry = playlist_get_next(pl)) != NULL)
			printf("%s\n", entry);

		playlist_free(&pl);

		return (ez_shutdown(0));
	}

	if (configFile == NULL) {
		printf("You must supply a config file with the -c argument.\n");
		usage();
		return (ez_shutdown(2));
	} else {
		/*
		 * Attempt to open configFile here for a more meaningful error
		 * message. Where possible, do it with stat() and check for
		 * safe config file permissions.
		 */
#ifdef HAVE_STAT
		struct stat	  st;

		if (stat(configFile, &st) == -1) {
			printf("%s: %s\n", configFile, strerror(errno));
			usage();
			return (ez_shutdown(2));
		}
		if (vFlag && (st.st_mode & (S_IRGRP | S_IROTH)))
			printf("%s: Warning: %s is group and/or world readable\n",
			       __progname, configFile);
		if (st.st_mode & (S_IWGRP | S_IWOTH)) {
			printf("%s: Error: %s is group and/or world writeable\n",
			       __progname, configFile);
			return (ez_shutdown(2));
		}
#else
		FILE		 *tmp;

		if ((tmp = fopen(configFile, "r")) == NULL) {
			printf("%s: %s\n", configFile, strerror(errno));
			usage();
			return (ez_shutdown(2));
		}
		fclose(tmp);
#endif /* HAVE_STAT */
	}

	if (!parseConfig(configFile))
		return (ez_shutdown(2));

	if (pezConfig->URL == NULL) {
		printf("%s: Error: Missing <url>\n", configFile);
		return (ez_shutdown(2));
	}
	if (!urlParse(pezConfig->URL, &host, &port, &mount)) {
		printf("Must be of the form ``http://server:port/mountpoint''\n");
		return (ez_shutdown(2));
	}
	if (strlen(host) == 0) {
		printf("%s: Error: Invalid <url>: Missing server:\n", configFile);
		printf("Must be of the form ``http://server:port/mountpoint''\n");
		return (ez_shutdown(2));
	}
	if (strlen(mount) == 0) {
		printf("%s: Error: Invalid <url>: Missing mountpoint:\n", configFile);
		printf("Must be of the form ``http://server:port/mountpoint''\n");
		return (ez_shutdown(2));
	}
	if (pezConfig->password == NULL) {
		printf("%s: Error: Missing <sourcepassword>\n", configFile);
		return (ez_shutdown(2));
	}
	if (pezConfig->fileName == NULL) {
		printf("%s: Error: Missing <filename>\n", configFile);
		return (ez_shutdown(2));
	}
	if (pezConfig->format == NULL) {
		printf("%s: Warning: Missing <format>:\n", configFile);
		printf("Specify a stream format of either MP3, VORBIS or THEORA\n");
	}

	xfree(configFile);

	if ((shout = stream_setup(host, port, mount)) == NULL)
		return (ez_shutdown(1));

	if (pezConfig->metadataProgram != NULL)
		metadataFromProgram = 1;
	else
		metadataFromProgram = 0;

#ifdef HAVE_SIGNALS
	memset(&act, 0, sizeof(act));
	act.sa_handler = sig_handler;
# ifdef SA_RESTART
	act.sa_flags = SA_RESTART;
# endif
	for (i = 0; i < sizeof(ezstream_signals) / sizeof(int); i++) {
		if (sigaction(ezstream_signals[i], &act, NULL) == -1) {
			printf("%s: sigaction(): %s\n",
			       __progname, strerror(errno));
			return (ez_shutdown(1));
		}
	}
	/*
	 * Ignore SIGPIPE, which has been seen to give a long-running ezstream
	 * process trouble. EOF and/or EPIPE are also easier to handle.
	 */
	act.sa_handler = SIG_IGN;
	if (sigaction(SIGPIPE, &act, NULL) == -1) {
		printf("%s: sigaction(): %s\n",
		       __progname, strerror(errno));
		return (ez_shutdown(1));
	}
#endif /* HAVE_SIGNALS */

	if (shout_open(shout) == SHOUTERR_SUCCESS) {
		int	ret;

		printf("%s: Connected to http://%s:%hu%s\n", __progname,
		       host, port, mount);

		if (pezConfig->fileNameIsProgram ||
		    strrcasecmp(pezConfig->fileName, ".m3u") == 0 ||
		    strrcasecmp(pezConfig->fileName, ".txt") == 0)
			playlistMode = 1;
		else
			playlistMode = 0;

		if (vFlag && pezConfig->fileNameIsProgram)
			printf("%s: Using program '%s' to get filenames for streaming\n",
			       __progname, pezConfig->fileName);

		do {
			if (playlistMode) {
				ret = streamPlaylist(shout,
						     pezConfig->fileName);
			} else {
				ret = streamFile(shout, pezConfig->fileName);
			}
			if (quit)
				break;
			if (pezConfig->streamOnce)
				break;
		} while (ret);

		shout_close(shout);
	} else
		printf("%s: Connection to http://%s:%hu%s failed: %s\n", __progname,
		       host, port, mount, shout_get_error(shout));

	if (quit)
		printf("\r%s: SIGINT or SIGTERM received\n", __progname);

	if (vFlag)
		printf("%s: Exiting ...\n", __progname);

	xfree(host);
	xfree(mount);
	playlist_free(&playlist);

	return (ez_shutdown(0));
}
Пример #4
0
/* Core streaming function for this module
 * This is what actually produces the data which gets streamed.
 *
 * returns:  >0  Number of bytes read
 *            0  Non-fatal error.
 *           <0  Fatal error.
 */
static int playlist_read(void *self, ref_buffer *rb)
{
    playlist_state_t *pl = (playlist_state_t *)self;
    int bytes;
    unsigned char *buf;
    char *newfn;
    int result;
    ogg_page og;

    if (pl->errors > 5) 
    {
        LOG_WARN0("Too many consecutive errors - exiting");
        return -1;
    }

    if (!pl->current_file || pl->nexttrack) 
    {
        pl->nexttrack = 0;

        if (pl->current_file && strcmp (pl->filename, "-"))
        {
            fclose(pl->current_file);
            pl->current_file = NULL;
        }
	if (pl->file_ended)
	{
	    pl->file_ended(pl->data, pl->filename);
	}

        newfn = pl->get_filename(pl->data);
        if (!newfn)
        {
            LOG_INFO0("No more filenames available, end of playlist");
            return -1; /* No more files available */
        }

        if (strcmp (newfn, "-"))
        {
            if (!pl->allow_repeat && pl->filename && !strcmp(pl->filename, newfn))
            {
                LOG_ERROR0("Cannot play same file twice in a row, skipping");
                pl->errors++;
                pl->free_filename (pl->data, newfn);
                return 0;
            }
            pl->free_filename(pl->data, pl->filename);
            pl->filename = newfn;

            pl->current_file = fopen(pl->filename, "rb");
            if (!pl->current_file) 
            {
                LOG_WARN2("Error opening file \"%s\": %s",pl->filename, strerror(errno));
                pl->errors++;
                return 0;
            }
            LOG_INFO1("Currently playing \"%s\"", pl->filename);
        }
        else
        {
            LOG_INFO0("Currently playing from stdin");
            pl->current_file = stdin;
            pl->free_filename(pl->data, pl->filename);
            pl->filename = newfn;
        }

        /* Reinit sync, so that dead data from previous file is discarded */
        ogg_sync_clear(&pl->oy);
        ogg_sync_init(&pl->oy);
    }
    input_sleep ();

    while(1)
    {
        result = ogg_sync_pageout(&pl->oy, &og);
        if(result < 0)
            LOG_WARN1("Corrupt or missing data in file (%s)", pl->filename);
        else if(result > 0)
        {
            if (ogg_page_bos (&og))
            {
               if (ogg_page_serialno (&og) == pl->current_serial)
                   LOG_WARN1 ("detected duplicate serial number reading \"%s\"", pl->filename);

               pl->current_serial = ogg_page_serialno (&og);
            }
            if (input_calculate_ogg_sleep (&og) < 0)
            {
                pl->nexttrack = 1;
                return 0;
            }
            rb->len = og.header_len + og.body_len;
            rb->buf = malloc(rb->len);
            rb->aux_data = og.header_len;

            memcpy(rb->buf, og.header, og.header_len);
            memcpy(rb->buf+og.header_len, og.body, og.body_len);
            if(ogg_page_granulepos(&og)==0)
                rb->critical = 1;
            break;
        }

        /* If we got to here, we didn't have enough data. */
        buf = ogg_sync_buffer(&pl->oy, BUFSIZE);
        bytes = fread(buf,1, BUFSIZE, pl->current_file);
        if (bytes <= 0) 
        {
            if (feof(pl->current_file)) 
            {
                pl->nexttrack = 1;
                return playlist_read(pl,rb);
            } 
            else 
            {
                LOG_ERROR2("Read error from \"%s\": %s", pl->filename, strerror(errno));
                fclose(pl->current_file);
                pl->current_file=NULL;
                pl->errors++;
                return 0; 
            }
        }
        else
            ogg_sync_wrote(&pl->oy, bytes);
    }

    pl->errors=0;

    return rb->len;
}