Almost there

Okay I have PCM part of Maestro working too, more or less.
Now I really need to know what to do with subchannels. Do I have to
create ‘subchannel mixers’ if I allow multiple acquires? Docs say that
‘volume set’ and ‘mute set’ functions of ‘subchannel mixer’ are
optional, what is purpose of the subchannel mixer then? What do I get by
creating it? How does it appear on user side (with and without those
optional funcs)?

Also, template driver suggests to use ado_mutex_lock in the interrupt
handler, but ado_mutex_lock is wrapper for pthread_mutex_lock which is
nointerrupt-safe. I tried and easily got myself a MUTEX deadlock between
2 threads of io-audio.I guess I should use InterruprLock, right?

Thanks,

  • Igor

Igor Kovalenko <kovalenko@home.com> wrote:

Okay I have PCM part of Maestro working too, more or less.
Now I really need to know what to do with subchannels. Do I have to
create ‘subchannel mixers’ if I allow multiple acquires? Docs say that
‘volume set’ and ‘mute set’ functions of ‘subchannel mixer’ are
optional, what is purpose of the subchannel mixer then? What do I get by
creating it? How does it appear on user side (with and without those
optional funcs)?

Subchannel mixers are simply mixer groups that are associated directly with
a particular subchannel. They are visible to the user through the
snd_pcm_channel_info() call in the mixer_gid member. Note: You must call
snd_pcm_channel_info() after you have configured the channel with a call
to snd_pcm_channel_params(). If you call it before, the subchannel has
not been allocated yet, so you get the next best thing, the PCM mixer
group. This is expected to be the most commonly accessed control in the
mixer (from an API point of view). Most application writers are writing
players that want a single control for their application only. That is
what the subchannel mixer group is intended for. It allows independent
controls for each application.

Implementation of subchannel mixers is recommended, but completely
optional. If they do not exist, the lib will pass on the next best
thing instead.

Here is a short section of code demonstrating how to setup a subchannel
mixer. It is for a fictional card called “Zone” (name changed to protect
the guilty :slight_smile:. Note that the volume and mute functions have the same
prototype. That is by design. You can have a single function, or two
as demonstrated here.

static void
zone_subchn_volume_set (HW_CONTEXT_T * zone,
PCM_SUBCHN_CONTEXT_T * zsc,
int32_t * volumes,
int32_t mute,
ado_pcm_subchn_mixer_config_t * config)
{
zone_voice_t *leftvoice, *rightvoice;
uint32_t value;

leftvoice = zsc->voice[0];
if (zsc->config->format.voices == 1)
rightvoice = zsc->voice[0];
else
rightvoice = zsc->voice[1];

zone_readvalue (zone, leftvoice->num, VOL, &value);
value &= 0xff00;
zone_writevalue (zone,
leftvoice->num, VOL, volumes[0] | value);

zone_readvalue (zone, rightvoice->num, RIGHT_VOL, &value);
value &= 0xff00;
zone_writevalue (zone,
rightvoice->num, VOL, volumes[1] | value);
}

static void
zone_subchn_mute_set ( HW_CONTEXT_T * zone,
PCM_SUBCHN_CONTEXT_T * zsc,
int32_t * volumes,
int32_t mute,
ado_pcm_subchn_mixer_config_t * config)
{
zone_voice_t *leftvoice, *rightvoice;
uint32_t value;

leftvoice = zsc->voice[0];
if (zsc->config->format.voices == 1)
rightvoice = zsc->voice[0];
else
rightvoice = zsc->voice[1];

zone_readvalue (zone, leftvoice->num, VOL, &value);
value &= 0x00ff;
zone_writevalue (zone,
leftvoice->num, VOL, (mute & (1 << 0)) ? 0x8000 : 0x0000 | value);

zone_readvalue (zone, rightvoice->num, RIGHT_VOL, &value);
value &= 0x00ff;
zone_writevalue (zone,
rightvoice->num, VOL, (mute & (1 << 1)) ? 0x8000 : 0x0000 | value);
}


int32_t
zone_playback_aquire (HW_CONTEXT_T * zone,
PCM_SUBCHN_CONTEXT_T ** zsc,
ado_pcm_config_t * config,
ado_pcm_subchn_t * subchn,
uint32_t * why_failed)
{
ado_pcm_subchn_mixer_config_t zsc_mix_cfg;

ado_mutex_lock (&zone->hw_lock);

memset (&zsc_mix_cfg, 0, sizeof (zsc_mix_cfg));
zsc_mix_cfg.hw_context = zone;
zsc_mix_cfg.pcm_sc_context = *zsc;
zsc_mix_cfg.channel_mask = SND_MIXER_CHN_MASK_STEREO;
zsc_mix_cfg.volume_range.min = 0;
zsc_mix_cfg.volume_range.max = 0xFF;
zsc_mix_cfg.volume_range.min_dB = -10235;
zsc_mix_cfg.volume_range.max_dB = 0;
zsc_mix_cfg.volume_set = zone_subchn_volume_set;
zsc_mix_cfg.mute_set = zone_subchn_mute_set;
if (((*zsc)->scmix =
ado_pcm_subchn_mixer_create (subchn,
zone->mixer,
&zsc_mix_cfg)) == NULL)
{

ado_mutex_unlock (&zone->hw_lock);
return (ENOMEM);
}

ado_mutex_unlock (&zone->hw_lock);
return (EOK);
}




Also, template driver suggests to use ado_mutex_lock in the interrupt
handler, but ado_mutex_lock is wrapper for pthread_mutex_lock which is
nointerrupt-safe. I tried and easily got myself a MUTEX deadlock between
2 threads of io-audio.I guess I should use InterruprLock, right?

Yes, if the template used a real ISR directly then you would need to use
InterruptLock/Unlock().

It does not use a real ISR.
ado_attach_interrupt() uses InterruptAttachEvent(), not InterruptAttach().
template_interrupt() is run in a standard thread, not an ISR. So the
interrupt-safety rules do not apply.

Do a pidin while running a driver and you can see the thread waiting on
interrupts. It has a STATE of INTR. Which means it has called
InterruptWait() and not received an interrupt signal yet.


If you want us to take a peek at your code and offer suggestions, let
use know.

Audio Support wrote:

Here is a short section of code demonstrating how to setup a subchannel
mixer. It is for a fictional card called “Zone” (name changed to protect
the guilty > :slight_smile:> . Note that the volume and mute functions have the same
prototype. That is by design. You can have a single function, or two
as demonstrated here.

[snip]

memset (&zsc_mix_cfg, 0, sizeof (zsc_mix_cfg));
zsc_mix_cfg.hw_context = zone;
zsc_mix_cfg.pcm_sc_context = *zsc;
zsc_mix_cfg.channel_mask = SND_MIXER_CHN_MASK_STEREO;
zsc_mix_cfg.volume_range.min = 0;
zsc_mix_cfg.volume_range.max = 0xFF;
zsc_mix_cfg.volume_range.min_dB = -10235;
zsc_mix_cfg.volume_range.max_dB = 0;
zsc_mix_cfg.volume_set = zone_subchn_volume_set;
zsc_mix_cfg.mute_set = zone_subchn_mute_set;
if (((*zsc)->scmix =
ado_pcm_subchn_mixer_create (subchn,
zone->mixer,
&zsc_mix_cfg)) == NULL)

I tried doing just that (with NULL for volume/mute funcs) and what I got
was odd behavior of volume controls. Changing volume in phplay has no
effect and does not lead to changes in volume controls of mixer. I still
could control volume from mixer app. Decreasing volume in the mixer app
leads to volume control in phplay jumping to 0, but increasing is back
(in mixer) does not affect volume control in phplay.

Without subchn_mixer_create() call volume control in phplay just
corresponds directly to PCM control in mixer.

What is magic number -10235? Also, my mixer seems to ignore any volume
setting outside of 0…31 range, but changing volume_range_max to 31 did
not help either.

Maestro does not really have notion of ‘subchannel’, but it has 64
devices called ‘APU’ which are allocated as needed and may be programmed
into one of modes (such as SRC, mixer, etc). ALSA code allocates 4 APUs
per capture channel and 2 per playback. I don’t see anything in ALSA
which would be an equivalent for ‘subchannel mixer volume set’ function
and just trying to guess how that should be implemented. Even the specs
page mentioned in the code is not available on ESS site anymore :wink:

Yes, if the template used a real ISR directly then you would need to use
InterruptLock/Unlock().

It does not use a real ISR.
ado_attach_interrupt() uses InterruptAttachEvent(), not InterruptAttach().
template_interrupt() is run in a standard thread, not an ISR. So the
interrupt-safety rules do not apply.

Do a pidin while running a driver and you can see the thread waiting on
interrupts. It has a STATE of INTR. Which means it has called
InterruptWait() and not received an interrupt signal yet.

In fact what I saw was thread 2 (normally in INTR state) blocked on
mutex held by thread 7 and thread 7 locked on mutex held by thread 2.
And yes I used the ado_attach_interrupt() call.

That situation seems to happen when I try to stop playing something,
which leads to trigger() call being invoked while interrupts are still
coming. If I change the code to use InterruptLock() between trigger and
interrupr handler the problem goes away.

This does not sound right. Perhaps interrupts need to be disabled while
holding lock? ALSA code uses spin_lock_irqsave() in the trigger()
func…

If you want us to take a peek at your code and offer suggestions, let
use know.

I surely will, as soon as I finish grooming it up. Another problem I
have is odd behavior of video player. When I play MP3 songs they sound
fine, but if that is MP3 clip everything seems to be going too fast.
Sound however does not sound like on ‘fast forward’ it rather sounds
like some frames are being skipped to keep pace with too fast video,
with monotonic ‘chopping’ sound. I’m not sure if that is audio problem,
perhaps it has something to do with SVGA driver? CPU utilisation is also
nearly 100% playing video…

Thanks,

  • Igor

Igor Kovalenko <Igor.Kovalenko@motorola.com> wrote:

Audio Support wrote:

Here is a short section of code demonstrating how to setup a subchannel
mixer. It is for a fictional card called “Zone” (name changed to protect
the guilty > :slight_smile:> . Note that the volume and mute functions have the same
prototype. That is by design. You can have a single function, or two
as demonstrated here.

[snip]

memset (&zsc_mix_cfg, 0, sizeof (zsc_mix_cfg));
zsc_mix_cfg.hw_context = zone;
zsc_mix_cfg.pcm_sc_context = *zsc;
zsc_mix_cfg.channel_mask = SND_MIXER_CHN_MASK_STEREO;
zsc_mix_cfg.volume_range.min = 0;
zsc_mix_cfg.volume_range.max = 0xFF;
zsc_mix_cfg.volume_range.min_dB = -10235;
zsc_mix_cfg.volume_range.max_dB = 0;
zsc_mix_cfg.volume_set = zone_subchn_volume_set;
zsc_mix_cfg.mute_set = zone_subchn_mute_set;
if (((*zsc)->scmix =
ado_pcm_subchn_mixer_create (subchn,
zone->mixer,
&zsc_mix_cfg)) == NULL)

I tried doing just that (with NULL for volume/mute funcs) and what I got
was odd behavior of volume controls. Changing volume in phplay has no
effect and does not lead to changes in volume controls of mixer. I still
could control volume from mixer app. Decreasing volume in the mixer app
leads to volume control in phplay jumping to 0, but increasing is back
(in mixer) does not affect volume control in phplay.

Completely correct. If you put NULL in for both the volume and mute
functions, effectively you have created a “placeholder” group. The
subchannel mixer group would only hold static information about the
group, but has no effect on actual hardware. This is hardly useful.
I would recommend not calling ado_pcm_subchn_mixer_create at all, if
you are not supporting mixer controls at the subchannel level.

Without subchn_mixer_create() call volume control in phplay just
corresponds directly to PCM control in mixer.

Yes, that is correct.

What is magic number -10235? Also, my mixer seems to ignore any volume
setting outside of 0…31 range, but changing volume_range_max to 31 did
not help either.

No magic. All four volume ranges are based on information gleaned from
the documentation of a card. This example volume control will accept
settings from 0 (-10235 dB) to 0xff (0 dB).

Maestro does not really have notion of ‘subchannel’, but it has 64
devices called ‘APU’ which are allocated as needed and may be programmed
into one of modes (such as SRC, mixer, etc). ALSA code allocates 4 APUs
per capture channel and 2 per playback. I don’t see anything in ALSA
which would be an equivalent for ‘subchannel mixer volume set’ function
and just trying to guess how that should be implemented. Even the specs
page mentioned in the code is not available on ESS site anymore > :wink:

A ‘subchannel’ is a synthetic concept on almost all cards. It is simply
the collection of ‘stuff’ that all relates to one stream of audio data
at runtime. How it is synthesized from available resources is hardware-
dependent. It is entirely possible that you may not be able to synthesize
a subchannel mixer from the infomation that ALSA is giving you. Regardless,
you will have to understand the hows and whys of 'APU’s to decide that.

I surely will, as soon as I finish grooming it up. Another problem I
have is odd behavior of video player. When I play MP3 songs they sound
fine, but if that is MP3 clip everything seems to be going too fast.
Sound however does not sound like on ‘fast forward’ it rather sounds
like some frames are being skipped to keep pace with too fast video,
with monotonic ‘chopping’ sound. I’m not sure if that is audio problem,
perhaps it has something to do with SVGA driver? CPU utilisation is also
nearly 100% playing video…

Your position function is probably wrong (or not implemented yet :slight_smile:
Which app are you using for testing?

“Audio Support” <audio_support@qnx.com> wrote in message
news:9leer0$jrm$1@nntp.qnx.com

Another problem I
have is odd behavior of video player. When I play MP3 songs they sound
fine, but if that is MP3 clip everything seems to be going too fast.
Sound however does not sound like on ‘fast forward’ it rather sounds
like some frames are being skipped to keep pace with too fast video,
with monotonic ‘chopping’ sound. I’m not sure if that is audio problem,
perhaps it has something to do with SVGA driver? CPU utilisation is also
nearly 100% playing video…

Your position function is probably wrong (or not implemented yet > :slight_smile:
Which app are you using for testing?

I am using phplay on a different MPEG video clips and MP3 songs. All songs
are played fine, as well as WAV files. But all MPEG videos have that
problem. If I had incorrect position function would not that affect
everything, not just MPEG videos? I’ve heard suggestions that I could be
overloading CPU when playing video on SVGA driver.

  • Igor

“Igor Kovalenko” <kovalenko@home.com> wrote in message
news:9leh9s$l3f$1@inn.qnx.com

“Audio Support” <> audio_support@qnx.com> > wrote in message
news:9leer0$jrm$> 1@nntp.qnx.com> …
Another problem I
have is odd behavior of video player. When I play MP3 songs they sound
fine, but if that is MP3 clip everything seems to be going too fast.
Sound however does not sound like on ‘fast forward’ it rather sounds
like some frames are being skipped to keep pace with too fast video,
with monotonic ‘chopping’ sound. I’m not sure if that is audio
problem,
perhaps it has something to do with SVGA driver? CPU utilisation is
also
nearly 100% playing video…

Your position function is probably wrong (or not implemented yet > :slight_smile:
Which app are you using for testing?

I am using phplay on a different MPEG video clips and MP3 songs. All songs
are played fine, as well as WAV files. But all MPEG videos have that
problem. If I had incorrect position function would not that affect
everything, not just MPEG videos? I’ve heard suggestions that I could be
overloading CPU when playing video on SVGA driver.

I just tried RealPlayer and it looks like it plays RM version of QNX
corporate video much better than phplay plays MPEG version. Sound is just
fine, although CPU utilisation is solid 100% and I also was transferring big
file over network in background…

  • Igor

“Audio Support” <audio_support@qnx.com> wrote in message
news:9leer0$jrm$1@nntp.qnx.com

Completely correct. If you put NULL in for both the volume and mute
functions, effectively you have created a “placeholder” group. The
subchannel mixer group would only hold static information about the
group, but has no effect on actual hardware. This is hardly useful.
I would recommend not calling ado_pcm_subchn_mixer_create at all, if
you are not supporting mixer controls at the subchannel level.

Is there any point in allowing multiple acquires if I do not support mixer
controls at subchannel level?
Support for hardware subchannels is quite expensive in terms of code
complexity, DMA memory management and locking/searching overhead.

I could just use your ‘software subchannels’ and make driver much simpler
but that would only work for playback and at expense of CPU usage. How big
is that expense? And does anyone actually need multiple capture subchannels?
What are advantages they provide?

  • igor