void real_buffer_ignore_lowmem(void) { if (!buffermem) return; if(buffermem->wakeme[XF_READER]) xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_WAKEUP); }
void buffer_ignore_lowmem(void) { #ifndef NOXFERMEM if(buffermem->wakeme[XF_READER]) xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_WAKEUP); #endif }
void real_buffer_start(void) { if(buffermem->justwait) { debug("ending buffer's waiting"); buffermem->justwait = FALSE; xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_WAKEUP); } }
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); }
/* 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); }
void real_buffer_end(int rude) { if (!buffermem) return; xfermem_putcmd(buffermem->fd[XF_WRITER], rude ? XF_CMD_ABORT : XF_CMD_TERMINATE); }
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); } }
void buffer_loop(struct audio_info_struct *ai, sigset_t *oldsigset) { int bytes; int my_fd = buffermem->fd[XF_READER]; txfermem *xf = buffermem; int done = FALSE; catchsignal (SIGINT, catch_interrupt); catchsignal (SIGUSR1, catch_usr1); sigprocmask (SIG_SETMASK, oldsigset, NULL); #ifndef NO_DECODE_AUDIO if (param.outmode == DECODE_AUDIO) { if (audio_open(ai) < 0) { perror("audio"); exit(1); } } #endif for (;;) { if (intflag) { intflag = FALSE; #ifndef NO_DECODE_AUDIO if (param.outmode == DECODE_AUDIO) audio_queueflush (ai); #endif xf->readindex = xf->freeindex; if (xf->wakeme[XF_WRITER]) xfermem_putcmd(my_fd, XF_CMD_WAKEUP); } if (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); #ifndef NO_DECODE_AUDIO if (param.outmode == DECODE_AUDIO) { audio_close (ai); ai->rate = xf->buf[0]; ai->channels = xf->buf[1]; ai->format = xf->buf[2]; if (audio_open(ai) < 0) { sleep(1); /* give em a 2. try */ if (audio_open(ai) < 0) { perror("audio"); exit(1); } } } #endif } 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 */ preload = xf->size>>3; if(preload < outburst) preload = outburst; } if(bytes < preload) { int cmd; if (done && !bytes) { break; } if(!done) { cmd = xfermem_block(XF_READER, xf); 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_TERMINATE: /* Proceed playing without * blocking any further. */ done=TRUE; break; case -1: if(errno==EINTR) continue; perror("Yuck! Error in buffer handling..."); 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. Tell Daniel!\n", cmd); } } } preload = outburst; /* set preload to lower mark */ if (bytes > xf->size - xf->readindex) bytes = xf->size - xf->readindex; if (bytes > outburst) bytes = outburst; if (param.outmode == DECODE_FILE) bytes = write(OutputDescriptor, xf->data + xf->readindex, bytes); #ifndef NO_DECODE_AUDIO else if (param.outmode == DECODE_AUDIO) bytes = audio_play_samples(ai, (unsigned char *) (xf->data + xf->readindex), bytes); #endif if(bytes < 0) { bytes = 0; if(errno != EINTR) { perror("Ouch ... error while writing audio data: "); /* * 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); } } xf->readindex = (xf->readindex + bytes) % xf->size; if (xf->wakeme[XF_WRITER]) xfermem_putcmd(my_fd, XF_CMD_WAKEUP); }
void buffer_end(void) { #ifndef NOXFERMEM xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_TERMINATE); #endif }