1 /*
2  * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "a2dp_codec_thread.h"
17 #include <sys/time.h>
18 #include "a2dp_decoder_aac.h"
19 #include "a2dp_encoder_aac.h"
20 #include "a2dp_decoder_sbc.h"
21 #include "a2dp_encoder_sbc.h"
22 #include "log.h"
23 #include "a2dp_service.h"
24 
25 namespace OHOS {
26 namespace bluetooth {
27 const int ENCODE_TIMER_SBC = 20;
28 const int ENCODE_TIMER_AAC = 25;
29 #define PCM_DATA_ENCODED_TIMER(isSbc) ((isSbc) ? ENCODE_TIMER_SBC : ENCODE_TIMER_AAC)
30 A2dpCodecThread *A2dpCodecThread::g_instance = nullptr;
31 std::recursive_mutex g_codecMutex {};
A2dpCodecThread(const std::string & name)32 A2dpCodecThread::A2dpCodecThread(const std::string &name) : name_(name)
33 {
34     LOG_INFO("[A2dpCodecThread]%{public}s\n", __func__);
35     dispatcher_ = std::make_unique<Dispatcher>(name);
36     auto callbackFunc = std::bind(&A2dpCodecThread::SignalingTimeoutCallback, this);
37     signalingTimer_ = std::make_unique<utility::Timer>(callbackFunc);
38 }
39 
~A2dpCodecThread()40 A2dpCodecThread::~A2dpCodecThread()
41 {
42     encoder_ = nullptr;
43     decoder_ = nullptr;
44     signalingTimer_ = nullptr;
45     dispatcher_ = nullptr;
46     g_instance = nullptr;
47     isSbc_ = false;
48 }
49 
PostMessage(const utility::Message msg,const A2dpEncoderInitPeerParams & peerParams,A2dpCodecConfig * config,A2dpDecoderObserver * decObserver) const50 bool A2dpCodecThread::PostMessage(const utility::Message msg, const A2dpEncoderInitPeerParams &peerParams,
51     A2dpCodecConfig *config, A2dpDecoderObserver *decObserver) const
52 {
53     dispatcher_->PostTask(
54         std::bind(&A2dpCodecThread::ProcessMessage, g_instance, msg, peerParams, config, decObserver));
55 
56     return true;
57 }
58 
GetInstance()59 A2dpCodecThread *A2dpCodecThread::GetInstance()
60 {
61     LOG_INFO("[A2dpCodecThread]%{public}s\n", __func__);
62     std::lock_guard<std::recursive_mutex> lock(g_codecMutex);
63     if (g_instance == nullptr) {
64         auto instance = std::make_unique<A2dpCodecThread>("a2dpCodec");
65         g_instance = instance.release();
66     }
67     return g_instance;
68 }
69 
StartA2dpCodecThread()70 void A2dpCodecThread::StartA2dpCodecThread()
71 {
72     LOG_INFO("[A2dpCodecThread]%{public}s\n", __func__);
73     dispatcher_->Initialize();
74     threadInit = true;
75 }
76 
StopA2dpCodecThread()77 void A2dpCodecThread::StopA2dpCodecThread()
78 {
79     LOG_INFO("[A2dpCodecThread]%{public}s\n", __func__);
80 
81     dispatcher_->Uninitialize();
82 
83     if (signalingTimer_ != nullptr) {
84         signalingTimer_->Stop();
85     }
86     threadInit = false;
87 }
88 
ProcessMessage(utility::Message msg,const A2dpEncoderInitPeerParams & peerParams,A2dpCodecConfig * config,A2dpDecoderObserver * decObserver)89 void A2dpCodecThread::ProcessMessage(utility::Message msg, const A2dpEncoderInitPeerParams &peerParams,
90     A2dpCodecConfig *config, A2dpDecoderObserver *decObserver)
91 {
92     LOG_INFO("[A2dpCodecThread]%{public}s msg is %{public}d\n", __func__, msg.what_);
93     struct timeval tv = {};
94     struct timezone tz = {};
95     gettimeofday(&tv, &tz);
96     std::lock_guard<std::recursive_mutex> lock(g_codecMutex);
97     switch (msg.what_) {
98         case A2DP_AUDIO_RECONFIGURE:
99             if (encoder_ != nullptr) {
100                 encoder_->UpdateEncoderParam();
101             }
102             break;
103         case A2DP_PCM_PUSH:
104             if (encoder_ != nullptr) {
105                 encoder_->SendFrames(tv.tv_usec);
106             }
107             break;
108         case A2DP_FRAME_READY:
109             if (msg.arg2_ != nullptr && decoder_ != nullptr) {
110                 decoder_->DecodePacket((uint8_t *)msg.arg2_, msg.arg1_);
111             }
112             if (msg.arg2_ != nullptr) {
113                 free((uint8_t *)msg.arg2_);
114             }
115             break;
116         case A2DP_PCM_ENCODED:
117             if (config == nullptr) {
118                 return;
119             }
120             if (encoder_ != nullptr) {
121                 A2dpEncoder* encoder = encoder_.release();
122                 delete encoder;
123             }
124             SourceEncode(peerParams, *config);
125             break;
126         case A2DP_FRAME_DECODED:
127             if (config == nullptr) {
128                 return;
129             }
130             if (decoder_ != nullptr) {
131                 A2dpDecoder* decoder = decoder_.release();
132                 delete decoder;
133             }
134             SinkDecode(*config, *decObserver);
135             break;
136         default:
137             break;
138     }
139 }
140 
StartTimer() const141 void A2dpCodecThread::StartTimer() const
142 {
143     LOG_INFO("[A2dpCodecThread]%{public}s\n", __func__);
144     if (signalingTimer_ != nullptr) {
145         signalingTimer_->Start(PCM_DATA_ENCODED_TIMER(isSbc_), true);
146     }
147 }
148 
StopTimer() const149 void A2dpCodecThread::StopTimer() const
150 {
151     LOG_INFO("[A2dpCodecThread]%{public}s\n", __func__);
152     if (signalingTimer_ != nullptr) {
153         signalingTimer_->Stop();
154     }
155     if (encoder_ != nullptr) {
156         encoder_->ResetFeedingState();
157     }
158 }
159 
GetInitStatus() const160 bool A2dpCodecThread::GetInitStatus() const
161 {
162     return threadInit;
163 }
164 
165 
GetRenderPosition(uint64_t & sendDataSize,uint32_t & timeStamp) const166 void A2dpCodecThread::GetRenderPosition(uint64_t &sendDataSize, uint32_t &timeStamp) const
167 {
168     LOG_INFO("[A2dpCodecThread]%{public}s\n", __func__);
169     if (encoder_ != nullptr) {
170         encoder_->GetRenderPosition(sendDataSize, timeStamp);
171     }
172 }
173 
SourceEncode(const A2dpEncoderInitPeerParams & peerParams,const A2dpCodecConfig & config)174 void A2dpCodecThread::SourceEncode(
175     const A2dpEncoderInitPeerParams &peerParams, const A2dpCodecConfig &config)
176 {
177     LOG_INFO("[A2dpCodecThread]%{public}s index:%u\n", __func__, config.GetCodecIndex());
178     switch (config.GetCodecIndex()) {
179         case A2DP_SINK_CODEC_INDEX_SBC:
180         case A2DP_SOURCE_CODEC_INDEX_SBC:
181             isSbc_ = true;
182             encoder_ = std::make_unique<A2dpSbcEncoder>(&const_cast<A2dpEncoderInitPeerParams &>(peerParams),
183                 &const_cast<A2dpCodecConfig &>(config));
184             if (signalingTimer_ != nullptr) {
185                 signalingTimer_->Stop();
186                 signalingTimer_->Start(PCM_DATA_ENCODED_TIMER(isSbc_), true);
187             }
188             break;
189         case A2DP_SOURCE_CODEC_INDEX_AAC:
190         case A2DP_SINK_CODEC_INDEX_AAC:
191             isSbc_ = false;
192             encoder_ = std::make_unique<A2dpAacEncoder>(&const_cast<A2dpEncoderInitPeerParams &>(peerParams),
193                 &const_cast<A2dpCodecConfig &>(config));
194             if (signalingTimer_ != nullptr) {
195                 signalingTimer_->Stop();
196                 signalingTimer_->Start(PCM_DATA_ENCODED_TIMER(isSbc_), true);
197             }
198             break;
199         default:
200             break;
201     }
202 }
203 
SignalingTimeoutCallback() const204 void A2dpCodecThread::SignalingTimeoutCallback() const
205 {
206     LOG_INFO("[A2dpCodecThread]%{public}s", __func__);
207     A2dpProfile *profile = GetProfileInstance(A2DP_ROLE_SOURCE);
208     profile->DequeuePacket();
209     utility::Message msg(A2DP_PCM_PUSH, 0, nullptr);
210     A2dpEncoderInitPeerParams peerParams = {};
211     PostMessage(msg, peerParams, nullptr, nullptr);
212 }
213 
SinkDecode(const A2dpCodecConfig & config,A2dpDecoderObserver & observer)214 void A2dpCodecThread::SinkDecode(const A2dpCodecConfig &config, A2dpDecoderObserver &observer)
215 {
216     LOG_INFO("[A2dpCodecThread]%{public}s index:%u\n", __func__, config.GetCodecIndex());
217 
218     switch (config.GetCodecIndex()) {
219         case A2DP_SINK_CODEC_INDEX_SBC:
220         case A2DP_SOURCE_CODEC_INDEX_SBC:
221             if (decoder_ == nullptr) {
222                 decoder_ = std::make_unique<A2dpSbcDecoder>(&observer);
223             }
224             break;
225         case A2DP_SOURCE_CODEC_INDEX_AAC:
226         case A2DP_SINK_CODEC_INDEX_AAC:
227             if (decoder_ == nullptr) {
228                 decoder_ = std::make_unique<A2dpAacDecoder>(&observer);
229             }
230 
231             break;
232         default:
233             break;
234     }
235 }
236 }  // namespace bluetooth
237 }  // namespace OHOS
238