1*4d7e907cSAndroid Build Coastguard Worker /* 2*4d7e907cSAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project 3*4d7e907cSAndroid Build Coastguard Worker * 4*4d7e907cSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*4d7e907cSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*4d7e907cSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*4d7e907cSAndroid Build Coastguard Worker * 8*4d7e907cSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*4d7e907cSAndroid Build Coastguard Worker * 10*4d7e907cSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*4d7e907cSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*4d7e907cSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*4d7e907cSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*4d7e907cSAndroid Build Coastguard Worker * limitations under the License. 15*4d7e907cSAndroid Build Coastguard Worker */ 16*4d7e907cSAndroid Build Coastguard Worker 17*4d7e907cSAndroid Build Coastguard Worker /** 18*4d7e907cSAndroid Build Coastguard Worker ** This class is deprecated because its use causes threading issues 19*4d7e907cSAndroid Build Coastguard Worker ** with the FMQ due to change of threads reading and writing into FMQ. 20*4d7e907cSAndroid Build Coastguard Worker ** 21*4d7e907cSAndroid Build Coastguard Worker ** DO NOT USE. These files will be removed. 22*4d7e907cSAndroid Build Coastguard Worker **/ 23*4d7e907cSAndroid Build Coastguard Worker 24*4d7e907cSAndroid Build Coastguard Worker #pragma once 25*4d7e907cSAndroid Build Coastguard Worker 26*4d7e907cSAndroid Build Coastguard Worker #include "core-impl/Stream.h" 27*4d7e907cSAndroid Build Coastguard Worker 28*4d7e907cSAndroid Build Coastguard Worker namespace aidl::android::hardware::audio::core::deprecated { 29*4d7e907cSAndroid Build Coastguard Worker 30*4d7e907cSAndroid Build Coastguard Worker // 'StreamSwitcher' is an implementation of 'StreamCommonInterface' which allows 31*4d7e907cSAndroid Build Coastguard Worker // dynamically switching the underlying stream implementation based on currently 32*4d7e907cSAndroid Build Coastguard Worker // connected devices. This is achieved by replacing inheritance from 33*4d7e907cSAndroid Build Coastguard Worker // 'StreamCommonImpl' with owning an instance of it. StreamSwitcher must be 34*4d7e907cSAndroid Build Coastguard Worker // extended in order to supply the logic for choosing the stream 35*4d7e907cSAndroid Build Coastguard Worker // implementation. When there are no connected devices, for instance, upon the 36*4d7e907cSAndroid Build Coastguard Worker // creation, the StreamSwitcher engages an instance of a stub stream in order to 37*4d7e907cSAndroid Build Coastguard Worker // keep serving requests coming via 'StreamDescriptor'. 38*4d7e907cSAndroid Build Coastguard Worker // 39*4d7e907cSAndroid Build Coastguard Worker // StreamSwitcher implements the 'IStreamCommon' interface directly, with 40*4d7e907cSAndroid Build Coastguard Worker // necessary delegation to the current stream implementation. While the stub 41*4d7e907cSAndroid Build Coastguard Worker // stream is engaged, any requests made via 'IStreamCommon' (parameters, effects 42*4d7e907cSAndroid Build Coastguard Worker // setting, etc) are postponed and only delivered on device connection change 43*4d7e907cSAndroid Build Coastguard Worker // to the "real" stream implementation provided by the extending class. This is why 44*4d7e907cSAndroid Build Coastguard Worker // the behavior of StreamSwitcher in the "stub" state is not identical to behavior 45*4d7e907cSAndroid Build Coastguard Worker // of 'StreamStub'. It can become a full substitute for 'StreamStub' once 46*4d7e907cSAndroid Build Coastguard Worker // device connection change event occurs and the extending class returns 47*4d7e907cSAndroid Build Coastguard Worker // 'LEAVE_CURRENT_STREAM' from 'switchCurrentStream' method. 48*4d7e907cSAndroid Build Coastguard Worker // 49*4d7e907cSAndroid Build Coastguard Worker // There is a natural limitation that the current stream implementation may only 50*4d7e907cSAndroid Build Coastguard Worker // be switched when the stream is in the 'STANDBY' state. Thus, when the event 51*4d7e907cSAndroid Build Coastguard Worker // to switch the stream occurs, the current stream is stopped and joined, and 52*4d7e907cSAndroid Build Coastguard Worker // its last state is validated. Since the change of the set of connected devices 53*4d7e907cSAndroid Build Coastguard Worker // normally occurs on patch updates, if the stream was not in standby, this is 54*4d7e907cSAndroid Build Coastguard Worker // reported to the caller of 'IModule.setAudioPatch' as the 'EX_ILLEGAL_STATE' 55*4d7e907cSAndroid Build Coastguard Worker // error. 56*4d7e907cSAndroid Build Coastguard Worker // 57*4d7e907cSAndroid Build Coastguard Worker // The simplest use case, when the implementor just needs to emulate the legacy HAL API 58*4d7e907cSAndroid Build Coastguard Worker // behavior of receiving the connected devices upon stream creation, the implementation 59*4d7e907cSAndroid Build Coastguard Worker // of the extending class can look as follows. We assume that 'StreamLegacy' implementation 60*4d7e907cSAndroid Build Coastguard Worker // is the one requiring to know connected devices on creation: 61*4d7e907cSAndroid Build Coastguard Worker // 62*4d7e907cSAndroid Build Coastguard Worker // class StreamLegacy : public StreamCommonImpl { 63*4d7e907cSAndroid Build Coastguard Worker // public: 64*4d7e907cSAndroid Build Coastguard Worker // StreamLegacy(StreamContext* context, const Metadata& metadata, 65*4d7e907cSAndroid Build Coastguard Worker // const std::vector<AudioDevice>& devices); 66*4d7e907cSAndroid Build Coastguard Worker // }; 67*4d7e907cSAndroid Build Coastguard Worker // 68*4d7e907cSAndroid Build Coastguard Worker // class StreamOutLegacy final : public StreamOut, public StreamSwitcher { 69*4d7e907cSAndroid Build Coastguard Worker // public: 70*4d7e907cSAndroid Build Coastguard Worker // StreamOutLegacy(StreamContext&& context, metatadata etc.) 71*4d7e907cSAndroid Build Coastguard Worker // private: 72*4d7e907cSAndroid Build Coastguard Worker // DeviceSwitchBehavior switchCurrentStream(const std::vector<AudioDevice>&) override { 73*4d7e907cSAndroid Build Coastguard Worker // // This implementation effectively postpones stream creation until 74*4d7e907cSAndroid Build Coastguard Worker // // receiving the first call to 'setConnectedDevices' with a non-empty list. 75*4d7e907cSAndroid Build Coastguard Worker // return isStubStream() ? DeviceSwitchBehavior::CREATE_NEW_STREAM : 76*4d7e907cSAndroid Build Coastguard Worker // DeviceSwitchBehavior::USE_CURRENT_STREAM; 77*4d7e907cSAndroid Build Coastguard Worker // } 78*4d7e907cSAndroid Build Coastguard Worker // std::unique_ptr<StreamCommonInterfaceEx> createNewStream( 79*4d7e907cSAndroid Build Coastguard Worker // const std::vector<AudioDevice>& devices, 80*4d7e907cSAndroid Build Coastguard Worker // StreamContext* context, const Metadata& metadata) override { 81*4d7e907cSAndroid Build Coastguard Worker // return std::unique_ptr<StreamCommonInterfaceEx>(new InnerStreamWrapper<StreamLegacy>( 82*4d7e907cSAndroid Build Coastguard Worker // context, metadata, devices)); 83*4d7e907cSAndroid Build Coastguard Worker // } 84*4d7e907cSAndroid Build Coastguard Worker // void onClose(StreamDescriptor::State) override { defaultOnClose(); } 85*4d7e907cSAndroid Build Coastguard Worker // } 86*4d7e907cSAndroid Build Coastguard Worker // 87*4d7e907cSAndroid Build Coastguard Worker 88*4d7e907cSAndroid Build Coastguard Worker class StreamCommonInterfaceEx : virtual public StreamCommonInterface { 89*4d7e907cSAndroid Build Coastguard Worker public: 90*4d7e907cSAndroid Build Coastguard Worker virtual StreamDescriptor::State getStatePriorToClosing() const = 0; 91*4d7e907cSAndroid Build Coastguard Worker }; 92*4d7e907cSAndroid Build Coastguard Worker 93*4d7e907cSAndroid Build Coastguard Worker template <typename T> 94*4d7e907cSAndroid Build Coastguard Worker class InnerStreamWrapper : public T, public StreamCommonInterfaceEx { 95*4d7e907cSAndroid Build Coastguard Worker public: 96*4d7e907cSAndroid Build Coastguard Worker template <typename... Args> InnerStreamWrapper(Args &&...args)97*4d7e907cSAndroid Build Coastguard Worker InnerStreamWrapper(Args&&... args) : T(std::forward<Args>(args)...) {} getStatePriorToClosing()98*4d7e907cSAndroid Build Coastguard Worker StreamDescriptor::State getStatePriorToClosing() const override { return mStatePriorToClosing; } 99*4d7e907cSAndroid Build Coastguard Worker 100*4d7e907cSAndroid Build Coastguard Worker private: 101*4d7e907cSAndroid Build Coastguard Worker // Do not need to do anything on close notification from the inner stream 102*4d7e907cSAndroid Build Coastguard Worker // because StreamSwitcher handles IStreamCommon::close by itself. onClose(StreamDescriptor::State statePriorToClosing)103*4d7e907cSAndroid Build Coastguard Worker void onClose(StreamDescriptor::State statePriorToClosing) override { 104*4d7e907cSAndroid Build Coastguard Worker mStatePriorToClosing = statePriorToClosing; 105*4d7e907cSAndroid Build Coastguard Worker } 106*4d7e907cSAndroid Build Coastguard Worker 107*4d7e907cSAndroid Build Coastguard Worker StreamDescriptor::State mStatePriorToClosing = StreamDescriptor::State::STANDBY; 108*4d7e907cSAndroid Build Coastguard Worker }; 109*4d7e907cSAndroid Build Coastguard Worker 110*4d7e907cSAndroid Build Coastguard Worker class StreamSwitcher : virtual public StreamCommonInterface { 111*4d7e907cSAndroid Build Coastguard Worker public: 112*4d7e907cSAndroid Build Coastguard Worker StreamSwitcher(StreamContext* context, const Metadata& metadata); 113*4d7e907cSAndroid Build Coastguard Worker 114*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus close() override; 115*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus prepareToClose() override; 116*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override; 117*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids, 118*4d7e907cSAndroid Build Coastguard Worker std::vector<VendorParameter>* _aidl_return) override; 119*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters, 120*4d7e907cSAndroid Build Coastguard Worker bool in_async) override; 121*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus addEffect( 122*4d7e907cSAndroid Build Coastguard Worker const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) 123*4d7e907cSAndroid Build Coastguard Worker override; 124*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus removeEffect( 125*4d7e907cSAndroid Build Coastguard Worker const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) 126*4d7e907cSAndroid Build Coastguard Worker override; 127*4d7e907cSAndroid Build Coastguard Worker 128*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus getStreamCommonCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override; 129*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override; 130*4d7e907cSAndroid Build Coastguard Worker 131*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus initInstance( 132*4d7e907cSAndroid Build Coastguard Worker const std::shared_ptr<StreamCommonInterface>& delegate) override; 133*4d7e907cSAndroid Build Coastguard Worker const StreamContext& getContext() const override; 134*4d7e907cSAndroid Build Coastguard Worker bool isClosed() const override; 135*4d7e907cSAndroid Build Coastguard Worker const ConnectedDevices& getConnectedDevices() const override; 136*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus setConnectedDevices( 137*4d7e907cSAndroid Build Coastguard Worker const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) 138*4d7e907cSAndroid Build Coastguard Worker override; 139*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus bluetoothParametersUpdated() override; 140*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus setGain(float gain) override; 141*4d7e907cSAndroid Build Coastguard Worker 142*4d7e907cSAndroid Build Coastguard Worker protected: 143*4d7e907cSAndroid Build Coastguard Worker // Since switching a stream requires closing down the current stream, StreamSwitcher 144*4d7e907cSAndroid Build Coastguard Worker // asks the extending class its intent on the connected devices change. 145*4d7e907cSAndroid Build Coastguard Worker enum DeviceSwitchBehavior { 146*4d7e907cSAndroid Build Coastguard Worker // Continue using the current stream implementation. If it's the stub implementation, 147*4d7e907cSAndroid Build Coastguard Worker // StreamSwitcher starts treating the stub stream as a "real" implementation, 148*4d7e907cSAndroid Build Coastguard Worker // without effectively closing it and starting again. 149*4d7e907cSAndroid Build Coastguard Worker USE_CURRENT_STREAM, 150*4d7e907cSAndroid Build Coastguard Worker // This is the normal case when the extending class provides a "real" implementation 151*4d7e907cSAndroid Build Coastguard Worker // which is not a stub implementation. 152*4d7e907cSAndroid Build Coastguard Worker CREATE_NEW_STREAM, 153*4d7e907cSAndroid Build Coastguard Worker // This is the case when the extending class wants to revert back to the initial 154*4d7e907cSAndroid Build Coastguard Worker // condition of using a stub stream provided by the StreamSwitcher. This behavior 155*4d7e907cSAndroid Build Coastguard Worker // is only allowed when the list of connected devices is empty. 156*4d7e907cSAndroid Build Coastguard Worker SWITCH_TO_STUB_STREAM, 157*4d7e907cSAndroid Build Coastguard Worker // Use when the set of devices is not supported by the extending class. This returns 158*4d7e907cSAndroid Build Coastguard Worker // 'EX_UNSUPPORTED_OPERATION' from 'setConnectedDevices'. 159*4d7e907cSAndroid Build Coastguard Worker UNSUPPORTED_DEVICES, 160*4d7e907cSAndroid Build Coastguard Worker }; 161*4d7e907cSAndroid Build Coastguard Worker // StreamSwitcher will call these methods from 'setConnectedDevices'. If the switch behavior 162*4d7e907cSAndroid Build Coastguard Worker // is 'CREATE_NEW_STREAM', the 'createwNewStream' function will be called (with the same 163*4d7e907cSAndroid Build Coastguard Worker // device vector) for obtaining a new stream implementation, assuming that closing 164*4d7e907cSAndroid Build Coastguard Worker // the current stream was a success. 165*4d7e907cSAndroid Build Coastguard Worker virtual DeviceSwitchBehavior switchCurrentStream( 166*4d7e907cSAndroid Build Coastguard Worker const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) = 0; 167*4d7e907cSAndroid Build Coastguard Worker virtual std::unique_ptr<StreamCommonInterfaceEx> createNewStream( 168*4d7e907cSAndroid Build Coastguard Worker const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, 169*4d7e907cSAndroid Build Coastguard Worker StreamContext* context, const Metadata& metadata) = 0; 170*4d7e907cSAndroid Build Coastguard Worker virtual void onClose(StreamDescriptor::State streamPriorToClosing) = 0; 171*4d7e907cSAndroid Build Coastguard Worker isStubStream()172*4d7e907cSAndroid Build Coastguard Worker bool isStubStream() const { return mIsStubStream; } getCurrentStream()173*4d7e907cSAndroid Build Coastguard Worker StreamCommonInterfaceEx* getCurrentStream() const { return mStream.get(); } 174*4d7e907cSAndroid Build Coastguard Worker 175*4d7e907cSAndroid Build Coastguard Worker private: 176*4d7e907cSAndroid Build Coastguard Worker using VndParam = std::pair<std::vector<VendorParameter>, bool /*isAsync*/>; 177*4d7e907cSAndroid Build Coastguard Worker isValidClosingStreamState(StreamDescriptor::State state)178*4d7e907cSAndroid Build Coastguard Worker static constexpr bool isValidClosingStreamState(StreamDescriptor::State state) { 179*4d7e907cSAndroid Build Coastguard Worker return state == StreamDescriptor::State::STANDBY || state == StreamDescriptor::State::ERROR; 180*4d7e907cSAndroid Build Coastguard Worker } 181*4d7e907cSAndroid Build Coastguard Worker 182*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus closeCurrentStream(bool validateStreamState); 183*4d7e907cSAndroid Build Coastguard Worker 184*4d7e907cSAndroid Build Coastguard Worker // StreamSwitcher does not own the context. 185*4d7e907cSAndroid Build Coastguard Worker StreamContext* mContext; 186*4d7e907cSAndroid Build Coastguard Worker Metadata mMetadata; 187*4d7e907cSAndroid Build Coastguard Worker ChildInterface<StreamCommonDelegator> mCommon; 188*4d7e907cSAndroid Build Coastguard Worker // The current stream. 189*4d7e907cSAndroid Build Coastguard Worker std::unique_ptr<StreamCommonInterfaceEx> mStream; 190*4d7e907cSAndroid Build Coastguard Worker // Indicates whether 'mCurrentStream' is a stub stream implementation 191*4d7e907cSAndroid Build Coastguard Worker // maintained by StreamSwitcher until the extending class provides a "real" 192*4d7e907cSAndroid Build Coastguard Worker // implementation. The invariant of this state is that there are no connected 193*4d7e907cSAndroid Build Coastguard Worker // devices. 194*4d7e907cSAndroid Build Coastguard Worker bool mIsStubStream = true; 195*4d7e907cSAndroid Build Coastguard Worker // Storage for the data from commands received via 'IStreamCommon'. 196*4d7e907cSAndroid Build Coastguard Worker std::optional<int32_t> mHwAvSyncId; 197*4d7e907cSAndroid Build Coastguard Worker std::vector<VndParam> mMissedParameters; 198*4d7e907cSAndroid Build Coastguard Worker std::vector<std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>> mEffects; 199*4d7e907cSAndroid Build Coastguard Worker bool mBluetoothParametersUpdated = false; 200*4d7e907cSAndroid Build Coastguard Worker }; 201*4d7e907cSAndroid Build Coastguard Worker 202*4d7e907cSAndroid Build Coastguard Worker } // namespace aidl::android::hardware::audio::core::deprecated 203