Playing status of audio source is checked using the native handler not 0. However, if AudioSystem#startAudioSource fails, the native handler returned is not 0, but an error code. In fact AudioPolicyManager sets the PORT to NONE (0) and sets an error status. JNI layer transforms the failure status into a native handler returned to the caller. Signed-off-by: Francois Gaffie <francois.gaffie@renault.com> Change-Id: Iaa920c073885c2556a93a1b5ae23467fa6ffad4f Merged-In: Iaa920c073885c2556a93a1b5ae23467fa6ffad4f
267 lines
9.3 KiB
Java
267 lines
9.3 KiB
Java
/*
|
|
* Copyright (C) 2019 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.media;
|
|
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.annotation.SystemApi;
|
|
|
|
import com.android.internal.util.Preconditions;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
/**
|
|
* The HwAudioSource represents the audio playback directly from a source audio device.
|
|
* It currently supports {@link HwAudioSource#start()} and {@link HwAudioSource#stop()} only
|
|
* corresponding to {@link AudioSystem#startAudioSource(AudioPortConfig, AudioAttributes)}
|
|
* and {@link AudioSystem#stopAudioSource(int)}.
|
|
*
|
|
* @hide
|
|
*/
|
|
@SystemApi
|
|
public class HwAudioSource extends PlayerBase {
|
|
private final AudioDeviceInfo mAudioDeviceInfo;
|
|
private final AudioAttributes mAudioAttributes;
|
|
|
|
/**
|
|
* The value of the native handle encodes the HwAudioSource state.
|
|
* The native handle returned by {@link AudioSystem#startAudioSource} is either valid
|
|
* (aka > 0, so successfully started) or hosting an error code (negative).
|
|
* 0 corresponds to an untialized or stopped HwAudioSource.
|
|
*/
|
|
private int mNativeHandle = 0;
|
|
|
|
/**
|
|
* Class constructor for a hardware audio source based player.
|
|
*
|
|
* Use the {@link Builder} class to construct a {@link HwAudioSource} instance.
|
|
*
|
|
* @param device {@link AudioDeviceInfo} instance of the source audio device.
|
|
* @param attributes {@link AudioAttributes} instance for this player.
|
|
*/
|
|
private HwAudioSource(@NonNull AudioDeviceInfo device, @NonNull AudioAttributes attributes) {
|
|
super(attributes, AudioPlaybackConfiguration.PLAYER_TYPE_HW_SOURCE);
|
|
Preconditions.checkNotNull(device);
|
|
Preconditions.checkNotNull(attributes);
|
|
Preconditions.checkArgument(device.isSource(), "Requires a source device");
|
|
mAudioDeviceInfo = device;
|
|
mAudioAttributes = attributes;
|
|
baseRegisterPlayer(AudioSystem.AUDIO_SESSION_ALLOCATE);
|
|
}
|
|
|
|
/**
|
|
* TODO: sets the gain on {@link #mAudioDeviceInfo}.
|
|
*
|
|
* @param muting if true, the player is to be muted, and the volume values can be ignored
|
|
* @param leftVolume the left volume to use if muting is false
|
|
* @param rightVolume the right volume to use if muting is false
|
|
*/
|
|
@Override
|
|
void playerSetVolume(boolean muting, float leftVolume, float rightVolume) {
|
|
}
|
|
|
|
/**
|
|
* TODO: applies {@link VolumeShaper} on {@link #mAudioDeviceInfo}.
|
|
*
|
|
* @param configuration a {@code VolumeShaper.Configuration} object
|
|
* created by {@link VolumeShaper.Configuration.Builder} or
|
|
* an created from a {@code VolumeShaper} id
|
|
* by the {@link VolumeShaper.Configuration} constructor.
|
|
* @param operation a {@code VolumeShaper.Operation}.
|
|
* @return
|
|
*/
|
|
@Override
|
|
int playerApplyVolumeShaper(
|
|
@NonNull VolumeShaper.Configuration configuration,
|
|
@NonNull VolumeShaper.Operation operation) {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* TODO: gets the {@link VolumeShaper} by a given id.
|
|
*
|
|
* @param id the {@code VolumeShaper} id returned from
|
|
* sending a fully specified {@code VolumeShaper.Configuration}
|
|
* through {@link #playerApplyVolumeShaper}
|
|
* @return
|
|
*/
|
|
@Override
|
|
@Nullable
|
|
VolumeShaper.State playerGetVolumeShaperState(int id) {
|
|
return new VolumeShaper.State(1f, 1f);
|
|
}
|
|
|
|
/**
|
|
* TODO: sets the level on {@link #mAudioDeviceInfo}.
|
|
*
|
|
* @param muting
|
|
* @param level
|
|
* @return
|
|
*/
|
|
@Override
|
|
int playerSetAuxEffectSendLevel(boolean muting, float level) {
|
|
return AudioSystem.SUCCESS;
|
|
}
|
|
|
|
@Override
|
|
void playerStart() {
|
|
start();
|
|
}
|
|
|
|
@Override
|
|
void playerPause() {
|
|
// Pause is equivalent to stop for hardware audio source based players.
|
|
stop();
|
|
}
|
|
|
|
@Override
|
|
void playerStop() {
|
|
stop();
|
|
}
|
|
|
|
/**
|
|
* Starts the playback from {@link AudioDeviceInfo}.
|
|
* Starts does not return any error code, caller must check {@link HwAudioSource#isPlaying} to
|
|
* ensure the state of the HwAudioSource encoded in {@link mNativeHandle}.
|
|
*/
|
|
public void start() {
|
|
Preconditions.checkState(!isPlaying(), "HwAudioSource is currently playing");
|
|
mNativeHandle = AudioSystem.startAudioSource(
|
|
mAudioDeviceInfo.getPort().activeConfig(),
|
|
mAudioAttributes);
|
|
if (isPlaying()) {
|
|
// FIXME: b/174876389 clean up device id reporting
|
|
baseStart(getDeviceId());
|
|
}
|
|
}
|
|
|
|
private int getDeviceId() {
|
|
ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
|
|
if (AudioManager.listAudioPatches(patches) != AudioManager.SUCCESS) {
|
|
return 0;
|
|
}
|
|
|
|
for (int i = 0; i < patches.size(); i++) {
|
|
AudioPatch patch = patches.get(i);
|
|
AudioPortConfig[] sources = patch.sources();
|
|
AudioPortConfig[] sinks = patch.sinks();
|
|
if ((sources != null) && (sources.length > 0)) {
|
|
for (int c = 0; c < sources.length; c++) {
|
|
if (sources[c].port().id() == mAudioDeviceInfo.getId()) {
|
|
return sinks[c].port().id();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Checks whether the HwAudioSource player is playing.
|
|
* It checks the state of the HwAudioSource encoded in {@link HwAudioSource#isPlaying}.
|
|
* 0 corresponds to a stopped or uninitialized HwAudioSource.
|
|
* Negative value corresponds to a status reported by {@link AudioSystem#startAudioSource} to
|
|
* indicate a failure when trying to start the HwAudioSource.
|
|
*
|
|
* @return true if currently playing, false otherwise
|
|
*/
|
|
public boolean isPlaying() {
|
|
return mNativeHandle > 0;
|
|
}
|
|
|
|
/**
|
|
* Stops the playback from {@link AudioDeviceInfo}.
|
|
*/
|
|
public void stop() {
|
|
if (mNativeHandle > 0) {
|
|
baseStop();
|
|
AudioSystem.stopAudioSource(mNativeHandle);
|
|
mNativeHandle = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Builder class for {@link HwAudioSource} objects.
|
|
* Use this class to configure and create a <code>HwAudioSource</code> instance.
|
|
* <p>Here is an example where <code>Builder</code> is used to specify an audio
|
|
* playback directly from a source device as media usage, to be used by a new
|
|
* <code>HwAudioSource</code> instance:
|
|
*
|
|
* <pre class="prettyprint">
|
|
* HwAudioSource player = new HwAudioSource.Builder()
|
|
* .setAudioAttributes(new AudioAttributes.Builder()
|
|
* .setUsage(AudioAttributes.USAGE_MEDIA)
|
|
* .build())
|
|
* .setAudioDeviceInfo(device)
|
|
* .build()
|
|
* </pre>
|
|
* <p>
|
|
* If the audio attributes are not set with {@link #setAudioAttributes(AudioAttributes)},
|
|
* attributes comprising {@link AudioAttributes#USAGE_MEDIA} will be used.
|
|
*/
|
|
public static final class Builder {
|
|
private AudioAttributes mAudioAttributes;
|
|
private AudioDeviceInfo mAudioDeviceInfo;
|
|
|
|
/**
|
|
* Constructs a new Builder with default values.
|
|
*/
|
|
public Builder() {
|
|
}
|
|
|
|
/**
|
|
* Sets the {@link AudioAttributes}.
|
|
* @param attributes a non-null {@link AudioAttributes} instance that describes the audio
|
|
* data to be played.
|
|
* @return the same Builder instance.
|
|
*/
|
|
public @NonNull Builder setAudioAttributes(@NonNull AudioAttributes attributes) {
|
|
Preconditions.checkNotNull(attributes);
|
|
mAudioAttributes = attributes;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the {@link AudioDeviceInfo}.
|
|
* @param info a non-null {@link AudioDeviceInfo} instance that describes the audio
|
|
* data come from.
|
|
* @return the same Builder instance.
|
|
*/
|
|
public @NonNull Builder setAudioDeviceInfo(@NonNull AudioDeviceInfo info) {
|
|
Preconditions.checkNotNull(info);
|
|
Preconditions.checkArgument(info.isSource());
|
|
mAudioDeviceInfo = info;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Builds an {@link HwAudioSource} instance initialized with all the parameters set
|
|
* on this <code>Builder</code>.
|
|
* @return a new successfully initialized {@link HwAudioSource} instance.
|
|
*/
|
|
public @NonNull HwAudioSource build() {
|
|
Preconditions.checkNotNull(mAudioDeviceInfo);
|
|
if (mAudioAttributes == null) {
|
|
mAudioAttributes = new AudioAttributes.Builder()
|
|
.setUsage(AudioAttributes.USAGE_MEDIA)
|
|
.build();
|
|
}
|
|
return new HwAudioSource(mAudioDeviceInfo, mAudioAttributes);
|
|
}
|
|
}
|
|
}
|