Exemplo n.º 1
0
void real_buffer_resync(void)
{
	if(buffermem->justwait)
	{
		buffermem->wakeme[XF_WRITER] = TRUE;
		xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_RESYNC);
		xfermem_getcmd(buffermem->fd[XF_WRITER], TRUE);
	}
	else buffer_sig(SIGINT, TRUE);
}
Exemplo n.º 2
0
/* This uses the currently opened audio device, queries its caps.
   In case of buffered playback, this works _once_ by querying the buffer for the caps before entering the main loop. */
void audio_capabilities(audio_output_t *ao, mpg123_handle *mh)
{
	int force_fmt = 0;
	int fmts;
	size_t ri;
	/* Pitching introduces a difference between decoder rate and playback rate. */
	long rate, decode_rate;
	int channels;
	const long *rates;
	size_t      num_rates, rlimit;
	debug("audio_capabilities");
	mpg123_rates(&rates, &num_rates);
	mpg123_format_none(mh); /* Start with nothing. */
	if(param.force_encoding != NULL)
	{
		int i;
		if(!param.quiet) fprintf(stderr, "Note: forcing output encoding %s\n", param.force_encoding);

		for(i=0;i<KNOWN_ENCS;++i)
		if(!strncasecmp(encdesc[i].name, param.force_encoding, encdesc[i].nlen))
		{
			force_fmt = encdesc[i].code;
			break;
		}

		if(i==KNOWN_ENCS)
		{
			error1("Failed to find an encoding to match requested \"%s\"!\n", param.force_encoding);
			return; /* No capabilities at all... */
		}
		else if(param.verbose > 2) fprintf(stderr, "Note: forcing encoding code 0x%x\n", force_fmt);
	}
	rlimit = param.force_rate > 0 ? num_rates+1 : num_rates;
	for(channels=1; channels<=2; channels++)
	for(ri = 0;ri<rlimit;ri++)
	{
		decode_rate = ri < num_rates ? rates[ri] : param.force_rate;
		rate = pitch_rate(decode_rate);
		if(param.verbose > 2) fprintf(stderr, "Note: checking support for %liHz/%ich.\n", rate, channels);
#ifndef NOXFERMEM
		if(param.usebuffer)
		{ /* Ask the buffer process. It is waiting for this. */
			buffermem->rate     = rate; 
			buffermem->channels = channels;
			buffermem->format   = 0; /* Just have it initialized safely. */
			debug2("asking for formats for %liHz/%ich", rate, channels);
			xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_AUDIOCAP);
			xfermem_getcmd(buffermem->fd[XF_WRITER], TRUE);
			fmts = buffermem->format;
		}
		else
#endif
		{ /* Check myself. */
			ao->rate     = rate;
			ao->channels = channels;
			fmts = ao->get_formats(ao);
		}
		if(param.verbose > 2) fprintf(stderr, "Note: result 0x%x\n", fmts);
		if(force_fmt)
		{ /* Filter for forced encoding. */
			if((fmts & force_fmt) == force_fmt) fmts = force_fmt;
			else fmts = 0; /* Nothing else! */

			if(param.verbose > 2) fprintf(stderr, "Note: after forcing 0x%x\n", fmts);
		}

		if(fmts < 0) continue;
		else mpg123_format(mh, decode_rate, channels, fmts);
	}

#ifndef NOXFERMEM
	/* Buffer loop shall start normal operation now. */
	if(param.usebuffer)
	{
		xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_WAKEUP);
		xfermem_getcmd(buffermem->fd[XF_WRITER], TRUE);
	}
#endif

	if(param.verbose > 1) print_capabilities(ao, mh);
}
Exemplo n.º 3
0
void buffer_loop(audio_output_t *ao, sigset_t *oldsigset)
{
	int bytes, outbytes;
	int my_fd = buffermem->fd[XF_READER];
	txfermem *xf = buffermem;
	int done = FALSE;
	int preload;

	catchsignal (SIGINT, catch_interrupt);
	catchsignal (SIGUSR1, catch_usr1);
	sigprocmask (SIG_SETMASK, oldsigset, NULL);

	xfermem_putcmd(my_fd, XF_CMD_WAKEUP);

	debug("audio output: waiting for cap requests");
	/* wait for audio setup queries */
	while(1)
	{
		int cmd;
		cmd = xfermem_block(XF_READER, xf);
		if(cmd == XF_CMD_AUDIOCAP)
		{
			ao->rate     = xf->rate;
			ao->channels = xf->channels;
			ao->format   = ao->get_formats(ao);
			debug3("formats for %liHz/%ich: 0x%x", ao->rate, ao->channels, ao->format);
			xf->format = ao->format;
			xfermem_putcmd(my_fd, XF_CMD_AUDIOCAP);
		}
		else if(cmd == XF_CMD_WAKEUP)
		{
			debug("got wakeup... leaving config mode");
			xfermem_putcmd(buffermem->fd[XF_READER], XF_CMD_WAKEUP);
			break;
		}
		else
		{
			error1("unexpected command %i", cmd);
			return;
		}
	}

	/* Fill complete buffer on first run before starting to play.
	 * Live mp3 streams constantly approach buffer underrun otherwise. [dk]
	 */
	preload = (int)(param.preload*xf->size);
	if(preload > xf->size) preload = xf->size;
	if(preload < 0) preload = 0;

	for (;;) {
		if (intflag) {
			debug("handle intflag... flushing");
			intflag = FALSE;
			ao->flush(ao);
			/* Either prepare for waiting or empty buffer now. */
			if(!xf->justwait) xf->readindex = xf->freeindex;
			else
			{
				int cmd;
				debug("Prepare for waiting; draining command queue. (There's a lot of wakeup commands pending, usually.)");
				do
				{
					cmd = xfermem_getcmd(my_fd, FALSE);
					/* debug1("drain: %i",  cmd); */
				} while(cmd > 0);
			}
			if(xf->wakeme[XF_WRITER]) xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
		}
		if (usr1flag) {
			debug("handling usr1flag");
			usr1flag = FALSE;
			/*   close and re-open in order to flush
			 *   the device's internal buffer before
			 *   changing the sample rate.   [OF]
			 */
			/* writer must block when sending SIGUSR1
			 * or we will lose all data processed 
			 * in the meantime! [dk]
			 */
			xf->readindex = xf->freeindex;
			/* We've nailed down the new starting location -
			 * writer is now safe to go on. [dk]
			 */
			if (xf->wakeme[XF_WRITER])
				xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
			ao->rate = xf->rate; 
			ao->channels = xf->channels; 
			ao->format = xf->format;
			if (reset_output(ao) < 0) {
				error1("failed to reset audio: %s", strerror(errno));
				exit(1);
			}
		}
		if ( (bytes = xfermem_get_usedspace(xf)) < outburst ) {
			/* if we got a buffer underrun we first
			 * fill 1/8 of the buffer before continue/start
			 * playing */
			if (preload < xf->size>>3)
				preload = xf->size>>3;
			if(preload < outburst)
				preload = outburst;
		}
		debug1("bytes: %i", bytes);
		if(xf->justwait || bytes < preload) {
			int cmd;
			if (done && !bytes) { 
				break;
			}
			
			if(xf->justwait || !done) {

				/* Don't spill into errno check below. */
				errno = 0;
				cmd = xfermem_block(XF_READER, xf);
				debug1("got %i", cmd);
				switch(cmd) {

					/* More input pending. */
					case XF_CMD_WAKEUP_INFO:
						continue;
					/* Yes, we know buffer is low but
					 * know we don't care.
					 */
					case XF_CMD_WAKEUP:
						break;	/* Proceed playing. */
					case XF_CMD_ABORT: /* Immediate end, discard buffer contents. */
						return; /* Cleanup happens outside of buffer_loop()*/
					case XF_CMD_TERMINATE: /* Graceful end, playing stuff in buffer and then return. */
						debug("going to terminate");
						done = TRUE;
						break;
					case XF_CMD_RESYNC:
						debug("ordered resync");
						if (param.outmode == DECODE_AUDIO) ao->flush(ao);

						xf->readindex = xf->freeindex;
						if (xf->wakeme[XF_WRITER]) xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
						continue;
						break;
					case -1:
						if(intflag || usr1flag) /* Got signal, handle it at top of loop... */
						{
							debug("buffer interrupted");
							continue;
						}
						if(errno)
							error1("Yuck! Error in buffer handling... or somewhere unexpected: %s", strerror(errno));
						done = TRUE;
						xf->readindex = xf->freeindex;
						xfermem_putcmd(xf->fd[XF_READER], XF_CMD_TERMINATE);
						break;
					default:
						fprintf(stderr, "\nEh!? Received unknown command 0x%x in buffer process.\n", cmd);
				}
			}
		}
		/* Hack! The writer issues XF_CMD_WAKEUP when first adjust 
		 * audio settings. We do not want to lower the preload mark
		 * just yet!
		 */
		if (xf->justwait || !bytes)
			continue;
		preload = outburst; /* set preload to lower mark */
		if (bytes > xf->size - xf->readindex)
			bytes = xf->size - xf->readindex;
		if (bytes > outburst)
			bytes = outburst;

		/* The output can only take multiples of framesize. */
		bytes -= bytes % ao->framesize;

		debug("write");
		outbytes = flush_output(ao, (unsigned char*) xf->data + xf->readindex, bytes);

		if(outbytes < bytes)
		{
			if(outbytes < 0) outbytes = 0;
			if(!intflag && !usr1flag) {
				error1("Ouch ... error while writing audio data: %s", strerror(errno));
				/*
				 * done==TRUE tells writer process to stop
				 * sending data. There might be some latency
				 * involved when resetting readindex to 
				 * freeindex so we might need more than one
				 * cycle to terminate. (The number of cycles
				 * should be finite unless I managed to mess
				 * up something. ;-) [dk]
				 */
				done = TRUE;	
				xf->readindex = xf->freeindex;
				xfermem_putcmd(xf->fd[XF_READER], XF_CMD_TERMINATE);
			}
			else debug("buffer interrupted");
		}
		bytes = outbytes;

		xf->readindex = (xf->readindex + bytes) % xf->size;
		if (xf->wakeme[XF_WRITER])
			xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
	}
}