| /* |
| * 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 <binder/IServiceManager.h> |
| #include <media/AidlConversionUtil.h> |
| #include <media/PlayerBase.h> |
| |
| #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<IBinder> binder = defaultServiceManager()->checkService(String16("audio")); |
| if (binder == 0) { |
| ALOGE("PlayerBase(): binding to audio service failed, service up?"); |
| } else { |
| mAudioManager = interface_cast<IAudioManager>(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 |