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