On Mon, Jan 06, 2020 at 07:55:22AM -0500, Peter Piwowarski wrote: > On Mon, 6 Jan 2020 07:43:12 +0100 > Alexandre Ratchov <a...@caoua.org> wrote: > > > The number of channels on the device is restricted by the > > s->opt->{pmin,pmax} variables. It is the number of channels common to > > the [0 : dev->pchan - 1] and [s->opt->pmin : s->opt->pmax] ranges. > > > > Note that there may be no overlap if s->opt->pmin >= dev->pchan, there > > are no audible channels in this case. For instance this may happen for > > a program playing on channels 2:3 of a 4-channel device which is > > dynamically replaced by a 2-channel device. > > > > In this case s->mix.cmap.nch == 0. > > Is this the same as might be achieved by the following? >
No, my example was about something that could be obtained with: sndiod -ddd -c 2:3 on a 2-channel audio device, then: aucat -i /dev/random In this case aucat channels 0:1 are routed to device channels 2:3 which do not exist on the hardware, so the signal is discarded. In this case d->pchan = 2, s->opt->pmax = 2, s->opt->pmax = 3. > $ sndiod -ddd -c 0:1 -j on & > $ aucat -i /dev/random -c 2:3 > > If so, is the expected behavior that channels 2 and 3 play on the > subdevice's channels 0 and 1? Yes. In your example, aucat sends 4-channel signal which is supposed to be joined as follows: aucat channel device channel --------------------------------- 0 silence -> 0 1 silence -> 1 2 /dev/random -> 0 3 /dev/random -> 1 So the noise is supposed to be audible. If "-j off" was used, then channel 2:3 wouldn't be joined to 0:1 and would be discarded. As 0:1 contain silence the noise should not be audible. Same logic as stereo->mono conversion, but with more channels. > > > Index: dev.c > > > =================================================================== > > > RCS file: /cvs/src/usr.bin/sndiod/dev.c,v > > > retrieving revision 1.62 > > > diff -u -p -r1.62 dev.c > > > --- dev.c 21 Sep 2019 04:42:46 -0000 1.62 > > > +++ dev.c 4 Jan 2020 01:01:20 -0000 > > > @@ -1501,9 +1501,14 @@ dev_mmcloc(struct dev *d, unsigned int o > > > void > > > slot_initconv(struct slot *s) > > > { > > > + unsigned int target_nch; > > > struct dev *d = s->dev; > > > > > > if (s->mode & MODE_PLAY) { > > > + target_nch = d->pchan < (s->opt->pmax - s->opt->pmin + 1) > > > + ? d->pchan > > > + : (s->opt->pmax - s->opt->pmin + 1); > > > + > > > > AFAIU this works only if s->opt->pmin == 0. As s->opt->pmin >= 0, the > > number of device channels is: > > > > target_nch = (d->pchan < s->opt->pmax + 1) ? > > d->pchan - s->opt->pmin : s->opt->pmax - s->opt->pmin + 1; > > I probably need to play with it some more to understand why this is; are > we trying to determine the number of channels with the same number both > in the stream and on the device? We try to determine the number of channels common to the hardware device and to the the sub-device (the s->opt structure, ie -c option argument). The -c option defines a subset of channels of the device to which clients channels are routed. Typically this is used to expose separate sub-devices for different channel pairs of many-channel devices. For instance on a 8-channel device where "-c 4:5" is set there are two channels used (4 and 5), so target_nch == 2 in this case. Another example, on a 6-channel device where "-c 4:7" is set there are two channels used only (4 and 5) as channels 6 and 7 are missing on the hardware. > If so, should that be factored into the > logic in a different way such that we output something in my example > above? (I *think* what happens with my example and this logic is that we > decide the device has no channels which we can expand to, and we therefore > output nothing...) > > > which is valid only if there are audible channels, i.e. if > > s->mix.cmap.nch > 0, so this could be handled by changing below > > condition to: > > > > if (s->opt->dup && s->mix.cmap.nch > 0) > > > > and moving the target_nch calculation inside the "true" conditional > > code block. > > If I understand correctly, this also will cause the join logic to be > skipped if we have no overlap between the stream and the device. Exactly. The stream starting channel is always s->opt->pmin, so if there's no overlap between the device and s->opt (-c argumet), then the stream is not audible. So there's nothing to join/expand. > > > @@ -1519,14 +1524,18 @@ slot_initconv(struct slot *s) > > > s->mix.join = 1; > > > s->mix.expand = 1; > > > if (s->opt->dup) { > > > - if (s->mix.cmap.nch > s->mix.nch) > > > - s->mix.expand = s->mix.cmap.nch / s->mix.nch; > > > - else if (s->mix.cmap.nch > 0) > > > - s->mix.join = s->mix.nch / s->mix.cmap.nch; > > > + if (target_nch > s->mix.nch) > > > + s->mix.expand = target_nch / s->mix.nch; > > > + else if (s->mix.cmap.nch > target_nch) > > > + s->mix.join = s->mix.nch / target_nch; > > > } > > > } > > > > > > if (s->mode & MODE_RECMASK) { > > > + target_nch = d->rchan < (s->opt->rmax - s->opt->rmin + 1) > > ^^^^^^^^ > > d->pchan in the (s->mode & MODE_MON) case. > > This requires another conditional, then? > yes, something like: (s->mode & MODE_MON) ? d->pchan : d->rchan this is already used as cmap_init() argument.