Nemo/Audio

= Audio in Nemo =

This page tries to document all relevant information regarding audio handling in Nemo, what pieces are relevant for which purpose and why and list places for further documentation.

Relevant Components

 * ALSA
 * PulseAudio
 * Pulseaudio-modules-nemo
 * Pulseaudio-policy-enforcement module

Audio modes
Audio modes are in practice audio routings as well as mode specific role-volumes. Audio mode configuration is always adaptation specific, all modes are not necessarily present in every adaptation.

Examples of audio modes,
 * ihf (Internal Hands-Free, or the device loudspeaker)
 * lineout (Normal stereo-device connected to audio jacket, usually 3.5mm stereo jack)
 * hp (Head Phone, small loudspeaker in device used for call audio)
 * bta2dp (Bluetooth A2DP, wireless A2DP device)

Audio routing targets are configured using PulseAudio port-configurations, each routing target has its own port-configuration. When audio mode changes, alsa-sink's active port is changed for routing related to given mode. Port configurations are in device at /usr/share/pulseaudio/alsa-mixer/{paths,profiles}

stream-restore-nemo contains patches to enable role-volumes, or route-volumes, which means every audio mode has individual volume level stored. When audio mode changes stream-restore-nemo applies mode's stored volume values to streams. Stream-restore-nemo also exports volume-proxy interface to communicate volume changes with Mainvolume.

pulseaudio-policy-enforcement-module enforces routing changes and other relevant audio policy rules (enforcing volume limits, corking streams that are not allowed to play for example during call, etc.) to PulseAudio and policy-enforcement-module communicates with OHM.

Mainvolume
Nemo/Audio/MainVolume

The purpose of mainvolume-module in PulseAudio is to simplify volume control by providing single entrypoint to control role volumes. Volume controlling of streams should not normally be done by hand (few important exceptions exist). Mainvolume is controlled using DBus API.

How volume works

Volume levels are stored in stream-restore-nemo database. There are two kinds of volumes, "static" volumes, or the normal stream volumes, which stay the same regardless of the audio mode, and "role-volumes or route-volumes" which are stored for each individual mode.

For example, role-volumes can be thought as and so on. When volume for sink-input-by-media-role:x-maemo is queried, stream-restore-nemo only replies currently active role-volume. Applying role-specific volume to this entry is done behind the scenes when audio mode changes.
 * sink-input-by-media-role:x-maemo:ihf
 * sink-input-by-media-role:x-maemo:lineout
 * sink-input-by-media-role:x-maemo:earpiece

PA   |---| | stream-restore-nemo --|- Stream volume database, contains volumes for role-volumes as well as   |       |          |    |      "static" stream-volumes. | mainvolume  DBus API | |      |          ^    |    | DBus API         |    | |      ^          |    |    |---|--||            |          |            |        applications changing static volumes (eg ngfd) |   volume controlling application Mainvolume client -> Mainvolume -> Volume proxy -> Stream Restore Nemo

So, for example if ihf-route is selected, volume is set to -6dB, when user connects headset to device lineout-route is selected and its stored volume applied, and volume is for example at level -16dB.

Role-volumes are defined in /etc/pulse/x-maemo-route.table. Syntax is

  [minimum volume in dB]

for example:

sink-input-by-media-role:x-maemo -15 sink-input-by-media-role:phone -10 -20

Default volume is set to stream when entering mode that doesn't have any stream volume stored yet. If minimum volume is set and volume is below minimum volume level, next time route with that volume is entered default volume is applied instead. This is useful in phone call case to prevent audio volume to be inaudible if for some reason volume is set to really low value in previous call.

When mainvolume-module is used for volume controlling, it controls precisely these predefined route-volumes. When in-call, it controls media-role:phone stream volume, and otherwise media-role:x-maemo. Also mainvolume module has configurable steps for volume levels, for example if five steps are used for in-call case they could be -15dB, -10dB, -7dB, -5dB, -2dB, 0dB. Then mainvolume exposes 5 steps in call-mode.

module-meego-parameters handles mode specific preferences and passes Mainvolume step configuration to Mainvolume as well.

Few useful command line applications for volumes (mainvolume-volume.py mainvolume-monitor.py pasr.py)

Stream Restore Nemo (module-stream-restore-nemo)
DBus API is identical to upstream stream-restore: http://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/Developer/Clients/DBus/StreamRestore

stream-restore-nemo is upstream stream-restore module with patches to enable role-volumes and small proxy which is used by mainvolume to communicate to stream-restore-nemo. Stream volumes can be changed directly with stream-restore-nemo as well. If volumes are set for streams other than route-volume-streams, everything works fine as well, but the volumes are not updated according to audio mode.

ngfd communicates directly with stream-restore-nemo to update volumes for event sounds, ringtone volume, etc.

Stream creation with Nemo
http://freedesktop.org/software/pulseaudio/doxygen/streams.html

In normal use cases new streams should be created without volume or name defined so that module-match and module-stream-restore-nemo can match, classify and restore volume for newly created stream. Unnamed streams are defaulted to "x-maemo", default is defined in /etc/pulse/x-maemo-match.table

pa_stream *stream; stream = pa_pstream_new_with_proplist(context, NULL, &sample_spec, &channel_map, NULL); // Connect default stream pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL);

If volume is defined for new stream module-stream-restore-nemo doesn't change the value but the stream passes through untouched. Also name should be defined for the stream so that the new stream doesn't interfere with role streams. PulseAudio in Nemo runs in flat volume volume which means that volume passed to pa_stream_connect_playback is absolute volume. Thus if volume is wanted for a stream; (usually playback stream is either mono or stereo)

pa_stream *stream; pa_cvolume volume; double dB_volume = -5.0; pa_cvolume_set(&volume, sample_spec.channels, pa_sw_volume_from_dB(dB_volume)); // Create new stream with defined name stream = pa_stream_new_with_proplist(context, "my-stream", &&sample_spec, &channel_map, NULL); pa_stream_connect_playback(stream, NULL, NULL, 0, &volume, NULL);

Now in ideal world the device Nemo is running in has proper ALSA dB info and/or tuned volume levels and you will get playback with true absolute volume -5dB.

Life of a new stream in Nemo

 * 1) Stream is created with NULL device, NULL name and NULL volume
 * 2) Stream is connected to context
 * 3) New corresponding sink-input is created in server-side
 * 4) Default sink is set for new sink-input (sink.music)
 * 5) module-match renames unnamed stream to default name
 * 6) stream-restore-nemo classifies stream and applies current role volume for the stream
 * 7) Client starts to transfer data to stream