Advanced Linux Sound Architecture - Driver: Mixer

Next Previous Contents

## 4. Mixer

Mixer related structures and function is in include/mixer.h header file.

## 4.1 Variables and functions

Variables from snd_kmixer_t structure which must be filled:

- name is name of mixer (for example 'AD1848').
- hw read-only variables dependend on hardware.

Variables from snd_kmixer_t structure which should be filled:

- private_data pointer to private data for mixer.
- private_free should free private_data when called.

Variables from struct snd_stru_mixer_hw structure which must be filled:

- caps mixer capabilities (see to SND_SND_MIXER_INFO_CAP_*).

Variables from struct snd_stru_mixer_hw structure which should be filled:

- get_special
- set_special

Variables from snd_kmixer_channel_t structure which must be filled:

- hw read-only variables dependend on hardware.

Variables from snd_kmixer_channel_t structure which should be filled:

- private_value is unsigned int variable which isn't used by middle-level code.
- private_data is pointer to some private data associated with appropriate channel. This data isn't freed by middle-level code. NOTE - Where should it be freed from then?

Variables from struct snd_stru_mixer_channel_hw structure which must be filled:

- priority priority (identificator) - see SND_MIXER_PRI_*
- parent_priority parent mixer channel priority or SND_MIXER_PRI_PARENT
- name name of this mixer channel - see SND_MIXER_ID_*
- ossdev OSS (Open Sound System) device - see SND_MIXER_OSS_*
- mute if hardware mute is supported
- stereo if stereo is supported
- record is recording is possible from this channel
- digital is this channel is digitaly (not analog) mixed
- input is channel is input channel
- min, max specifies exact linear range from min to max
- min_dB, max_dB, step_dB range and step size for decibel * 100
- void (*set_record_source)( snd_kmixer_t *mixer, snd_kmixer_channel_t *channel, int enable )
  - mixer pointer to mixer structure
  - channel pointer to channel structure
  - enable if non-zero - record source must be enabled
  - must be set, if channel supports recording
- void (*set_mute)( snd_kmixer_t *mixer, snd_kmixer_channel_t *channel, unsigned int mute )
  - mixer pointer to mixer structure
  - channel pointer to channel structure
  - mute should be zero (no mute) or SND_MIX_MUTE*
  - must be set, if channel supports hardware muting
- void (*set_volume_level)( snd_kmixer_t *mixer, snd_kmixer_channel_t *channel, int left, int right )
  - mixer pointer to mixer structure
  - channel pointer to channel structure
  - left volume level in exact range
  - right volume level in exact range
  - handler which sets volume level for this channel

Variables from struct snd_stru_mixer_channel_hw structure which should be filled:

- int (*compute_linear)( snd_kmixer_t *mixer, snd_kmixer_channel_t *channel, int dB )
  - input = dB from application, output = min...max (linear volume)
- int (*compute_dB)( snd_kmixer_t *mixer, snd_kmixer_channel_t *channel, int volume )
  - input = min...max (linear volume), output = dB to application

Functions list:

- void snd_mixer_set_kernel_mute( snd_kmixer_t *mixer, unsigned int priority, unsigned short mute )
  - mixer pointer to mixer structure
  - priority specifies mixer channel
  - mute zero or SND_MIX_MUTE*
  - should be use as mute control from kernel
  - this settings are never overriden by application
- snd_kmixer_t *snd_mixer_new( snd_card_t *card, char *id )
  - card pointer to soundcard structure
  - id is identification of code (for example 'AD1848').
- int snd_mixer_free( snd_kmixer_t *mixer )
  - mixer pointer to mixer structure
  - frees mixer structure and private data
- snd_kmixer_channel_t *snd_mixer_new_channel( snd_kmixer_t *mixer, struct snd_stru_mixer_channel_hw *hw )
  - mixer pointer to mixer structure
  - hw pointer to mixer channel variables and operations
  - creates new mixer channel
- void snd_mixer_reorder_channel( snd_kmixer_t *mixer, snd_kmixer_channel_t *channel )
  - mixer pointer to mixer structure
  - channel pointer to mixer channel
  - reorders mixer channels if channel -> priority was changed
- int snd_mixer_register( snd_kmixer_t *mixer, int device )
  - mixer pointer to mixer structure
  - device device number (0-1)
  - registers specified mixer
- int snd_mixer_unregister( snd_mixer_t *mixer )
  - mixer pointer to mixer structure
  - unregisters and frees specified mixer

## 4.2 Exaples

> `

>     #define CS4231_MIXS (sizeof(snd_cs4231_mixs)/sizeof(struct snd_stru_mixer_channel_hw))
>     #define CS4231_PRIVATE( left, right, shift, mute ) ((left << 24)|(right << 16)|(shift<<8)|mute)

>     static struct snd_stru_mixer_channel_hw snd_cs4231_mixs[] = {
>       {
>         SND_MIXER_PRI_GAIN,         /* priority */
>         SND_MIXER_PRI_PARENT,       /* parent priority */
>         SND_MIXER_ID_GAIN,          /* device name */
>         SND_MIXER_OSS_IMIX,         /* OSS device # */
>         0, 1, 0, 0, 1,              /* mute/stereo/record/digital/input */
>         0, 15,                      /* min, max value */
>         0, 2250, 150,               /* min, max, step - dB */
>         CS4231_PRIVATE( CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0x00 ) | 0x2000,
>         NULL,                       /* compute dB -> linear */
>         NULL,                       /* compute linear -> dB */
>         NULL,                       /* record source */
>         NULL,                       /* set mute */
>         snd_cs4231_volume_level,    /* set volume level */
>       },
>       ....
>     };

>     snd_kmixer_t *snd_cs4231_new_mixer( snd_pcm_t *pcm )
>     {
>       int idx;
>       cs4231_t *codec;
>       snd_kmixer_t *mixer;
>       snd_kmixer_channel_t *channel;

>       if ( !pcm || !pcm -> card ) return NULL;
>       codec = (cs4231_t *)pcm -> private_data;
>       if ( !codec ) return NULL;
>       mixer = snd_mixer_new( pcm -> card, pcm -> id );
>       if ( !mixer ) return NULL;
>       strcpy( mixer -> name, pcm -> name );
>       for ( idx = 0; idx < CS4231_MIXS; idx++ ) {
>         channel = snd_mixer_new_channel( mixer, &snd_cs4231_mixs[ idx ] );
>         if ( !channel ) {
>           snd_mixer_free( mixer );
>           return NULL;
>         }
>       }
>       mixer -> hw.caps = SND_MIXER_INFO_CAP_EXCL_RECORD;
>       mixer -> private_data = codec;
>       codec -> mixer = mixer;
>       return mixer;
>     }

> `

Do you need modify some default mixer channel assignment?

> `

>       snd_kmixer_channel_t *channel;

>       /* ok. InterWave have MIC different (stereo) */
>       channel = snd_mixer_find_channel( mixer, SND_MIXER_PRI_MIC );
>       channel -> hw.stereo = 1;
>       channel -> hw.max = 31;
>       channel -> hw.private_value = CS4231_PRIVATE( CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0x80 );

>       /* reassign AUXA to SYNTHESIZER */
>       channel = snd_mixer_find_channel( mixer, SND_MIXER_PRI_AUXA );
>       channel -> hw.priority = SND_MIXER_PRI_SYNTHESIZER;
>       channel -> hw.ossdev = SND_MIXER_OSS_SYNTH;
>       strcpy( channel -> hw.name, SND_MIXER_ID_SYNTHESIZER );
>       snd_mixer_reorder_channel( mixer, channel );

> `

Do you need add some mixer channel to generic mixer?

> `

>       static struct snd_stru_mixer_channel_hw master = {
>         SND_MIXER_PRI_MASTER,               /* priority */
>         SND_MIXER_PRI_PARENT,               /* parent priority */
>         SND_MIXER_ID_MASTER,                /* device name */
>         SND_MIXER_OSS_VOLUME,               /* OSS device # */
>         1, 1, 1, 0, 0,                      /* mute/stereo/record/digital */
>         0, 31,                              /* max. value */
>         -3450, 1200, 150,                   /* min, max, step - dB */
>         CS4231_PRIVATE( CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0x80
>         NULL,                               /* compute dB -> linear */
>         NULL,                               /* compute linear -> dB */
>         NULL,                               /* record source */
>         NULL,                               /* set mute */
>         NULL,                               /* set volume level */
>       };
>       int idx;

>       /* make master as parent */
>       for ( idx = 0; idx < mixer -> channels_count; idx++ ) {
>         channel = mixer -> channels[ idx ];
>         if ( !channel -> hw.input )
>           channel -> hw.parent_priority = SND_MIXER_PRI_MASTER;
>       }
>       /* add master volume control */
>       master.set_record_source = channel -> hw.set_record_source;
>       master.set_mute = channel -> hw.set_mute;
>       master.set_volume_level = channel -> hw.set_volume_level;
>       channel = snd_mixer_new_channel( mixer, &master );
>       if ( !channel ) return -ENOMEM;

> `

Mixer device registering:

> `

>       snd_card_t *card;
>       snd_pcm_t *pcm.
>       snd_kmixer_t *mixer;

>       ...
>       mixer = snd_es1688_new_mixer( pcm );
>       if ( !mixer ) {
>         snd_pcm_free( pcm );
>         snd_card_free( card );
>         return -NXIO;
>       }
>       ...
>       if ( snd_mixer_register( mixer, 0 ) ) {
>         ... unregister already registered devices ...
>         snd_mixer_free( mixer );
>         snd_pcm_free( pcm );
>         snd_card_free( card );
>         return -ENXIO;
>       }
>       ...
>       snd_mixer_unregister( mixer );

> `

Next Previous Contents