Alternatives to Creating a Player

This article describes alternatives to creating a player.

HwAudioSource player

HwAudioSource connects the audio source device directly to an Android mixer.

Several limitations may arise when using a device-to-device or hardware audio patch with Android. These are unable to receive media key events such as PLAY, PAUSE, and STOP and, because they circumvent Android's audio stack, they require hardware to mix the patch into other audio from Android.

Using HwAudioSource

HwAudioSource is a new type of player designed as a software patch. This enables applications that use this player to receive media key events and the output stream to be mixed and routed by Android.

mHwAudioSource = new HwAudioSource.Builder()
                .setAudioDeviceInfo(AudioDeviceInfo: info)
                .setAudioAttributes(new AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_MEDIA)
                        .build())
                .build();
mHwAudioSource.play();
mHwAudioSource.stop();

Changes to the audio HAL

With this new player, there are a couple of expectations for the audio HAL (for example, device/generic/car/emulator/audio/driver/audio_hw.c):

  • adev_create_audio_patch expects the request to establish an audio patch from a device to a mixer. This does not require anything special.
  • Adev_open_input_stream expects the audio_source to be AUDIO_SOURCE_FM_TUNER
  • In_read fill the audio buffer with actual broadcast radio audio data

It is recommended to configure a tuner device with type AUDIO_DEVICE_IN_FM_TUNER in audio_policy_configuration.xml:

<devicePort
    tagName="Tuner_source"
    type="AUDIO_DEVICE_IN_FM_TUNER"
    role="source"
    address="tuner0">
    <profile
        name=""
        format="AUDIO_FORMAT_PCM_16_BIT"
        samplingRates="48000"
        channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
</devicePort>

With this device configuration, finding the FM radio input device can be facilitated by using the AudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS) in conjunction with AudioDeviceInfo.TYPE_FM_TUNER.

Creating audio patches

You can create an audio patch between two audio ports, either a mix port or a device port. Typically, an audio patch from mix port to device port is for playback while the reverse direction is for capture.

For example, an audio patch that routes audio samples from FM_TUNER source directly to the media sink bypasses the software mixer. You must then use a hardware mixer to mix the audio samples from Android and FM_TUNER for the sink. When creating an audio patch directly from FM_TUNER source to the media sink:

  • Volume control applies to the media sink and should affect both the Android and FM_TUNER audio.
  • Users should be able to switch between Android and FM_TUNER audio through a simple app switch (no explicit media source choice should be necessary).

Automotive implementations might also need to create an audio patch between two device ports. To do so, you must first declare the device ports and possible routes in audio_policy_configuration.xml and associate mixports with these device ports.

Sample configuration

See also device/generic/car/emulator/audio/audio_policy_configuration.xml.

<audioPolicyConfiguration>
    <modules>
        <module name="primary" halVersion="3.0">
            <attachedDevices>
                <item>bus0_media_out</item>
                <item>bus1_audio_patch_test_in</item>
            </attachedDevices>
            <mixPorts>
                <mixPort name="mixport_bus0_media_out" role="source"
                        flags="AUDIO_OUTPUT_FLAG_PRIMARY">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000"
                            channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
                <mixPort name="mixport_audio_patch_in" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                           samplingRates="48000"
                           channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
                </mixPort>
            </mixPorts>
            <devicePorts>
                <devicePort tagName="bus0_media_out" role="sink" type="AUDIO_DEVICE_OUT_BUS"
                        address="bus0_media_out">
                    <profile balance="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                    <gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="-8400" maxValueMB="4000" defaultValueMB="0" stepValueMB="100"/>
                    </gains>
                </devicePort>
                <devicePort tagName="bus1_audio_patch_test_in" type="AUDIO_DEVICE_IN_BUS" role="source"
                        address="bus1_audio_patch_test_in">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
                    <gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="-8400" maxValueMB="4000" defaultValueMB="0" stepValueMB="100"/>
                    </gains>
                </devicePort>
            </devicePorts>
            <routes>
                <route type="mix" sink="bus0_media_out" sources="mixport_bus0_media_out,bus1_audio_patch_test_in"/>
                <route type="mix" sink="mixport_audio_patch_in" sources="bus1_audio_patch_test_in"/>
            </routes>
        </module>
    </modules>
</audioPolicyConfiguration>

Audio driver API

You can use getExternalSources() to retrieve a list of available sources (identified by address), then create audio patches between these sources and the sink ports by audio usages. The corresponding entry points on the Audio HAL appear in IDevice.hal:

Interface IDevice {
...
/
* Creates an audio patch between several source and sink ports.  The handle
* is allocated by the HAL and must be unique for this audio HAL module.
*
* @param sources patch sources.
* @param sinks patch sinks.
* @return retval operation completion status.
* @return patch created patch handle.
*/
createAudioPatch(vec<AudioPortConfig> sources, vec<AudioPortConfig> sinks)
       generates (Result retval, AudioPatchHandle patch);

* Release an audio patch.
*
* @param patch patch handle.
* @return retval operation completion status.
*/
releaseAudioPatch(AudioPatchHandle patch) generates (Result retval);
...
}

Note: These API hooks have been available since AUDIO_DEVICE_API_VERSION_3_0. For details, see device/generic/car/emulator/audio/driver/audio_hw.c.