1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker * Copyright 2018 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 #pragma once
18*4d7e907cSAndroid Build Coastguard Worker
19*4d7e907cSAndroid Build Coastguard Worker #include <mutex>
20*4d7e907cSAndroid Build Coastguard Worker #include <unordered_map>
21*4d7e907cSAndroid Build Coastguard Worker
22*4d7e907cSAndroid Build Coastguard Worker #include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioPort.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <fmq/MessageQueue.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <hardware/audio.h>
25*4d7e907cSAndroid Build Coastguard Worker #include <hidl/MQDescriptor.h>
26*4d7e907cSAndroid Build Coastguard Worker
27*4d7e907cSAndroid Build Coastguard Worker namespace android {
28*4d7e907cSAndroid Build Coastguard Worker namespace bluetooth {
29*4d7e907cSAndroid Build Coastguard Worker namespace audio {
30*4d7e907cSAndroid Build Coastguard Worker
31*4d7e907cSAndroid Build Coastguard Worker using ::android::sp;
32*4d7e907cSAndroid Build Coastguard Worker using ::android::hardware::kSynchronizedReadWrite;
33*4d7e907cSAndroid Build Coastguard Worker using ::android::hardware::MessageQueue;
34*4d7e907cSAndroid Build Coastguard Worker using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
35*4d7e907cSAndroid Build Coastguard Worker using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
36*4d7e907cSAndroid Build Coastguard Worker using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
37*4d7e907cSAndroid Build Coastguard Worker using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
38*4d7e907cSAndroid Build Coastguard Worker using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort;
39*4d7e907cSAndroid Build Coastguard Worker using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
40*4d7e907cSAndroid Build Coastguard Worker using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
41*4d7e907cSAndroid Build Coastguard Worker using ::android::hardware::bluetooth::audio::V2_0::SessionType;
42*4d7e907cSAndroid Build Coastguard Worker
43*4d7e907cSAndroid Build Coastguard Worker using BluetoothAudioStatus =
44*4d7e907cSAndroid Build Coastguard Worker ::android::hardware::bluetooth::audio::V2_0::Status;
45*4d7e907cSAndroid Build Coastguard Worker
46*4d7e907cSAndroid Build Coastguard Worker using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
47*4d7e907cSAndroid Build Coastguard Worker
48*4d7e907cSAndroid Build Coastguard Worker static constexpr uint16_t kObserversCookieSize = 0x0010; // 0x0000 ~ 0x000f
49*4d7e907cSAndroid Build Coastguard Worker constexpr uint16_t kObserversCookieUndefined =
50*4d7e907cSAndroid Build Coastguard Worker (static_cast<uint16_t>(SessionType::UNKNOWN) << 8 & 0xff00);
ObserversCookieGetSessionType(uint16_t cookie)51*4d7e907cSAndroid Build Coastguard Worker inline SessionType ObserversCookieGetSessionType(uint16_t cookie) {
52*4d7e907cSAndroid Build Coastguard Worker return static_cast<SessionType>(cookie >> 8 & 0x00ff);
53*4d7e907cSAndroid Build Coastguard Worker }
ObserversCookieGetInitValue(SessionType session_type)54*4d7e907cSAndroid Build Coastguard Worker inline uint16_t ObserversCookieGetInitValue(SessionType session_type) {
55*4d7e907cSAndroid Build Coastguard Worker return (static_cast<uint16_t>(session_type) << 8 & 0xff00);
56*4d7e907cSAndroid Build Coastguard Worker }
ObserversCookieGetUpperBound(SessionType session_type)57*4d7e907cSAndroid Build Coastguard Worker inline uint16_t ObserversCookieGetUpperBound(SessionType session_type) {
58*4d7e907cSAndroid Build Coastguard Worker return (static_cast<uint16_t>(session_type) << 8 & 0xff00) +
59*4d7e907cSAndroid Build Coastguard Worker kObserversCookieSize;
60*4d7e907cSAndroid Build Coastguard Worker }
61*4d7e907cSAndroid Build Coastguard Worker
62*4d7e907cSAndroid Build Coastguard Worker // This presents the callbacks of started / suspended and session changed,
63*4d7e907cSAndroid Build Coastguard Worker // and the bluetooth_audio module uses to receive the status notification
64*4d7e907cSAndroid Build Coastguard Worker struct PortStatusCallbacks {
65*4d7e907cSAndroid Build Coastguard Worker // control_result_cb_ - when the Bluetooth stack reports results of
66*4d7e907cSAndroid Build Coastguard Worker // streamStarted or streamSuspended, the BluetoothAudioProvider will invoke
67*4d7e907cSAndroid Build Coastguard Worker // this callback to report to the bluetooth_audio module.
68*4d7e907cSAndroid Build Coastguard Worker // @param: cookie - indicates which bluetooth_audio output should handle
69*4d7e907cSAndroid Build Coastguard Worker // @param: start_resp - this report is for startStream or not
70*4d7e907cSAndroid Build Coastguard Worker // @param: status - the result of startStream
71*4d7e907cSAndroid Build Coastguard Worker std::function<void(uint16_t cookie, bool start_resp,
72*4d7e907cSAndroid Build Coastguard Worker const BluetoothAudioStatus& status)>
73*4d7e907cSAndroid Build Coastguard Worker control_result_cb_;
74*4d7e907cSAndroid Build Coastguard Worker // session_changed_cb_ - when the Bluetooth stack start / end session, the
75*4d7e907cSAndroid Build Coastguard Worker // BluetoothAudioProvider will invoke this callback to notify to the
76*4d7e907cSAndroid Build Coastguard Worker // bluetooth_audio module.
77*4d7e907cSAndroid Build Coastguard Worker // @param: cookie - indicates which bluetooth_audio output should handle
78*4d7e907cSAndroid Build Coastguard Worker std::function<void(uint16_t cookie)> session_changed_cb_;
79*4d7e907cSAndroid Build Coastguard Worker };
80*4d7e907cSAndroid Build Coastguard Worker
81*4d7e907cSAndroid Build Coastguard Worker class BluetoothAudioSession {
82*4d7e907cSAndroid Build Coastguard Worker friend class BluetoothAudioSession_2_1;
83*4d7e907cSAndroid Build Coastguard Worker friend class BluetoothAudioSession_2_2;
84*4d7e907cSAndroid Build Coastguard Worker
85*4d7e907cSAndroid Build Coastguard Worker private:
86*4d7e907cSAndroid Build Coastguard Worker // using recursive_mutex to allow hwbinder to re-enter agian.
87*4d7e907cSAndroid Build Coastguard Worker std::recursive_mutex mutex_;
88*4d7e907cSAndroid Build Coastguard Worker SessionType session_type_;
89*4d7e907cSAndroid Build Coastguard Worker
90*4d7e907cSAndroid Build Coastguard Worker // audio control path to use for both software and offloading
91*4d7e907cSAndroid Build Coastguard Worker sp<IBluetoothAudioPort> stack_iface_;
92*4d7e907cSAndroid Build Coastguard Worker // audio data path (FMQ) for software encoding
93*4d7e907cSAndroid Build Coastguard Worker std::unique_ptr<DataMQ> mDataMQ;
94*4d7e907cSAndroid Build Coastguard Worker // audio data configuration for both software and offloading
95*4d7e907cSAndroid Build Coastguard Worker AudioConfiguration audio_config_;
96*4d7e907cSAndroid Build Coastguard Worker
97*4d7e907cSAndroid Build Coastguard Worker static AudioConfiguration invalidSoftwareAudioConfiguration;
98*4d7e907cSAndroid Build Coastguard Worker static AudioConfiguration invalidOffloadAudioConfiguration;
99*4d7e907cSAndroid Build Coastguard Worker
100*4d7e907cSAndroid Build Coastguard Worker // saving those registered bluetooth_audio's callbacks
101*4d7e907cSAndroid Build Coastguard Worker std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks>>
102*4d7e907cSAndroid Build Coastguard Worker observers_;
103*4d7e907cSAndroid Build Coastguard Worker
104*4d7e907cSAndroid Build Coastguard Worker bool UpdateDataPath(const DataMQ::Descriptor* dataMQ);
105*4d7e907cSAndroid Build Coastguard Worker bool UpdateAudioConfig(const AudioConfiguration& audio_config);
106*4d7e907cSAndroid Build Coastguard Worker // invoking the registered session_changed_cb_
107*4d7e907cSAndroid Build Coastguard Worker void ReportSessionStatus();
108*4d7e907cSAndroid Build Coastguard Worker
109*4d7e907cSAndroid Build Coastguard Worker public:
110*4d7e907cSAndroid Build Coastguard Worker BluetoothAudioSession(const SessionType& session_type);
111*4d7e907cSAndroid Build Coastguard Worker
112*4d7e907cSAndroid Build Coastguard Worker // The function helps to check if this session is ready or not
113*4d7e907cSAndroid Build Coastguard Worker // @return: true if the Bluetooth stack has started the specified session
114*4d7e907cSAndroid Build Coastguard Worker bool IsSessionReady();
115*4d7e907cSAndroid Build Coastguard Worker
116*4d7e907cSAndroid Build Coastguard Worker // The report function is used to report that the Bluetooth stack has started
117*4d7e907cSAndroid Build Coastguard Worker // this session without any failure, and will invoke session_changed_cb_ to
118*4d7e907cSAndroid Build Coastguard Worker // notify those registered bluetooth_audio outputs
119*4d7e907cSAndroid Build Coastguard Worker void OnSessionStarted(const sp<IBluetoothAudioPort> stack_iface,
120*4d7e907cSAndroid Build Coastguard Worker const DataMQ::Descriptor* dataMQ,
121*4d7e907cSAndroid Build Coastguard Worker const AudioConfiguration& audio_config);
122*4d7e907cSAndroid Build Coastguard Worker
123*4d7e907cSAndroid Build Coastguard Worker // The report function is used to report that the Bluetooth stack has ended
124*4d7e907cSAndroid Build Coastguard Worker // the session, and will invoke session_changed_cb_ to notify registered
125*4d7e907cSAndroid Build Coastguard Worker // bluetooth_audio outputs
126*4d7e907cSAndroid Build Coastguard Worker void OnSessionEnded();
127*4d7e907cSAndroid Build Coastguard Worker
128*4d7e907cSAndroid Build Coastguard Worker // The report function is used to report that the Bluetooth stack has notified
129*4d7e907cSAndroid Build Coastguard Worker // the result of startStream or suspendStream, and will invoke
130*4d7e907cSAndroid Build Coastguard Worker // control_result_cb_ to notify registered bluetooth_audio outputs
131*4d7e907cSAndroid Build Coastguard Worker void ReportControlStatus(bool start_resp, const BluetoothAudioStatus& status);
132*4d7e907cSAndroid Build Coastguard Worker
133*4d7e907cSAndroid Build Coastguard Worker // The control function helps the bluetooth_audio module to register
134*4d7e907cSAndroid Build Coastguard Worker // PortStatusCallbacks
135*4d7e907cSAndroid Build Coastguard Worker // @return: cookie - the assigned number to this bluetooth_audio output
136*4d7e907cSAndroid Build Coastguard Worker uint16_t RegisterStatusCback(const PortStatusCallbacks& cbacks);
137*4d7e907cSAndroid Build Coastguard Worker
138*4d7e907cSAndroid Build Coastguard Worker // The control function helps the bluetooth_audio module to unregister
139*4d7e907cSAndroid Build Coastguard Worker // PortStatusCallbacks
140*4d7e907cSAndroid Build Coastguard Worker // @param: cookie - indicates which bluetooth_audio output is
141*4d7e907cSAndroid Build Coastguard Worker void UnregisterStatusCback(uint16_t cookie);
142*4d7e907cSAndroid Build Coastguard Worker
143*4d7e907cSAndroid Build Coastguard Worker // The control function is for the bluetooth_audio module to get the current
144*4d7e907cSAndroid Build Coastguard Worker // AudioConfiguration
145*4d7e907cSAndroid Build Coastguard Worker const AudioConfiguration& GetAudioConfig();
146*4d7e907cSAndroid Build Coastguard Worker
147*4d7e907cSAndroid Build Coastguard Worker // Those control functions are for the bluetooth_audio module to start,
148*4d7e907cSAndroid Build Coastguard Worker // suspend, stop stream, to check position, and to update metadata.
149*4d7e907cSAndroid Build Coastguard Worker bool StartStream();
150*4d7e907cSAndroid Build Coastguard Worker bool SuspendStream();
151*4d7e907cSAndroid Build Coastguard Worker void StopStream();
152*4d7e907cSAndroid Build Coastguard Worker bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
153*4d7e907cSAndroid Build Coastguard Worker uint64_t* total_bytes_readed,
154*4d7e907cSAndroid Build Coastguard Worker timespec* data_position);
155*4d7e907cSAndroid Build Coastguard Worker void UpdateTracksMetadata(const struct source_metadata* source_metadata);
156*4d7e907cSAndroid Build Coastguard Worker
157*4d7e907cSAndroid Build Coastguard Worker // The control function writes stream to FMQ
158*4d7e907cSAndroid Build Coastguard Worker size_t OutWritePcmData(const void* buffer, size_t bytes);
159*4d7e907cSAndroid Build Coastguard Worker // The control function read stream from FMQ
160*4d7e907cSAndroid Build Coastguard Worker size_t InReadPcmData(void* buffer, size_t bytes);
161*4d7e907cSAndroid Build Coastguard Worker
162*4d7e907cSAndroid Build Coastguard Worker static constexpr PcmParameters kInvalidPcmParameters = {
163*4d7e907cSAndroid Build Coastguard Worker .sampleRate = SampleRate::RATE_UNKNOWN,
164*4d7e907cSAndroid Build Coastguard Worker .channelMode = ChannelMode::UNKNOWN,
165*4d7e907cSAndroid Build Coastguard Worker .bitsPerSample = BitsPerSample::BITS_UNKNOWN,
166*4d7e907cSAndroid Build Coastguard Worker };
167*4d7e907cSAndroid Build Coastguard Worker // can't be constexpr because of non-literal type
168*4d7e907cSAndroid Build Coastguard Worker static const CodecConfiguration kInvalidCodecConfiguration;
169*4d7e907cSAndroid Build Coastguard Worker
170*4d7e907cSAndroid Build Coastguard Worker static constexpr AudioConfiguration& kInvalidSoftwareAudioConfiguration =
171*4d7e907cSAndroid Build Coastguard Worker invalidSoftwareAudioConfiguration;
172*4d7e907cSAndroid Build Coastguard Worker static constexpr AudioConfiguration& kInvalidOffloadAudioConfiguration =
173*4d7e907cSAndroid Build Coastguard Worker invalidOffloadAudioConfiguration;
174*4d7e907cSAndroid Build Coastguard Worker };
175*4d7e907cSAndroid Build Coastguard Worker
176*4d7e907cSAndroid Build Coastguard Worker class BluetoothAudioSessionInstance {
177*4d7e907cSAndroid Build Coastguard Worker public:
178*4d7e907cSAndroid Build Coastguard Worker // The API is to fetch the specified session of A2DP / Hearing Aid
179*4d7e907cSAndroid Build Coastguard Worker static std::shared_ptr<BluetoothAudioSession> GetSessionInstance(
180*4d7e907cSAndroid Build Coastguard Worker const SessionType& session_type);
181*4d7e907cSAndroid Build Coastguard Worker
182*4d7e907cSAndroid Build Coastguard Worker private:
183*4d7e907cSAndroid Build Coastguard Worker static std::unique_ptr<BluetoothAudioSessionInstance> instance_ptr;
184*4d7e907cSAndroid Build Coastguard Worker std::mutex mutex_;
185*4d7e907cSAndroid Build Coastguard Worker std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
186*4d7e907cSAndroid Build Coastguard Worker sessions_map_;
187*4d7e907cSAndroid Build Coastguard Worker };
188*4d7e907cSAndroid Build Coastguard Worker
189*4d7e907cSAndroid Build Coastguard Worker } // namespace audio
190*4d7e907cSAndroid Build Coastguard Worker } // namespace bluetooth
191*4d7e907cSAndroid Build Coastguard Worker } // namespace android
192