1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <condition_variable>
20 #include <mutex>
21 
22 #include <android-base/thread_annotations.h>
23 
24 #include <aidl/android/hardware/audio/common/SinkMetadata.h>
25 #include <aidl/android/hardware/audio/common/SourceMetadata.h>
26 #include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
27 #include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
28 #include <aidl/android/hardware/bluetooth/audio/PresentationPosition.h>
29 #include <aidl/android/hardware/bluetooth/audio/SessionType.h>
30 #include <aidl/android/media/audio/common/AudioDeviceDescription.h>
31 
32 namespace android::bluetooth::audio::aidl {
33 
34 enum class BluetoothStreamState : uint8_t {
35     DISABLED = 0,  // This stream is closing or Bluetooth profiles (A2DP/LE) is disabled
36     STANDBY,
37     STARTING,
38     STARTED,
39     SUSPENDING,
40     UNKNOWN,
41 };
42 
43 std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state);
44 
45 /**
46  * Proxy for Bluetooth Audio HW Module to communicate with Bluetooth Audio
47  * Session Control. All methods are not thread safe, so users must acquire a
48  * lock. Note: currently, getState() of DevicePortProxy is only used for
49  * verbose logging, it is not locked, so the state may not be synchronized.
50  */
51 class BluetoothAudioPort {
52   public:
53     BluetoothAudioPort() = default;
54     virtual ~BluetoothAudioPort() = default;
55 
56     /**
57      * Fetch output control / data path of BluetoothAudioPort and setup
58      * callbacks into BluetoothAudioProvider. If registerPort() returns false, the audio
59      * HAL must delete this BluetoothAudioPort and return EINVAL to caller
60      */
61     virtual bool registerPort(
62             const ::aidl::android::media::audio::common::AudioDeviceDescription&) = 0;
63 
64     /**
65      * Unregister this BluetoothAudioPort from BluetoothAudioSessionControl.
66      * Audio HAL must delete this BluetoothAudioPort after calling this.
67      */
68     virtual void unregisterPort() = 0;
69 
70     /**
71      * When the Audio framework / HAL tries to query audio config about format,
72      * channel mask and sample rate, it uses this function to fetch from the
73      * Bluetooth stack
74      */
75     virtual bool loadAudioConfig(
76             ::aidl::android::hardware::bluetooth::audio::PcmConfiguration&) = 0;
77 
78     /**
79      * When the Audio framework / HAL wants to change the stream state, it invokes
80      * these 4 functions to control the Bluetooth stack (Audio Control Path).
81      * Note: standby(), start() and suspend() will return true when there are no errors.
82 
83      * Called by Audio framework / HAL to change the state to stand by. When A2DP/LE profile is
84      * disabled, the port is first set to STANDBY by calling suspend and then mState is set to
85      * DISABLED. To reset the state back to STANDBY this method is called.
86      */
87     virtual bool standby() = 0;
88 
89     /**
90      * Called by Audio framework / HAL to start the stream
91      */
92     virtual bool start() = 0;
93 
94     /**
95      * Called by Audio framework / HAL to suspend the stream
96      */
97     virtual bool suspend() = 0;
98 
99     /**
100      * Called by Audio framework / HAL to stop the stream
101      */
102     virtual void stop() = 0;
103 
104     /**
105      * Called by the Audio framework / HAL to fetch information about audio frames
106      * presented to an external sink, or frames presented fror an internal sink
107      */
108     virtual bool getPresentationPosition(
109             ::aidl::android::hardware::bluetooth::audio::PresentationPosition&) const = 0;
110 
111     /**
112      * Called by the Audio framework / HAL when the metadata of the stream's
113      * source has been changed.
114      */
updateSourceMetadata(const::aidl::android::hardware::audio::common::SourceMetadata &)115     virtual bool updateSourceMetadata(
116             const ::aidl::android::hardware::audio::common::SourceMetadata&) const {
117         return false;
118     }
119 
120     /**
121      * Called by the Audio framework / HAL when the metadata of the stream's
122      * sink has been changed.
123      */
updateSinkMetadata(const::aidl::android::hardware::audio::common::SinkMetadata &)124     virtual bool updateSinkMetadata(
125             const ::aidl::android::hardware::audio::common::SinkMetadata&) const {
126         return false;
127     }
128 
129     /**
130      * Return the current BluetoothStreamState
131      */
132     virtual BluetoothStreamState getState() const = 0;
133 
134     /**
135      * Set the current BluetoothStreamState
136      */
137     virtual bool setState(BluetoothStreamState) = 0;
138 
139     virtual bool isA2dp() const = 0;
140 
141     virtual bool isLeAudio() const = 0;
142 
143     virtual bool getPreferredDataIntervalUs(size_t&) const = 0;
144 
writeData(const void *,size_t)145     virtual size_t writeData(const void*, size_t) const { return 0; }
146 
readData(void *,size_t)147     virtual size_t readData(void*, size_t) const { return 0; }
148 };
149 
150 class BluetoothAudioPortAidl : public BluetoothAudioPort {
151   public:
152     BluetoothAudioPortAidl();
153     virtual ~BluetoothAudioPortAidl();
154 
155     bool registerPort(const ::aidl::android::media::audio::common::AudioDeviceDescription&
156                               description) override;
157 
158     void unregisterPort() override;
159 
160     bool loadAudioConfig(
161             ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;
162 
163     bool standby() override;
164     bool start() override;
165     bool suspend() override;
166     void stop() override;
167 
168     bool getPresentationPosition(::aidl::android::hardware::bluetooth::audio::PresentationPosition&
169                                          presentation_position) const override;
170 
171     bool updateSourceMetadata(const ::aidl::android::hardware::audio::common::SourceMetadata&
172                                       sourceMetadata) const override;
173 
174     bool updateSinkMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
175                                     sinkMetadata) const override;
176 
177     /**
178      * Return the current BluetoothStreamState
179      * Note: This method is used for logging, does not lock, so value returned may not be latest
180      */
181     BluetoothStreamState getState() const override NO_THREAD_SAFETY_ANALYSIS;
182 
183     bool setState(BluetoothStreamState state) override;
184 
185     bool isA2dp() const override;
186 
187     bool isLeAudio() const override;
188 
189     bool getPreferredDataIntervalUs(size_t& interval_us) const override;
190 
191   protected:
192     uint16_t mCookie;
193     BluetoothStreamState mState GUARDED_BY(mCvMutex);
194     ::aidl::android::hardware::bluetooth::audio::SessionType mSessionType;
195     // WR to support Mono: True if fetching Stereo and mixing into Mono
196     bool mIsStereoToMono = false;
197 
198     bool inUse() const;
199 
200     std::string debugMessage() const;
201 
202   private:
203     // start()/suspend() report state change status via callback. Wait until kMaxWaitingTimeMs or a
204     // state change after a call to start()/suspend() and analyse the returned status. Below mutex,
205     // conditional variable serves this purpose.
206     mutable std::mutex mCvMutex;
207     std::condition_variable mInternalCv GUARDED_BY(mCvMutex);
208 
209     // Check and initialize session type for |devices| If failed, this
210     // BluetoothAudioPortAidl is not initialized and must be deleted.
211     bool initSessionType(
212             const ::aidl::android::media::audio::common::AudioDeviceDescription& description);
213 
214     bool condWaitState(BluetoothStreamState state);
215 
216     void controlResultHandler(
217             uint16_t cookie,
218             const ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus& status);
219     void sessionChangedHandler(uint16_t cookie);
220 };
221 
222 class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl {
223   public:
224     bool loadAudioConfig(
225             ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;
226 
227     // The audio data path to the Bluetooth stack (Software encoding)
228     size_t writeData(const void* buffer, size_t bytes) const override;
229 };
230 
231 class BluetoothAudioPortAidlIn : public BluetoothAudioPortAidl {
232   public:
233     // The audio data path from the Bluetooth stack (Software decoded)
234     size_t readData(void* buffer, size_t bytes) const override;
235 };
236 
237 }  // namespace android::bluetooth::audio::aidl
238