// Copyright (C) 2020 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 "AudioProxyManager.h" #include #include #include #include #include #include "AudioProxyDevice.h" #include "StreamProviderImpl.h" using aidl::device::google::atv::audio_proxy::IAudioProxy; using android::sp; using android::status_t; namespace audio_proxy { namespace { bool checkDevice(audio_proxy_device_t* device) { return device && device->get_address && device->open_output_stream && device->close_output_stream && // Check v2 extension. Currently only MediaShell uses this library and // we'll make sure the MediaShell will update to use the new API. device->v2 && device->v2->get_service_name && device->v2->open_output_stream; } std::shared_ptr getAudioProxyService( const std::string& serviceName) { std::string instanceName = std::string(IAudioProxy::descriptor) + "/" + serviceName; return IAudioProxy::fromBinder( ndk::SpAIBinder(AServiceManager_getService(instanceName.c_str()))); } class AudioProxyManagerImpl : public AudioProxyManager { public: AudioProxyManagerImpl(); ~AudioProxyManagerImpl() override = default; bool registerDevice(audio_proxy_device_t* device) override; private: static void onServiceDied(void* cookie); bool reconnectService(); bool reconnectService_Locked() REQUIRES(mLock); ndk::ScopedAIBinder_DeathRecipient mDeathRecipient; std::mutex mLock; std::shared_ptr mService GUARDED_BY(mLock); std::unique_ptr mDevice GUARDED_BY(mLock); }; AudioProxyManagerImpl::AudioProxyManagerImpl() : mDeathRecipient( AIBinder_DeathRecipient_new(AudioProxyManagerImpl::onServiceDied)) {} bool AudioProxyManagerImpl::registerDevice(audio_proxy_device_t* device) { if (!checkDevice(device)) { LOG(ERROR) << "Invalid device."; return false; } std::scoped_lock lock(mLock); if (mDevice) { DCHECK(mService); LOG(ERROR) << "Device already registered!"; return false; } mDevice = std::make_unique(device); DCHECK(!mService); return reconnectService_Locked(); } bool AudioProxyManagerImpl::reconnectService() { std::scoped_lock lock(mLock); return reconnectService_Locked(); } bool AudioProxyManagerImpl::reconnectService_Locked() { DCHECK(mDevice); auto service = getAudioProxyService(mDevice->getServiceName()); if (!service) { LOG(ERROR) << "Failed to reconnect service"; return false; } binder_status_t binder_status = AIBinder_linkToDeath( service->asBinder().get(), mDeathRecipient.get(), this); if (binder_status != STATUS_OK) { LOG(ERROR) << "Failed to linkToDeath " << static_cast(binder_status); return false; } ndk::ScopedAStatus status = service->start( ndk::SharedRefBase::make(mDevice.get())); if (!status.isOk()) { LOG(ERROR) << "Failed to start service."; return false; } mService = std::move(service); return true; } // static void AudioProxyManagerImpl::onServiceDied(void* cookie) { auto* manager = static_cast(cookie); manager->reconnectService(); } } // namespace std::unique_ptr createAudioProxyManager() { return std::make_unique(); } } // namespace audio_proxy