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.

Reply via email to