=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/sndiod/dev.c,v retrieving revision 1.11 retrieving revision 1.12 diff -c -r1.11 -r1.12 *** src/usr.bin/sndiod/dev.c 2014/03/05 20:24:16 1.11 --- src/usr.bin/sndiod/dev.c 2014/03/05 20:31:22 1.12 *************** *** 1,4 **** ! /* $OpenBSD: dev.c,v 1.11 2014/03/05 20:24:16 ratchov Exp $ */ /* * Copyright (c) 2008-2012 Alexandre Ratchov * --- 1,4 ---- ! /* $OpenBSD: dev.c,v 1.12 2014/03/05 20:31:22 ratchov Exp $ */ /* * Copyright (c) 2008-2012 Alexandre Ratchov * *************** *** 55,65 **** void dev_mix_badd(struct dev *, struct slot *); void dev_empty_cycle(struct dev *); void dev_mix_adjvol(struct dev *); - void dev_mix_cycle(struct dev *); int rec_filt_resamp(struct slot *, void *, void *, int); int rec_filt_enc(struct slot *, void *, void *, int); void dev_sub_bcopy(struct dev *, struct slot *); ! void dev_sub_cycle(struct dev *); void dev_onmove(struct dev *, int); void dev_master(struct dev *, unsigned int); --- 55,64 ---- void dev_mix_badd(struct dev *, struct slot *); void dev_empty_cycle(struct dev *); void dev_mix_adjvol(struct dev *); int rec_filt_resamp(struct slot *, void *, void *, int); int rec_filt_enc(struct slot *, void *, void *, int); void dev_sub_bcopy(struct dev *, struct slot *); ! void dev_full_cycle(struct dev *); void dev_onmove(struct dev *, int); void dev_master(struct dev *, unsigned int); *************** *** 93,102 **** void slot_start(struct slot *); void slot_detach(struct slot *); void slot_stop(struct slot *); void slot_write(struct slot *); void slot_read(struct slot *); ! void slot_mix_drop(struct slot *); ! void slot_sub_sil(struct slot *); struct midiops dev_midiops = { dev_midi_imsg, --- 92,101 ---- void slot_start(struct slot *); void slot_detach(struct slot *); void slot_stop(struct slot *); + void slot_skip_update(struct slot *); void slot_write(struct slot *); void slot_read(struct slot *); ! int slot_skip(struct slot *); struct midiops dev_midiops = { dev_midi_imsg, *************** *** 541,584 **** dev_close(d); } ! void ! slot_mix_drop(struct slot *s) { ! while (s->mix.drop > 0 && s->mix.buf.used >= s->round * s->mix.bpf) { ! #ifdef DEBUG ! if (log_level >= 4) { ! slot_log(s); ! log_puts(": dropped a play block\n"); ! } ! #endif ! abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf); ! s->mix.drop--; ! } ! } ! void ! slot_sub_sil(struct slot *s) ! { ! unsigned char *data; ! int count; ! ! while (s->sub.silence > 0) { ! data = abuf_wgetblk(&s->sub.buf, &count); ! if (count < s->round * s->sub.bpf) ! break; #ifdef DEBUG if (log_level >= 4) { slot_log(s); ! log_puts(": inserted a rec block of silence\n"); } #endif ! if (s->sub.encbuf) ! enc_sil_do(&s->sub.enc, data, s->round); ! else ! memset(data, 0, s->round * s->sub.bpf); ! abuf_wcommit(&s->sub.buf, s->round * s->sub.bpf); ! s->sub.silence--; } } /* --- 540,581 ---- dev_close(d); } ! int ! slot_skip(struct slot *s) { ! unsigned char *data = (unsigned char *)0xdeadbeef; /* please gcc */ ! int max, count; ! max = s->skip; ! while (s->skip > 0) { ! if (s->pstate != SLOT_STOP && (s->mode & MODE_RECMASK)) { ! data = abuf_wgetblk(&s->sub.buf, &count); ! if (count < s->round * s->sub.bpf) ! break; ! } ! if (s->mode & MODE_PLAY) { ! if (s->mix.buf.used < s->round * s->mix.bpf) ! break; ! } #ifdef DEBUG if (log_level >= 4) { slot_log(s); ! log_puts(": skipped a cycle\n"); } #endif ! if (s->pstate != SLOT_STOP && (s->mode & MODE_RECMASK)) { ! if (s->sub.encbuf) ! enc_sil_do(&s->sub.enc, data, s->round); ! else ! memset(data, 0, s->round * s->sub.bpf); ! abuf_wcommit(&s->sub.buf, s->round * s->sub.bpf); ! } ! if (s->mode & MODE_PLAY) { ! abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf); ! } ! s->skip--; } + return max - s->skip; } /* *************** *** 716,814 **** } } - void - dev_mix_cycle(struct dev *d) - { - struct slot *s, **ps; - unsigned char *base; - int nsamp; - - #ifdef DEBUG - if (log_level >= 4) { - dev_log(d); - log_puts(": dev_mix_cycle, poffs = "); - log_puti(d->poffs); - log_puts("\n"); - } - #endif - base = (unsigned char *)DEV_PBUF(d); - nsamp = d->round * d->pchan; - memset(base, 0, nsamp * sizeof(adata_t)); - ps = &d->slot_list; - while ((s = *ps) != NULL) { - if (!(s->mode & MODE_PLAY)) { - ps = &s->next; - continue; - } - #ifdef DEBUG - if (log_level >= 4) { - slot_log(s); - log_puts(": mixing, drop = "); - log_puti(s->mix.drop); - log_puts(" cycles\n"); - } - #endif - slot_mix_drop(s); - if (s->mix.drop < 0) { - s->mix.drop++; - ps = &s->next; - continue; - } - if (s->mix.buf.used < s->round * s->mix.bpf && - s->pstate == SLOT_STOP) { - /* - * partial blocks are zero-filled by socket - * layer - */ - s->pstate = SLOT_INIT; - abuf_done(&s->mix.buf); - if (s->mix.decbuf) - xfree(s->mix.decbuf); - if (s->mix.resampbuf) - xfree(s->mix.resampbuf); - s->ops->eof(s->arg); - *ps = s->next; - dev_mix_adjvol(d); - continue; - } - if (s->mix.buf.used < s->round * s->mix.bpf && - !(s->pstate == SLOT_STOP)) { - if (s->xrun == XRUN_IGNORE) { - if (s->mode & MODE_RECMASK) - s->sub.silence--; - s->delta -= s->round; - #ifdef DEBUG - if (log_level >= 3) { - slot_log(s); - log_puts(": underrun, pause cycle\n"); - } - #endif - ps = &s->next; - continue; - } - if (s->xrun == XRUN_SYNC) { - s->mix.drop++; - ps = &s->next; - continue; - } - if (s->xrun == XRUN_ERROR) { - s->ops->exit(s->arg); - *ps = s->next; - continue; - } - } else { - dev_mix_badd(d, s); - if (s->pstate != SLOT_STOP) - s->ops->fill(s->arg); - } - ps = &s->next; - } - if (d->encbuf) { - enc_do(&d->enc, (unsigned char *)DEV_PBUF(d), - d->encbuf, d->round); - } - } - int rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo) { --- 713,718 ---- *************** *** 872,931 **** } void ! dev_sub_cycle(struct dev *d) { struct slot *s, **ps; #ifdef DEBUG if (log_level >= 4) { dev_log(d); ! log_puts(": dev_sub_cycle\n"); } #endif if ((d->mode & MODE_REC) && d->decbuf) dec_do(&d->dec, d->decbuf, (unsigned char *)d->rbuf, d->round); ps = &d->slot_list; while ((s = *ps) != NULL) { ! if (!(s->mode & MODE_RECMASK) || s->pstate == SLOT_STOP) { ps = &s->next; continue; } ! slot_sub_sil(s); ! if (s->sub.silence < 0) { ! s->sub.silence++; ! ps = &s->next; continue; } ! if (s->sub.buf.len - s->sub.buf.used < s->round * s->sub.bpf) { if (s->xrun == XRUN_IGNORE) { - if (s->mode & MODE_PLAY) - s->mix.drop--; s->delta -= s->round; #ifdef DEBUG if (log_level >= 3) { slot_log(s); ! log_puts(": overrun, pause cycle\n"); } #endif ! ps = &s->next; ! continue; } - if (s->xrun == XRUN_SYNC) { - s->sub.silence++; - ps = &s->next; - continue; - } - if (s->xrun == XRUN_ERROR) { - s->ops->exit(s->arg); - *ps = s->next; - continue; - } - } else { - dev_sub_bcopy(d, s); - s->ops->flush(s->arg); } ps = &s->next; } } /* --- 776,917 ---- } void ! dev_full_cycle(struct dev *d) { struct slot *s, **ps; + unsigned char *base; + int nsamp; + d->delta -= d->round; #ifdef DEBUG if (log_level >= 4) { dev_log(d); ! log_puts(": dev_full_cycle: clk="); ! log_puti(d->delta); ! if (d->mode & MODE_PLAY) { ! log_puts(", poffs = "); ! log_puti(d->poffs); ! } ! log_puts("\n"); } #endif + if (d->mode & MODE_PLAY) { + base = (unsigned char *)DEV_PBUF(d); + nsamp = d->round * d->pchan; + memset(base, 0, nsamp * sizeof(adata_t)); + } if ((d->mode & MODE_REC) && d->decbuf) dec_do(&d->dec, d->decbuf, (unsigned char *)d->rbuf, d->round); ps = &d->slot_list; while ((s = *ps) != NULL) { ! #ifdef DEBUG ! if (log_level >= 4) { ! slot_log(s); ! log_puts(": running"); ! log_puts(", skip = "); ! log_puti(s->skip); ! log_puts("\n"); ! } ! #endif ! /* ! * skip cycles for XRUN_SYNC correction ! */ ! slot_skip(s); ! if (s->skip < 0) { ! s->skip++; ps = &s->next; continue; } ! ! #ifdef DEBUG ! if (s->pstate == SLOT_STOP && !(s->mode & MODE_PLAY)) { ! slot_log(s); ! log_puts(": rec-only slots can't be drained\n"); ! panic(); ! } ! #endif ! /* ! * check if stopped stream finished draining ! */ ! if (s->pstate == SLOT_STOP && ! s->mix.buf.used < s->round * s->mix.bpf) { ! /* ! * partial blocks are zero-filled by socket ! * layer, so s->mix.buf.used == 0 and we can ! * destroy the buffer ! */ ! s->pstate = SLOT_INIT; ! abuf_done(&s->mix.buf); ! if (s->mix.decbuf) ! xfree(s->mix.decbuf); ! if (s->mix.resampbuf) ! xfree(s->mix.resampbuf); ! s->ops->eof(s->arg); ! *ps = s->next; ! dev_mix_adjvol(d); continue; } ! ! /* ! * check for xruns ! */ ! if (((s->mode & MODE_PLAY) && ! s->mix.buf.used < s->round * s->mix.bpf) || ! ((s->mode & MODE_RECMASK) && ! s->sub.buf.len - s->sub.buf.used < ! s->round * s->sub.bpf)) { ! ! #ifdef DEBUG ! if (log_level >= 3) { ! slot_log(s); ! log_puts(": xrun, pause cycle\n"); ! } ! #endif if (s->xrun == XRUN_IGNORE) { s->delta -= s->round; + ps = &s->next; + } else if (s->xrun == XRUN_SYNC) { + s->skip++; + ps = &s->next; + } else if (s->xrun == XRUN_ERROR) { + s->ops->exit(s->arg); + *ps = s->next; + } else { #ifdef DEBUG + slot_log(s); + log_puts(": bad xrun mode\n"); + panic(); + #endif + } + continue; + } + if (s->mode & MODE_PLAY) { + dev_mix_badd(d, s); + if (s->pstate != SLOT_STOP) + s->ops->fill(s->arg); + } + if ((s->mode & MODE_RECMASK) && !(s->pstate == SLOT_STOP)) { + if (s->sub.prime == 0) { + dev_sub_bcopy(d, s); + s->ops->flush(s->arg); + } else { + #ifdef DEBUG if (log_level >= 3) { slot_log(s); ! log_puts(": prime = "); ! log_puti(s->sub.prime); ! log_puts("\n"); } #endif ! s->sub.prime--; } } ps = &s->next; } + if ((d->mode & MODE_PLAY) && d->encbuf) { + enc_do(&d->enc, (unsigned char *)DEV_PBUF(d), + d->encbuf, d->round); + } } /* *************** *** 935,946 **** dev_onmove(struct dev *d, int delta) { long long pos; ! struct slot *s, *snext; ! /* ! * s->ops->onmove() may remove the slot ! */ for (s = d->slot_list; s != NULL; s = snext) { snext = s->next; pos = (long long)delta * s->round + s->delta_rem; s->delta_rem = pos % d->round; --- 921,934 ---- dev_onmove(struct dev *d, int delta) { long long pos; ! struct slot *s, *snext; ! d->delta += delta; ! for (s = d->slot_list; s != NULL; s = snext) { + /* + * s->ops->onmove() may remove the slot + */ snext = s->next; pos = (long long)delta * s->round + s->delta_rem; s->delta_rem = pos % d->round; *************** *** 994,1003 **** d->prime -= d->round; dev_empty_cycle(d); } else { ! if (d->mode & MODE_RECMASK) ! dev_sub_cycle(d); ! if (d->mode & MODE_PLAY) ! dev_mix_cycle(d); } } --- 982,988 ---- d->prime -= d->round; dev_empty_cycle(d); } else { ! dev_full_cycle(d); } } *************** *** 1332,1337 **** --- 1317,1326 ---- } else { d->prime = 0; } + + /* empty cycles don't increment delta */ + d->delta = 0; + d->pstate = DEV_RUN; dev_sio_start(d); } *************** *** 1675,1680 **** --- 1664,1670 ---- { struct dev *d = s->dev; unsigned int slot_nch, dev_nch; + long long pos; int startpos; /* *************** *** 1687,1700 **** * played and/or recorded */ startpos = dev_getpos(d) * (int)s->round / (int)d->round; ! s->delta = startpos; ! s->delta_rem = 0; s->pstate = SLOT_RUN; #ifdef DEBUG ! if (log_level >= 3) { slot_log(s); log_puts(": attached at "); log_puti(startpos); log_puts("\n"); } #endif --- 1677,1698 ---- * played and/or recorded */ startpos = dev_getpos(d) * (int)s->round / (int)d->round; ! ! /* ! * adjust initial clock ! */ ! pos = (long long)d->delta * s->round; ! s->delta = startpos + pos / (int)d->round; ! s->delta_rem = pos % d->round; ! s->pstate = SLOT_RUN; #ifdef DEBUG ! if (log_level >= 0) { slot_log(s); log_puts(": attached at "); log_puti(startpos); + log_puts(", delta = "); + log_puti(d->delta); log_puts("\n"); } #endif *************** *** 1713,1718 **** --- 1711,1717 ---- #endif s->next = d->slot_list; d->slot_list = s; + s->skip = 0; if (s->mode & MODE_PLAY) { slot_nch = s->mix.slot_cmax - s->mix.slot_cmin + 1; dev_nch = s->mix.dev_cmax - s->mix.dev_cmin + 1; *************** *** 1742,1748 **** s->mix.resampbuf = xmalloc(d->round * slot_nch * sizeof(adata_t)); } - s->mix.drop = 0; s->mix.vol = MIDI_TO_ADATA(s->vol); dev_mix_adjvol(d); } --- 1741,1746 ---- *************** *** 1779,1785 **** /* * N-th recorded block is the N-th played block */ ! s->sub.silence = startpos / (int)s->round; } } --- 1777,1783 ---- /* * N-th recorded block is the N-th played block */ ! s->sub.prime = -startpos / (int)s->round; } } *************** *** 1958,1963 **** --- 1956,1982 ---- s->tstate = MMC_STOP; } + void + slot_skip_update(struct slot *s) + { + int skip; + + skip = slot_skip(s); + while (skip > 0) { + #ifdef DEBUG + if (log_level >= 4) { + slot_log(s); + log_puts(": catching skipped block\n"); + } + #endif + if (s->mode & MODE_RECMASK) + s->ops->flush(s->arg); + if (s->mode & MODE_PLAY) + s->ops->fill(s->arg); + skip--; + } + } + /* * notify the slot that we just wrote in the play buffer, must be called * after each write *************** *** 1965,1972 **** void slot_write(struct slot *s) { - int drop; - if (s->pstate == SLOT_START && s->mix.buf.used == s->mix.buf.len) { #ifdef DEBUG if (log_level >= 4) { --- 1984,1989 ---- *************** *** 1977,1994 **** s->pstate = SLOT_READY; slot_ready(s); } ! drop = s->mix.drop; ! slot_mix_drop(s); ! while (drop > s->mix.drop) { ! #ifdef DEBUG ! if (log_level >= 4) { ! slot_log(s); ! log_puts(": catching play block\n"); ! } ! #endif ! s->ops->fill(s->arg); ! drop--; ! } } /* --- 1994,2000 ---- s->pstate = SLOT_READY; slot_ready(s); } ! slot_skip_update(s); } /* *************** *** 1997,2014 **** void slot_read(struct slot *s) { ! int sil; ! ! sil = s->sub.silence; ! slot_sub_sil(s); ! while (sil > s->sub.silence) { ! #ifdef DEBUG ! if (log_level >= 4) { ! slot_log(s); ! log_puts(": catching rec block\n"); ! } ! #endif ! s->ops->flush(s->arg); ! sil--; ! } } --- 2003,2007 ---- void slot_read(struct slot *s) { ! slot_skip_update(s); }