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
.