/* * Copyright (C) 2017 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. */ #include #include #include #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) namespace android { using aidl_utils::binderStatusFromStatusT; using media::VolumeShaperConfiguration; using media::VolumeShaperOperation; //-------------------------------------------------------------------------------------------------- PlayerBase::PlayerBase() : BnPlayer(), mPanMultiplierL(1.0f), mPanMultiplierR(1.0f), mVolumeMultiplierL(1.0f), mVolumeMultiplierR(1.0f), mPIId(PLAYER_PIID_INVALID), mLastReportedEvent(PLAYER_STATE_UNKNOWN), mLastReportedDeviceId(AUDIO_PORT_HANDLE_NONE) { ALOGD("PlayerBase::PlayerBase()"); // use checkService() to avoid blocking if audio service is not up yet sp binder = defaultServiceManager()->checkService(String16("audio")); if (binder == 0) { ALOGE("PlayerBase(): binding to audio service failed, service up?"); } else { mAudioManager = interface_cast(binder); } } PlayerBase::~PlayerBase() { ALOGD("PlayerBase::~PlayerBase()"); baseDestroy(); } void PlayerBase::init(player_type_t playerType, audio_usage_t usage, audio_session_t sessionId) { if (mAudioManager == 0) { ALOGE("AudioPlayer realize: no audio service, player will not be registered"); } else { mPIId = mAudioManager->trackPlayer(playerType, usage, AUDIO_CONTENT_TYPE_UNKNOWN, this, sessionId); } } void PlayerBase::triggerPortIdUpdate(audio_port_handle_t portId) const { if (mAudioManager == nullptr) { ALOGE("%s: no audio service, player %d will not update portId %d", __func__, mPIId, portId); return; } if (mPIId != PLAYER_PIID_INVALID && portId != AUDIO_PORT_HANDLE_NONE) { mAudioManager->playerEvent(mPIId, android::PLAYER_UPDATE_PORT_ID, portId); } } void PlayerBase::baseDestroy() { serviceReleasePlayer(); if (mAudioManager != 0) { mAudioManager.clear(); } } //------------------------------------------------------------------------------ void PlayerBase::servicePlayerEvent(player_state_t event, audio_port_handle_t deviceId) { if (mAudioManager != 0) { bool changed = false; { Mutex::Autolock _l(mDeviceIdLock); changed = mLastReportedDeviceId != deviceId; mLastReportedDeviceId = deviceId; } { Mutex::Autolock _l(mPlayerStateLock); // PLAYER_UPDATE_DEVICE_ID is not saved as an actual state, instead it is used to update // device ID only. if ((event != PLAYER_UPDATE_DEVICE_ID) && (event != mLastReportedEvent)) { mLastReportedEvent = event; changed = true; } } if (changed && (mPIId != PLAYER_PIID_INVALID)) { mAudioManager->playerEvent(mPIId, event, deviceId); } } } void PlayerBase::serviceReleasePlayer() { if (mAudioManager != 0 && mPIId != PLAYER_PIID_INVALID) { mAudioManager->releasePlayer(mPIId); } } //FIXME temporary method while some player state is outside of this class void PlayerBase::reportEvent(player_state_t event, audio_port_handle_t deviceId) { servicePlayerEvent(event, deviceId); } void PlayerBase::baseUpdateDeviceId(audio_port_handle_t deviceId) { servicePlayerEvent(PLAYER_UPDATE_DEVICE_ID, deviceId); } status_t PlayerBase::startWithStatus(audio_port_handle_t deviceId) { status_t status = playerStart(); if (status == NO_ERROR) { servicePlayerEvent(PLAYER_STATE_STARTED, deviceId); } else { ALOGW("PlayerBase::start() error %d", status); } return status; } status_t PlayerBase::pauseWithStatus() { status_t status = playerPause(); if (status == NO_ERROR) { servicePlayerEvent(PLAYER_STATE_PAUSED, AUDIO_PORT_HANDLE_NONE); } else { ALOGW("PlayerBase::pause() error %d", status); } return status; } status_t PlayerBase::stopWithStatus() { status_t status = playerStop(); if (status == NO_ERROR) { servicePlayerEvent(PLAYER_STATE_STOPPED, AUDIO_PORT_HANDLE_NONE); } else { ALOGW("PlayerBase::stop() error %d", status); } return status; } //------------------------------------------------------------------------------ // Implementation of IPlayer binder::Status PlayerBase::start() { ALOGD("PlayerBase::start() from IPlayer"); audio_port_handle_t deviceId; { Mutex::Autolock _l(mDeviceIdLock); deviceId = mLastReportedDeviceId; } (void)startWithStatus(deviceId); return binder::Status::ok(); } binder::Status PlayerBase::pause() { ALOGD("PlayerBase::pause() from IPlayer"); (void)pauseWithStatus(); return binder::Status::ok(); } binder::Status PlayerBase::stop() { ALOGD("PlayerBase::stop() from IPlayer"); (void)stopWithStatus(); return binder::Status::ok(); } binder::Status PlayerBase::setVolume(float vol) { ALOGD("PlayerBase::setVolume() from IPlayer"); { Mutex::Autolock _l(mSettingsLock); mVolumeMultiplierL = vol; mVolumeMultiplierR = vol; } status_t status = playerSetVolume(); if (status != NO_ERROR) { ALOGW("PlayerBase::setVolume() error %d", status); } return binderStatusFromStatusT(status); } binder::Status PlayerBase::setPan(float pan) { ALOGD("PlayerBase::setPan() from IPlayer"); { Mutex::Autolock _l(mSettingsLock); pan = min(max(-1.0f, pan), 1.0f); if (pan >= 0.0f) { mPanMultiplierL = 1.0f - pan; mPanMultiplierR = 1.0f; } else { mPanMultiplierL = 1.0f; mPanMultiplierR = 1.0f + pan; } } status_t status = playerSetVolume(); if (status != NO_ERROR) { ALOGW("PlayerBase::setPan() error %d", status); } return binderStatusFromStatusT(status); } binder::Status PlayerBase::setStartDelayMs(int32_t delayMs __unused) { ALOGW("setStartDelay() is not supported"); return binder::Status::ok(); } binder::Status PlayerBase::applyVolumeShaper( const VolumeShaperConfiguration& configuration __unused, const VolumeShaperOperation& operation __unused) { ALOGW("applyVolumeShaper() is not supported"); return binder::Status::ok(); } } // namespace android