Add AudioRouting interface for MediaPlayer

Bug: 64038649
Test: Run cts in RoutingTest
      Switch output device when playing music/video with MediaPlayer

Change-Id: I5b5c288e6557199b0a6986785f9335a18a80ab89
gugelfrei
jiabin 7 years ago
parent ef9fc7792d
commit 156c6873a5

@ -216,19 +216,19 @@ AudioTrack::AudioTrack(
pid_t pid,
const audio_attributes_t* pAttributes,
bool doNotReconnect,
float maxRequiredSpeed)
float maxRequiredSpeed,
audio_port_handle_t selectedDeviceId)
: mStatus(NO_INIT),
mState(STATE_STOPPED),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
mPortId(AUDIO_PORT_HANDLE_NONE)
{
mStatus = set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed);
offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
}
AudioTrack::AudioTrack(
@ -310,7 +310,8 @@ status_t AudioTrack::set(
pid_t pid,
const audio_attributes_t* pAttributes,
bool doNotReconnect,
float maxRequiredSpeed)
float maxRequiredSpeed,
audio_port_handle_t selectedDeviceId)
{
ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
"flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
@ -318,6 +319,7 @@ status_t AudioTrack::set(
sessionId, transferType, uid, pid);
mThreadCanCallJava = threadCanCallJava;
mSelectedDeviceId = selectedDeviceId;
switch (transferType) {
case TRANSFER_DEFAULT:
@ -1221,6 +1223,7 @@ status_t AudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
mSelectedDeviceId = deviceId;
if (mStatus == NO_ERROR) {
android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
mProxy->interrupt();
}
}
return NO_ERROR;

@ -218,6 +218,8 @@ public:
* maxRequiredSpeed playback. Values less than 1.0f and greater than
* AUDIO_TIMESTRETCH_SPEED_MAX will be clamped. For non-PCM tracks
* and direct or offloaded tracks, this parameter is ignored.
* selectedDeviceId: Selected device id of the app which initially requested the AudioTrack
* to open with a specific device.
* threadCanCallJava: Not present in parameter list, and so is fixed at false.
*/
@ -237,7 +239,8 @@ public:
pid_t pid = -1,
const audio_attributes_t* pAttributes = NULL,
bool doNotReconnect = false,
float maxRequiredSpeed = 1.0f);
float maxRequiredSpeed = 1.0f,
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
/* Creates an audio track and registers it with AudioFlinger.
* With this constructor, the track is configured for static buffer mode.
@ -313,7 +316,8 @@ public:
pid_t pid = -1,
const audio_attributes_t* pAttributes = NULL,
bool doNotReconnect = false,
float maxRequiredSpeed = 1.0f);
float maxRequiredSpeed = 1.0f,
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
/* Result of constructing the AudioTrack. This must be checked for successful initialization
* before using any AudioTrack API (except for set()), because using

@ -78,6 +78,10 @@ enum {
// Modular DRM
PREPARE_DRM,
RELEASE_DRM,
// AudioRouting
SET_OUTPUT_DEVICE,
GET_ROUTED_DEVICE_ID,
ENABLE_AUDIO_DEVICE_CALLBACK,
};
// ModDrm helpers
@ -559,6 +563,59 @@ public:
return reply.readInt32();
}
status_t setOutputDevice(audio_port_handle_t deviceId)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
data.writeInt32(deviceId);
status_t status = remote()->transact(SET_OUTPUT_DEVICE, data, &reply);
if (status != OK) {
ALOGE("setOutputDevice: binder call failed: %d", status);
return status;
}
return reply.readInt32();
}
status_t getRoutedDeviceId(audio_port_handle_t* deviceId)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
status_t status = remote()->transact(GET_ROUTED_DEVICE_ID, data, &reply);
if (status != OK) {
ALOGE("getRoutedDeviceid: binder call failed: %d", status);
*deviceId = AUDIO_PORT_HANDLE_NONE;
return status;
}
status = reply.readInt32();
if (status != NO_ERROR) {
*deviceId = AUDIO_PORT_HANDLE_NONE;
} else {
*deviceId = reply.readInt32();
}
return status;
}
status_t enableAudioDeviceCallback(bool enabled)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
data.writeBool(enabled);
status_t status = remote()->transact(ENABLE_AUDIO_DEVICE_CALLBACK, data, &reply);
if (status != OK) {
ALOGE("enableAudioDeviceCallback: binder call failed: %d, %d", enabled, status);
return status;
}
return reply.readInt32();
}
};
IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@ -916,6 +973,41 @@ status_t BnMediaPlayer::onTransact(
reply->writeInt32(result);
return OK;
}
// AudioRouting
case SET_OUTPUT_DEVICE: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
int deviceId;
status_t status = data.readInt32(&deviceId);
if (status == NO_ERROR) {
reply->writeInt32(setOutputDevice(deviceId));
} else {
reply->writeInt32(BAD_VALUE);
}
return NO_ERROR;
}
case GET_ROUTED_DEVICE_ID: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
audio_port_handle_t deviceId;
status_t ret = getRoutedDeviceId(&deviceId);
reply->writeInt32(ret);
if (ret == NO_ERROR) {
reply->writeInt32(deviceId);
}
return NO_ERROR;
} break;
case ENABLE_AUDIO_DEVICE_CALLBACK: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
bool enabled;
status_t status = data.readBool(&enabled);
if (status == NO_ERROR) {
reply->writeInt32(enableAudioDeviceCallback(enabled));
} else {
reply->writeInt32(BAD_VALUE);
}
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}

@ -131,6 +131,11 @@ public:
virtual status_t getMetadata(bool update_only,
bool apply_filter,
Parcel *metadata) = 0;
// AudioRouting
virtual status_t setOutputDevice(audio_port_handle_t deviceId) = 0;
virtual status_t getRoutedDeviceId(audio_port_handle_t *deviceId) = 0;
virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
};
// ----------------------------------------------------------------------------

@ -57,6 +57,7 @@ enum media_event_type {
MEDIA_SUBTITLE_DATA = 201,
MEDIA_META_DATA = 202,
MEDIA_DRM_INFO = 210,
MEDIA_AUDIO_ROUTING_CHANGED = 10000,
};
// Generic error codes for the media player framework. Errors are fatal, the
@ -275,6 +276,10 @@ public:
// Modular DRM
status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
status_t releaseDrm();
// AudioRouting
status_t setOutputDevice(audio_port_handle_t deviceId);
audio_port_handle_t getRoutedDeviceId();
status_t enableAudioDeviceCallback(bool enabled);
private:
void clear_l();

@ -1094,4 +1094,39 @@ status_t MediaPlayer::releaseDrm()
return status;
}
status_t MediaPlayer::setOutputDevice(audio_port_handle_t deviceId)
{
Mutex::Autolock _l(mLock);
if (mPlayer == NULL) {
ALOGV("setOutputDevice: player not init");
return NO_INIT;
}
return mPlayer->setOutputDevice(deviceId);
}
audio_port_handle_t MediaPlayer::getRoutedDeviceId()
{
Mutex::Autolock _l(mLock);
if (mPlayer == NULL) {
ALOGV("getRoutedDeviceId: player not init");
return AUDIO_PORT_HANDLE_NONE;
}
audio_port_handle_t deviceId;
status_t status = mPlayer->getRoutedDeviceId(&deviceId);
if (status != NO_ERROR) {
return AUDIO_PORT_HANDLE_NONE;
}
return deviceId;
}
status_t MediaPlayer::enableAudioDeviceCallback(bool enabled)
{
Mutex::Autolock _l(mLock);
if (mPlayer == NULL) {
ALOGV("addAudioDeviceCallback: player not init");
return NO_INIT;
}
return mPlayer->enableAudioDeviceCallback(enabled);
}
} // namespace android

@ -590,6 +590,7 @@ MediaPlayerService::Client::~Client()
free(mAudioAttributes);
}
clearDeathNotifiers_l();
mAudioDeviceUpdatedListener.clear();
}
void MediaPlayerService::Client::disconnect()
@ -697,6 +698,17 @@ void MediaPlayerService::Client::ServiceDeathNotifier::unlinkToDeath() {
}
}
void MediaPlayerService::Client::AudioDeviceUpdatedNotifier::onAudioDeviceUpdate(
audio_io_handle_t audioIo,
audio_port_handle_t deviceId) {
sp<MediaPlayerBase> listener = mListener.promote();
if (listener != NULL) {
listener->sendEvent(MEDIA_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
} else {
ALOGW("listener for process %d death is gone", MEDIA_AUDIO_ROUTING_CHANGED);
}
}
void MediaPlayerService::Client::clearDeathNotifiers_l() {
if (mExtractorDeathListener != nullptr) {
mExtractorDeathListener->unlinkToDeath();
@ -755,10 +767,11 @@ sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
clearDeathNotifiers_l();
mExtractorDeathListener = extractorDeathListener;
mCodecDeathListener = codecDeathListener;
mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
if (!p->hardwareOutput()) {
mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
mPid, mAudioAttributes);
mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
}
@ -1528,6 +1541,42 @@ status_t MediaPlayerService::Client::releaseDrm()
return ret;
}
status_t MediaPlayerService::Client::setOutputDevice(audio_port_handle_t deviceId)
{
ALOGV("[%d] setOutputDevice", mConnId);
{
Mutex::Autolock l(mLock);
if (mAudioOutput.get() != nullptr) {
return mAudioOutput->setOutputDevice(deviceId);
}
}
return NO_INIT;
}
status_t MediaPlayerService::Client::getRoutedDeviceId(audio_port_handle_t* deviceId)
{
ALOGV("[%d] getRoutedDeviceId", mConnId);
{
Mutex::Autolock l(mLock);
if (mAudioOutput.get() != nullptr) {
return mAudioOutput->getRoutedDeviceId(deviceId);
}
}
return NO_INIT;
}
status_t MediaPlayerService::Client::enableAudioDeviceCallback(bool enabled)
{
ALOGV("[%d] enableAudioDeviceCallback, %d", mConnId, enabled);
{
Mutex::Autolock l(mLock);
if (mAudioOutput.get() != nullptr) {
return mAudioOutput->enableAudioDeviceCallback(enabled);
}
}
return NO_INIT;
}
#if CALLBACK_ANTAGONIZER
const int Antagonizer::interval = 10000; // 10 msecs
@ -1566,7 +1615,7 @@ int Antagonizer::callbackThread(void* user)
#undef LOG_TAG
#define LOG_TAG "AudioSink"
MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
const audio_attributes_t* attr)
const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
: mCallback(NULL),
mCallbackCookie(NULL),
mCallbackData(NULL),
@ -1583,7 +1632,10 @@ MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t ui
mSendLevel(0.0),
mAuxEffectId(0),
mFlags(AUDIO_OUTPUT_FLAG_NONE),
mVolumeHandler(new media::VolumeHandler())
mVolumeHandler(new media::VolumeHandler()),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
mDeviceCallbackEnabled(false),
mDeviceCallback(deviceCallback)
{
ALOGV("AudioOutput(%d)", sessionId);
if (attr != NULL) {
@ -1969,7 +2021,9 @@ status_t MediaPlayerService::AudioOutput::open(
mUid,
mPid,
mAttributes,
doNotReconnect);
doNotReconnect,
1.0f, // default value for maxRequiredSpeed
mSelectedDeviceId);
} else {
// TODO: Due to buffer memory concerns, we use a max target playback speed
// based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
@ -1996,7 +2050,8 @@ status_t MediaPlayerService::AudioOutput::open(
mPid,
mAttributes,
doNotReconnect,
targetSpeed);
targetSpeed,
mSelectedDeviceId);
}
if ((t == 0) || (t->initCheck() != NO_ERROR)) {
@ -2090,6 +2145,10 @@ status_t MediaPlayerService::AudioOutput::updateTrack() {
res = mTrack->attachAuxEffect(mAuxEffectId);
}
}
mTrack->setOutputDevice(mSelectedDeviceId);
if (mDeviceCallbackEnabled) {
mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
}
ALOGV("updateTrack() DONE status %d", res);
return res;
}
@ -2305,6 +2364,45 @@ status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
return NO_ERROR;
}
status_t MediaPlayerService::AudioOutput::setOutputDevice(audio_port_handle_t deviceId)
{
ALOGV("setOutputDevice(%d)", deviceId);
Mutex::Autolock lock(mLock);
mSelectedDeviceId = deviceId;
if (mTrack != 0) {
return mTrack->setOutputDevice(deviceId);
}
return NO_ERROR;
}
status_t MediaPlayerService::AudioOutput::getRoutedDeviceId(audio_port_handle_t* deviceId)
{
ALOGV("getRoutedDeviceId");
Mutex::Autolock lock(mLock);
if (mTrack != 0) {
*deviceId = mTrack->getRoutedDeviceId();
return NO_ERROR;
}
return NO_INIT;
}
status_t MediaPlayerService::AudioOutput::enableAudioDeviceCallback(bool enabled)
{
ALOGV("enableAudioDeviceCallback, %d", enabled);
Mutex::Autolock lock(mLock);
mDeviceCallbackEnabled = enabled;
if (mTrack != 0) {
status_t status;
if (enabled) {
status = mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
} else {
status = mTrack->removeAudioDeviceCallback(mDeviceCallback.promote());
}
return status;
}
return NO_ERROR;
}
VolumeShaper::Status MediaPlayerService::AudioOutput::applyVolumeShaper(
const sp<VolumeShaper::Configuration>& configuration,
const sp<VolumeShaper::Operation>& operation)

@ -78,8 +78,12 @@ class MediaPlayerService : public BnMediaPlayerService
class CallbackData;
public:
AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
const audio_attributes_t * attr);
AudioOutput(
audio_session_t sessionId,
uid_t uid,
int pid,
const audio_attributes_t * attr,
const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
virtual ~AudioOutput();
virtual bool ready() const { return mTrack != 0; }
@ -137,6 +141,11 @@ class MediaPlayerService : public BnMediaPlayerService
const sp<media::VolumeShaper::Operation>& operation) override;
virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) override;
// AudioRouting
virtual status_t setOutputDevice(audio_port_handle_t deviceId);
virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
virtual status_t enableAudioDeviceCallback(bool enabled);
private:
static void setMinBufferCount();
static void CallbackWrapper(
@ -166,6 +175,9 @@ class MediaPlayerService : public BnMediaPlayerService
int mAuxEffectId;
audio_output_flags_t mFlags;
sp<media::VolumeHandler> mVolumeHandler;
audio_port_handle_t mSelectedDeviceId;
bool mDeviceCallbackEnabled;
wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
mutable Mutex mLock;
// static variables below not protected by mutex
@ -374,6 +386,10 @@ private:
// Modular DRM
virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
virtual status_t releaseDrm();
// AudioRouting
virtual status_t setOutputDevice(audio_port_handle_t deviceId);
virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
virtual status_t enableAudioDeviceCallback(bool enabled);
private:
class ServiceDeathNotifier:
@ -403,6 +419,21 @@ private:
wp<MediaPlayerBase> mListener;
};
class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback
{
public:
AudioDeviceUpdatedNotifier(const sp<MediaPlayerBase>& listener) {
mListener = listener;
}
~AudioDeviceUpdatedNotifier() {}
virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
audio_port_handle_t deviceId);
private:
wp<MediaPlayerBase> mListener;
};
void clearDeathNotifiers_l();
friend class MediaPlayerService;
@ -466,6 +497,7 @@ private:
sp<ServiceDeathNotifier> mExtractorDeathListener;
sp<ServiceDeathNotifier> mCodecDeathListener;
sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedListener;
#if CALLBACK_ANTAGONIZER
Antagonizer* mAntagonizer;
#endif

@ -150,6 +150,11 @@ public:
const sp<media::VolumeShaper::Configuration>& configuration,
const sp<media::VolumeShaper::Operation>& operation);
virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id);
// AudioRouting
virtual status_t setOutputDevice(audio_port_handle_t deviceId);
virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
virtual status_t enableAudioDeviceCallback(bool enabled);
};
MediaPlayerBase() : mCookie(0), mNotify(0) {}

Loading…
Cancel
Save