diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 10 | ||||
| -rw-r--r-- | src/main.c | 189 | ||||
| -rw-r--r-- | src/player.c | 239 | ||||
| -rw-r--r-- | src/player.h | 51 | 
4 files changed, 315 insertions, 174 deletions
| diff --git a/src/Makefile.am b/src/Makefile.am index 6bffa2d..606430b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,10 @@  bin_PROGRAMS = pianobar -pianobar_SOURCES = main.c terminal.c terminal.h settings.c settings.h -pianobar_CPPFLAGS = ${LIBCURL_CFLAGS} ${LIBAO_CFLAGS} ${LIBXML_CFLAGS} -I../libpiano/src -pianobar_LDADD = ${LIBCURL_LIBS} ${LIBAO_LIBS} ${LIBFAAD_LIBS} ${LIBREADLINE_LIBS} ${LIBXML_LIBS} -lpthread ../libpiano/src/libpiano.la +pianobar_SOURCES = main.c terminal.c terminal.h settings.c settings.h \ +		player.c player.h +pianobar_CPPFLAGS = ${LIBCURL_CFLAGS} ${LIBAO_CFLAGS} ${LIBXML_CFLAGS} \ +		-I../libpiano/src +pianobar_LDADD = ${LIBCURL_LIBS} ${LIBAO_LIBS} ${LIBFAAD_LIBS} \ +		${LIBREADLINE_LIBS} ${LIBXML_LIBS} -lpthread \ +		../libpiano/src/libpiano.la  dist_man1_MANS = pianobar.1 @@ -27,7 +27,6 @@ THE SOFTWARE.  #include <stdlib.h>  #include <string.h>  #include <stdio.h> -#include <ao/ao.h>  #include <neaacdec.h>  #include <pthread.h>  #include <unistd.h> @@ -37,175 +36,7 @@ THE SOFTWARE.  #include "terminal.h"  #include "settings.h"  #include "config.h" - -struct aacPlayer { -	/* buffer; should be large enough */ -	char buffer[CURL_MAX_WRITE_SIZE*2]; -	size_t bufferFilled; -	/* got mdat atom */ -	char dataMode; -	char foundEsdsAtom; -	char audioInitialized; -	/* aac */ -	NeAACDecHandle aacHandle; -	unsigned long samplerate; -	unsigned char channels; -	/* audio out */ -	ao_device *audioOutDevice; -	char *url; -	char finishedPlayback; -	char doQuit; -	char doPause; -	CURL *audioFd; -}; - -void dumpBuffer (char *buf, size_t len) { -	int i; -	for (i = 0; i < len; i++) { -		printf ("%02x ", buf[i] & 0xff); -	} -	printf ("\n"); -} - -/* FIXME: this is a huge block of _bad_ and buggy code */ -size_t playCurlCb (void *ptr, size_t size, size_t nmemb, void *stream) { -	char *data = ptr; -	struct aacPlayer *player = stream; - -	if (player->doQuit) { -		return 0; -	} - -	/* FIXME: not the best solution to poll every second, but the easiest one -	 * I know... (pthread's conditions could be another solution) */ -	if (player->doPause == 1) { -		curl_easy_pause (player->audioFd, CURLPAUSE_ALL); -		while (player->doPause == 1) { -			sleep (1); -		} -		curl_easy_pause (player->audioFd, CURLPAUSE_CONT); -	} - -	/* fill buffer */ -	if (player->bufferFilled + size*nmemb > sizeof (player->buffer)) { -		printf ("Buffer overflow!\n"); -		return 0; -	} -	memcpy (player->buffer+player->bufferFilled, data, size*nmemb); -	player->bufferFilled += size*nmemb; - -	if (player->dataMode == 1) { -		char *aacDecoded; -		NeAACDecFrameInfo frameInfo; - -		/* 500 is just a guessed size; prevent buffer underruns and error -		 * messages by faad2 */ -		while (player->bufferFilled > 500) { -			/* FIXME: well, i think we need this block length table */ -			aacDecoded = NeAACDecDecode(player->aacHandle, &frameInfo, -					(unsigned char *) player->buffer, player->bufferFilled); -			if (frameInfo.error != 0) { -				printf ("error: %s\n\n", -						NeAACDecGetErrorMessage (frameInfo.error)); -				break; -			} -			ao_play (player->audioOutDevice, aacDecoded, -					frameInfo.samples*frameInfo.channels); -			/* move remaining bytes to buffer beginning */ -			memmove (player->buffer, player->buffer + frameInfo.bytesconsumed, -					player->bufferFilled - frameInfo.bytesconsumed); -			player->bufferFilled -= frameInfo.bytesconsumed; -		} -	} else { -		char *searchBegin = player->buffer; - -		if (!player->foundEsdsAtom) { -			while (searchBegin < player->buffer + nmemb) { -				if (memcmp (searchBegin, "esds", 4) == 0) { -					player->foundEsdsAtom = 1; -					break; -				} -				searchBegin++; -			} -		} -		if (player->foundEsdsAtom && !player->audioInitialized) { -			/* FIXME: is this the correct way? */ -			while (searchBegin < player->buffer + nmemb) { -				if (memcmp (searchBegin, "\x05\x80\x80\x80", 4) == 0) { -					ao_sample_format format; -					int audioOutDriver; - -					/* +1+4 needs to be replaced by <something>! */ -					char err = NeAACDecInit2 (player->aacHandle, -							(unsigned char *) searchBegin+1+4, 5, -							&player->samplerate, &player->channels); -					if (err != 0) { -						printf ("whoops... %i\n", err); -						return 1; -					} -					audioOutDriver = ao_default_driver_id(); -					format.bits = 16; -					format.channels = player->channels; -					format.rate = player->samplerate; -					format.byte_format = AO_FMT_LITTLE; -					player->audioOutDevice = ao_open_live (audioOutDriver, -							&format, NULL); -					player->audioInitialized = 1; -					break; -				} -				searchBegin++; -			} -		} -		if (player->audioInitialized) { -			while (searchBegin < player->buffer + nmemb) { -				if (memcmp (searchBegin, "mdat", 4) == 0) { -					player->dataMode = 1; -					memmove (player->buffer, searchBegin + strlen ("mdat"), -							nmemb - (searchBegin - player->buffer)); -					player->bufferFilled = nmemb - (searchBegin-player->buffer); -					break; -				} -				searchBegin++; -			} -		} -		if (!player->dataMode) { -			/* copy last four bytes to buffer beginning and set filled -			 * size to four */ -			memcpy (player->buffer, player->buffer+player->bufferFilled - 4, 4); -			player->bufferFilled = 4; -		} -	} - -	return size*nmemb; -} - -/* player thread; for every song a new thread is started */ -void *threadPlayUrl (void *data) { -	struct aacPlayer *player = data; -	NeAACDecConfigurationPtr conf; - -	player->audioFd = curl_easy_init (); -	player->aacHandle = NeAACDecOpen(); - -	conf = NeAACDecGetCurrentConfiguration(player->aacHandle); -	conf->outputFormat = FAAD_FMT_16BIT; -    conf->downMatrix = 1; -	NeAACDecSetConfiguration(player->aacHandle, conf); - -	curl_easy_setopt (player->audioFd, CURLOPT_URL, player->url); -	curl_easy_setopt (player->audioFd, CURLOPT_WRITEFUNCTION, playCurlCb); -	curl_easy_setopt (player->audioFd, CURLOPT_WRITEDATA, player); -	curl_easy_setopt (player->audioFd, CURLOPT_USERAGENT, PACKAGE_STRING); -	curl_easy_perform (player->audioFd); - -	NeAACDecClose(player->aacHandle); -	ao_close(player->audioOutDevice); -	curl_easy_cleanup (player->audioFd); - -	player->finishedPlayback = 1; - -	return NULL; -} +#include "player.h"  PianoStation_t *selectStation (PianoHandle_t *ph) {  	PianoStation_t *curStation; @@ -534,7 +365,23 @@ int main (int argc, char **argv) {  								curStation->name);  					}  					break; -			} +			} /* end case */ +		} /* end poll */ + +		/* show time */ +		if (player.finishedPlayback == 0) { +			/* FIXME: is this calculation correct? */ +			/* one frame length: T = 1/f */ +			float songLength = 1.0 / (float) player.samplerate * +					(float) player.channels * 1000.0 * +					(float) player.sampleSizeN; +			float songRemaining = songLength - 1.0 / (float) player.samplerate * +					(float) player.channels * 1000.0 * +					(float) player.sampleSizeCurr; +			printf ("-%02i:%02i/%02i:%02i\r", (int) songRemaining/60, +					(int) songRemaining%60, (int) songLength/60, +					(int) songLength%60); +			fflush (stdout);  		}  	} diff --git a/src/player.c b/src/player.c new file mode 100644 index 0000000..3a7aa25 --- /dev/null +++ b/src/player.c @@ -0,0 +1,239 @@ +/* +Copyright (c) 2008 Lars-Dominik Braun + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include <unistd.h> +#include <string.h> + +#include "player.h" +#include "config.h" + +/*	LE to BE and reverse + *	@param unsigned int + *	@return byteswapped unsigned int + */ +unsigned int changeByteorderUI32 (char buf[4]) { +	unsigned int ret = 0; + +	ret = buf[0] << 24 & 0xffffffff; +	ret |= buf[1] << 16 & 0xffffff; +	ret |= buf[2] << 8 & 0xffff; +	ret |= buf[3] << 0 & 0xff; +	return ret; +} + +/*	our heart: plays streamed music + *	@param streamed data + *	@param block size + *	@param received blocks + *	@param extra data (player data) + *	@return received bytes or less on error + */ +size_t playCurlCb (void *ptr, size_t size, size_t nmemb, void *stream) { +	char *data = ptr; +	struct aacPlayer *player = stream; + +	if (player->doQuit) { +		return 0; +	} +	 +	/* FIXME: not the best solution to poll every second, but the easiest +	 * one I know... (pthread's conditions could be another solution) */ +	if (player->doPause == 1) { +		curl_easy_pause (player->audioFd, CURLPAUSE_ALL); +		while (player->doPause == 1) { +			sleep (1); +		} +		curl_easy_pause (player->audioFd, CURLPAUSE_CONT); +	} + +	/* fill buffer */ +	if (player->bufferFilled + size*nmemb > sizeof (player->buffer)) { +		printf ("Buffer overflow!\n"); +		return 0; +	} +	memcpy (player->buffer+player->bufferFilled, data, size*nmemb); +	player->bufferFilled += size*nmemb; +	player->bufferRead = 0; + +	if (player->mode == RECV_DATA) { +		char *aacDecoded; +		NeAACDecFrameInfo frameInfo; + +		while ((player->bufferFilled - player->bufferRead) > +				player->sampleSize[player->sampleSizeCurr]) { +			/* decode frame */ +			aacDecoded = NeAACDecDecode(player->aacHandle, &frameInfo, +					(unsigned char *) player->buffer + player->bufferRead, +					player->sampleSize[player->sampleSizeCurr]); +			if (frameInfo.error != 0) { +				printf ("error: %s\n\n", +						NeAACDecGetErrorMessage (frameInfo.error)); +				break; +			} +			ao_play (player->audioOutDevice, aacDecoded, +					frameInfo.samples*frameInfo.channels); +			player->bufferRead += frameInfo.bytesconsumed; +			player->sampleSizeCurr++; +		} +	} else { +		if (player->mode == FIND_ESDS) { +			while (player->bufferRead+4 < player->bufferFilled) { +				if (memcmp (player->buffer + player->bufferRead, "esds", +						4) == 0) { +					player->mode = FOUND_ESDS; +					player->bufferRead += 4; +					break; +				} +				player->bufferRead++; +			} +		} +		if (player->mode == FOUND_ESDS) { +			/* FIXME: is this the correct way? */ +			/* we're gonna read 10 bytes */ +			while (player->bufferRead+1+4+5 < player->bufferFilled) { +				if (memcmp (player->buffer + player->bufferRead, +						"\x05\x80\x80\x80", 4) == 0) { +					ao_sample_format format; +					int audioOutDriver; + +					/* +1+4 needs to be replaced by <something>! */ +					player->bufferRead += 1+4; +					char err = NeAACDecInit2 (player->aacHandle, +							(unsigned char *) player->buffer + +							player->bufferRead, 5, &player->samplerate, +							&player->channels); +					player->bufferRead += 5; +					if (err != 0) { +						printf ("Error while initializing audio decoder (%i)\n", +								err); +						return 1; +					} +					audioOutDriver = ao_default_driver_id(); +					format.bits = 16; +					format.channels = player->channels; +					format.rate = player->samplerate; +					format.byte_format = AO_FMT_LITTLE; +					player->audioOutDevice = ao_open_live (audioOutDriver, +							&format, NULL); +					player->mode = AUDIO_INITIALIZED; +					break; +				} +				player->bufferRead++; +			} +		} +		if (player->mode == AUDIO_INITIALIZED) { +			while (player->bufferRead+4+8 < player->bufferFilled) { +				if (memcmp (player->buffer + player->bufferRead, "stsz", +						4) == 0) { +					player->mode = FOUND_STSZ; +					player->bufferRead += 4; +					/* skip version and unknown */ +					player->bufferRead += 8; +					break; +				} +				player->bufferRead++; +			} +		} +		/* get frame sizes */ +		if (player->mode == FOUND_STSZ) { +			while (player->bufferRead+4 < player->bufferFilled) { +				/* how many frames do we have? */ +				if (player->sampleSizeN == 0) { +					/* mp4 uses big endian, convert */ +					player->sampleSizeN = changeByteorderUI32 (player->buffer + +							player->bufferRead); +					player->sampleSize = calloc (player->sampleSizeN, +							sizeof (player->sampleSizeN)); +					player->bufferRead += 4; +					player->sampleSizeCurr = 0; +					break; +				} else { +					player->sampleSize[player->sampleSizeCurr] = +							changeByteorderUI32 (player->buffer + +							player->bufferRead); +					player->sampleSizeCurr++; +					player->bufferRead += 4; +				} +				/* all sizes read, nearly ready for data mode */ +				if (player->sampleSizeCurr >= player->sampleSizeN) { +					player->mode = SAMPLESIZE_INITIALIZED; +					break; +				} +			} +		} +		/* search for data atom and let the show begin... */ +		if (player->mode == SAMPLESIZE_INITIALIZED) { +			while (player->bufferRead+4 < player->bufferFilled) { +				if (memcmp (player->buffer + player->bufferRead, "mdat", +						4) == 0) { +					player->mode = RECV_DATA; +					player->sampleSizeCurr = 0; +					player->bufferRead += 4; +					break; +				} +				player->bufferRead++; +			} +		} +	} + +	/* move remaining bytes to buffer beginning */ +	memmove (player->buffer, player->buffer + player->bufferRead, +			(player->bufferFilled - player->bufferRead)); +	player->bufferFilled = (player->bufferFilled - player->bufferRead); + +	return size*nmemb; +} + + +/*	player thread; for every song a new thread is started + *	@param aacPlayer structure + *	@return NULL NULL NULL ... + */ +void *threadPlayUrl (void *data) { +	struct aacPlayer *player = data; +	NeAACDecConfigurationPtr conf; + +	player->audioFd = curl_easy_init (); +	player->aacHandle = NeAACDecOpen(); + +	conf = NeAACDecGetCurrentConfiguration(player->aacHandle); +	conf->outputFormat = FAAD_FMT_16BIT; +    conf->downMatrix = 1; +	NeAACDecSetConfiguration(player->aacHandle, conf); + +	curl_easy_setopt (player->audioFd, CURLOPT_URL, player->url); +	curl_easy_setopt (player->audioFd, CURLOPT_WRITEFUNCTION, playCurlCb); +	curl_easy_setopt (player->audioFd, CURLOPT_WRITEDATA, player); +	curl_easy_setopt (player->audioFd, CURLOPT_USERAGENT, PACKAGE_STRING); +	curl_easy_perform (player->audioFd); + +	NeAACDecClose(player->aacHandle); +	ao_close(player->audioOutDevice); +	curl_easy_cleanup (player->audioFd); +	if (player->sampleSize != NULL) { +		free (player->sampleSize); +	} + +	player->finishedPlayback = 1; + +	return NULL; +} diff --git a/src/player.h b/src/player.h new file mode 100644 index 0000000..2e36c11 --- /dev/null +++ b/src/player.h @@ -0,0 +1,51 @@ +/* +Copyright (c) 2008 Lars-Dominik Braun + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include <curl/curl.h> +#include <neaacdec.h> +#include <ao/ao.h> + +struct aacPlayer { +	/* buffer; should be large enough */ +	char buffer[CURL_MAX_WRITE_SIZE*2]; +	size_t bufferFilled; +	size_t bufferRead; +	enum {FIND_ESDS, FOUND_ESDS, AUDIO_INITIALIZED, FOUND_STSZ, +			SAMPLESIZE_INITIALIZED, RECV_DATA} mode; +	/* stsz atom: sample sizes */ +	unsigned int *sampleSize; +	size_t sampleSizeN; +	size_t sampleSizeCurr; +	/* aac */ +	NeAACDecHandle aacHandle; +	unsigned long samplerate; +	unsigned char channels; +	/* audio out */ +	ao_device *audioOutDevice; +	char *url; +	char finishedPlayback; +	char doQuit; +	char doPause; +	CURL *audioFd; +}; + +void *threadPlayUrl (void *data); | 
