1 /*
2 * Copyright (c) 2024 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 #ifndef LOG_TAG
16 #define LOG_TAG "NoneMixEngine"
17 #endif
18
19 #include "audio_common_converter.h"
20 #include "audio_errors.h"
21 #include "audio_service_log.h"
22 #include "audio_utils.h"
23 #include "none_mix_engine.h"
24
25 namespace OHOS {
26 namespace AudioStandard {
27 constexpr int32_t DELTA_TIME = 4000000; // 4ms
28 constexpr int32_t PERIOD_NS = 20000000; // 20ms
29 constexpr int32_t FADING_MS = 20; // 20ms
30 constexpr int32_t MAX_ERROR_COUNT = 50;
31 constexpr int16_t STEREO_CHANNEL_COUNT = 2;
32 constexpr int16_t HDI_STEREO_CHANNEL_LAYOUT = 3;
33 constexpr int16_t HDI_MONO_CHANNEL_LAYOUT = 4;
34 constexpr int32_t DIRECT_STOP_TIMEOUT_IN_SEC = 8; // 8S
35 const std::string THREAD_NAME = "noneMixThread";
36 const std::string VOIP_SINK_NAME = "voip";
37 const std::string DIRECT_SINK_NAME = "direct";
38 const char *SINK_ADAPTER_NAME = "primary";
39 static const int32_t XCOLLIE_FLAG_DEFAULT = (1 | 2); // dump stack and kill self
40
NoneMixEngine()41 NoneMixEngine::NoneMixEngine()
42 : isVoip_(false),
43 isStart_(false),
44 isInit_(false),
45 failedCount_(0),
46 writeCount_(0),
47 fwkSyncTime_(0),
48 stream_(nullptr),
49 startFadein_(false),
50 startFadeout_(false),
51 uChannel_(0),
52 uFormat_(sizeof(int32_t)),
53 uSampleRate_(0)
54 {
55 AUDIO_INFO_LOG("Constructor");
56 }
57
~NoneMixEngine()58 NoneMixEngine::~NoneMixEngine()
59 {
60 writeCount_ = 0;
61 failedCount_ = 0;
62 fwkSyncTime_ = 0;
63 if (playbackThread_) {
64 playbackThread_->Stop();
65 playbackThread_ = nullptr;
66 }
67 if (renderSink_ && renderSink_->IsInited()) {
68 renderSink_->Stop();
69 renderSink_->DeInit();
70 renderSink_ = nullptr;
71 }
72 isStart_ = false;
73 startFadein_ = false;
74 startFadeout_ = false;
75 }
76
Init(const DeviceInfo & type,bool isVoip)77 int32_t NoneMixEngine::Init(const DeviceInfo &type, bool isVoip)
78 {
79 if (!isInit_) {
80 isVoip_ = isVoip;
81 device_ = type;
82 return SUCCESS;
83 }
84 if (type.deviceType != device_.deviceType || isVoip_ != isVoip) {
85 isVoip_ = isVoip;
86 device_ = type;
87 if (renderSink_ && renderSink_->IsInited()) {
88 renderSink_->Stop();
89 renderSink_->DeInit();
90 }
91 renderSink_ = nullptr;
92 }
93 return SUCCESS;
94 }
95
Start()96 int32_t NoneMixEngine::Start()
97 {
98 AUDIO_INFO_LOG("Enter in");
99 int32_t ret = SUCCESS;
100 CHECK_AND_RETURN_RET_LOG(renderSink_ != nullptr, ERR_INVALID_HANDLE, "null sink");
101 CHECK_AND_RETURN_RET_LOG(renderSink_->IsInited(), ERR_NOT_STARTED, "sink Not Inited! Init the sink first");
102 fwkSyncTime_ = static_cast<uint64_t>(ClockTime::GetCurNano());
103 writeCount_ = 0;
104 failedCount_ = 0;
105 if (!playbackThread_) {
106 playbackThread_ = std::make_unique<AudioThreadTask>(THREAD_NAME);
107 playbackThread_->RegisterJob([this] { this->MixStreams(); });
108 }
109 if (!isStart_) {
110 startFadeout_ = false;
111 startFadein_ = true;
112 ret = renderSink_->Start();
113 isStart_ = true;
114 }
115 if (!playbackThread_->CheckThreadIsRunning()) {
116 playbackThread_->Start();
117 }
118 return ret;
119 }
120
Stop()121 int32_t NoneMixEngine::Stop()
122 {
123 AUDIO_INFO_LOG("Enter");
124 int32_t ret = SUCCESS;
125 if (!isStart_) {
126 AUDIO_INFO_LOG("already stopped");
127 return ret;
128 }
129 int32_t xCollieFlagDefault = (1 | 2);
130 AudioXCollie audioXCollie(
131 "NoneMixEngine::Stop", DIRECT_STOP_TIMEOUT_IN_SEC,
132 [this](void *) { AUDIO_ERR_LOG("%{public}d stop timeout", isVoip_); }, nullptr, xCollieFlagDefault);
133
134 writeCount_ = 0;
135 failedCount_ = 0;
136 if (playbackThread_) {
137 startFadein_ = false;
138 startFadeout_ = true;
139 // wait until fadeout complete
140 std::unique_lock fadingLock(fadingMutex_);
141 cvFading_.wait_for(
142 fadingLock, std::chrono::milliseconds(FADING_MS), [this] { return (!(startFadein_ || startFadeout_)); });
143 playbackThread_->Stop();
144 playbackThread_ = nullptr;
145 }
146 ret = StopAudioSink();
147 isStart_ = false;
148 return ret;
149 }
150
PauseAsync()151 void NoneMixEngine::PauseAsync()
152 {
153 // stop thread when failed 5 times,do not add logic inside.
154 if (playbackThread_ && playbackThread_->CheckThreadIsRunning()) {
155 playbackThread_->PauseAsync();
156 }
157 int32_t ret = StopAudioSink();
158 if (ret != SUCCESS) {
159 AUDIO_ERR_LOG("sink stop failed.ret:%{public}d", ret);
160 }
161 isStart_ = false;
162 }
163
StopAudioSink()164 int32_t NoneMixEngine::StopAudioSink()
165 {
166 int32_t ret = SUCCESS;
167 if (renderSink_ && renderSink_->IsInited()) {
168 ret = renderSink_->Stop();
169 } else {
170 AUDIO_ERR_LOG("sink is null or not init");
171 }
172 return ret;
173 }
174
Pause()175 int32_t NoneMixEngine::Pause()
176 {
177 AUDIO_INFO_LOG("Enter");
178
179 AudioXCollie audioXCollie(
180 "NoneMixEngine::Pause", DIRECT_STOP_TIMEOUT_IN_SEC,
181 [this](void *) { AUDIO_ERR_LOG("%{public}d pause timeout", isVoip_); }, nullptr, XCOLLIE_FLAG_DEFAULT);
182
183 writeCount_ = 0;
184 failedCount_ = 0;
185 if (playbackThread_) {
186 startFadein_ = false;
187 startFadeout_ = true;
188 // wait until fadeout complete
189 std::unique_lock fadingLock(fadingMutex_);
190 cvFading_.wait_for(
191 fadingLock, std::chrono::milliseconds(FADING_MS), [this] { return (!(startFadein_ || startFadeout_)); });
192 playbackThread_->Pause();
193 }
194 int32_t ret = StopAudioSink();
195 isStart_ = false;
196 return ret;
197 }
198
Flush()199 int32_t NoneMixEngine::Flush()
200 {
201 AUDIO_INFO_LOG("Enter");
202 return SUCCESS;
203 }
204
205 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
206 static void DoFadeInOut(T *dest, size_t count, bool isFadeOut, uint32_t channel)
207 {
208 if (count <= 0) {
209 return;
210 }
211 float fadeStep = 1.0f / count;
212 for (size_t i = 0; i < count; i++) {
213 float fadeFactor;
214 if (isFadeOut) {
215 fadeFactor = 1.0f - ((i + 1) * fadeStep);
216 } else {
217 fadeFactor = (i + 1) * fadeStep;
218 }
219 for (uint32_t j = 0; j < channel; j++) {
220 dest[i * channel + j] *= fadeFactor;
221 }
222 }
223 }
224
DoFadeinOut(bool isFadeOut,char * pBuffer,size_t bufferSize)225 void NoneMixEngine::DoFadeinOut(bool isFadeOut, char *pBuffer, size_t bufferSize)
226 {
227 CHECK_AND_RETURN_LOG(pBuffer != nullptr && bufferSize > 0 && uChannel_ > 0, "buffer is null.");
228 size_t dataLength = bufferSize / (static_cast<uint32_t>(uFormat_) * uChannel_);
229 if (uFormat_ == sizeof(int16_t)) {
230 AUDIO_INFO_LOG("int16 fading frame length:%{public}zu", dataLength);
231 DoFadeInOut(reinterpret_cast<int16_t *>(pBuffer), dataLength, isFadeOut, uChannel_);
232 } else if (uFormat_ == sizeof(int32_t)) {
233 AUDIO_INFO_LOG("int32 fading frame length:%{public}zu", dataLength);
234 DoFadeInOut(reinterpret_cast<int32_t *>(pBuffer), dataLength, isFadeOut, uChannel_);
235 }
236 if (isFadeOut) {
237 startFadeout_.store(false);
238 } else {
239 startFadein_.store(false);
240 }
241 }
242
MixStreams()243 void NoneMixEngine::MixStreams()
244 {
245 if (stream_ == nullptr) {
246 StandbySleep();
247 return;
248 }
249 if (failedCount_ >= MAX_ERROR_COUNT) {
250 AUDIO_WARNING_LOG("failed count is overflow.");
251 PauseAsync();
252 return;
253 }
254 std::vector<char> audioBuffer;
255 int32_t appUid = stream_->GetAudioProcessConfig().appInfo.appUid;
256 int32_t index = -1;
257 int32_t result = stream_->Peek(&audioBuffer, index);
258 writeCount_++;
259 if (index < 0) {
260 AUDIO_WARNING_LOG("peek buffer failed.result:%{public}d,buffer size:%{public}d", result, index);
261 stream_->ReturnIndex(index);
262 failedCount_++;
263 if (startFadeout_) {
264 startFadeout_.store(false);
265 cvFading_.notify_all();
266 return;
267 }
268 ClockTime::RelativeSleep(PERIOD_NS);
269 return;
270 }
271 failedCount_ = 0;
272 uint64_t written = 0;
273 // fade in or fade out
274 if (startFadeout_ || startFadein_) {
275 DoFadeinOut(startFadeout_, audioBuffer.data(), audioBuffer.size());
276 cvFading_.notify_all();
277 }
278 renderSink_->RenderFrame(*audioBuffer.data(), audioBuffer.size(), written);
279 stream_->ReturnIndex(index);
280 renderSink_->UpdateAppsUid({appUid});
281 StandbySleep();
282 }
283
AddRenderer(const std::shared_ptr<IRendererStream> & stream)284 int32_t NoneMixEngine::AddRenderer(const std::shared_ptr<IRendererStream> &stream)
285 {
286 AUDIO_INFO_LOG("Enter add");
287 if (!stream_) {
288 AudioProcessConfig config = stream->GetAudioProcessConfig();
289 int32_t result = InitSink(config.streamInfo);
290 if (result == SUCCESS) {
291 stream_ = stream;
292 isInit_ = true;
293 }
294 return result;
295 } else if (stream->GetStreamIndex() != stream_->GetStreamIndex()) {
296 return ERROR_UNSUPPORTED;
297 }
298 return SUCCESS;
299 }
300
RemoveRenderer(const std::shared_ptr<IRendererStream> & stream)301 void NoneMixEngine::RemoveRenderer(const std::shared_ptr<IRendererStream> &stream)
302 {
303 AUDIO_INFO_LOG("step in remove");
304 if (stream_ == nullptr) {
305 AUDIO_INFO_LOG("stream already removed.");
306 return;
307 }
308 if (stream->GetStreamIndex() == stream_->GetStreamIndex()) {
309 Stop();
310 stream_ = nullptr;
311 }
312 }
313
IsPlaybackEngineRunning() const314 bool NoneMixEngine::IsPlaybackEngineRunning() const noexcept
315 {
316 return isStart_;
317 }
318
StandbySleep()319 void NoneMixEngine::StandbySleep()
320 {
321 int64_t writeTime = static_cast<int64_t>(fwkSyncTime_) + static_cast<int64_t>(writeCount_) * PERIOD_NS + DELTA_TIME;
322 ClockTime::AbsoluteSleep(writeTime);
323 }
324
GetDirectSampleRate(AudioSamplingRate sampleRate)325 AudioSamplingRate NoneMixEngine::GetDirectSampleRate(AudioSamplingRate sampleRate)
326 {
327 AudioSamplingRate result = sampleRate;
328 switch (sampleRate) {
329 case AudioSamplingRate::SAMPLE_RATE_44100:
330 result = AudioSamplingRate::SAMPLE_RATE_48000;
331 break;
332 case AudioSamplingRate::SAMPLE_RATE_88200:
333 result = AudioSamplingRate::SAMPLE_RATE_96000;
334 break;
335 case AudioSamplingRate::SAMPLE_RATE_176400:
336 result = AudioSamplingRate::SAMPLE_RATE_192000;
337 break;
338 default:
339 break;
340 }
341 AUDIO_INFO_LOG("GetDirectSampleRate: sampleRate: %{public}d, result: %{public}d", sampleRate, result);
342 return result;
343 }
344
GetDirectVoipSampleRate(AudioSamplingRate sampleRate)345 AudioSamplingRate NoneMixEngine::GetDirectVoipSampleRate(AudioSamplingRate sampleRate)
346 {
347 AudioSamplingRate result = sampleRate;
348 if (sampleRate <= AudioSamplingRate::SAMPLE_RATE_16000) {
349 result = AudioSamplingRate::SAMPLE_RATE_16000;
350 } else {
351 result = AudioSamplingRate::SAMPLE_RATE_48000;
352 }
353 AUDIO_INFO_LOG("GetDirectVoipSampleRate: sampleRate: %{public}d, result: %{public}d", sampleRate, result);
354 return result;
355 }
356
GetDirectDeviceFormate(AudioSampleFormat format)357 HdiAdapterFormat NoneMixEngine::GetDirectDeviceFormate(AudioSampleFormat format)
358 {
359 switch (format) {
360 case AudioSampleFormat::SAMPLE_U8:
361 case AudioSampleFormat::SAMPLE_S16LE:
362 return HdiAdapterFormat::SAMPLE_S16;
363 case AudioSampleFormat::SAMPLE_S24LE:
364 case AudioSampleFormat::SAMPLE_S32LE:
365 return HdiAdapterFormat::SAMPLE_S32;
366 case AudioSampleFormat::SAMPLE_F32LE:
367 return HdiAdapterFormat::SAMPLE_F32;
368 default:
369 return HdiAdapterFormat::SAMPLE_S16;
370 }
371 }
372
GetDirectFormatByteSize(HdiAdapterFormat format)373 int32_t NoneMixEngine::GetDirectFormatByteSize(HdiAdapterFormat format)
374 {
375 switch (format) {
376 case HdiAdapterFormat::SAMPLE_S16:
377 return sizeof(int16_t);
378 case HdiAdapterFormat::SAMPLE_S32:
379 case HdiAdapterFormat::SAMPLE_F32:
380 return sizeof(int32_t);
381 default:
382 return sizeof(int32_t);
383 }
384 }
385
InitSink(const AudioStreamInfo & streamInfo)386 int32_t NoneMixEngine::InitSink(const AudioStreamInfo &streamInfo)
387 {
388 uint32_t targetChannel = streamInfo.channels >= STEREO_CHANNEL_COUNT ? STEREO_CHANNEL_COUNT : 1;
389 HdiAdapterFormat format = GetDirectDeviceFormate(streamInfo.format);
390 uint32_t sampleRate =
391 isVoip_ ? GetDirectVoipSampleRate(streamInfo.samplingRate) : GetDirectSampleRate(streamInfo.samplingRate);
392 if (isInit_ && renderSink_) {
393 if (uChannel_ != targetChannel || uFormat_ != format || sampleRate != uSampleRate_) {
394 if (renderSink_ && renderSink_->IsInited()) {
395 renderSink_->Stop();
396 renderSink_->DeInit();
397 }
398 renderSink_ = nullptr;
399 } else {
400 return SUCCESS;
401 }
402 }
403 return InitSink(targetChannel, format, sampleRate);
404 }
405
InitSink(uint32_t channel,HdiAdapterFormat format,uint32_t rate)406 int32_t NoneMixEngine::InitSink(uint32_t channel, HdiAdapterFormat format, uint32_t rate)
407 {
408 std::string sinkName = DIRECT_SINK_NAME;
409 if (isVoip_) {
410 sinkName = VOIP_SINK_NAME;
411 }
412 renderSink_ = AudioRendererSink::GetInstance(sinkName);
413 IAudioSinkAttr attr = {};
414 attr.adapterName = SINK_ADAPTER_NAME;
415 attr.sampleRate = rate;
416 attr.channel = channel;
417 attr.format = format;
418 attr.channelLayout = channel >= STEREO_CHANNEL_COUNT ? HDI_STEREO_CHANNEL_LAYOUT : HDI_MONO_CHANNEL_LAYOUT;
419 attr.deviceType = device_.deviceType;
420 attr.volume = 1.0f;
421 attr.openMicSpeaker = 1;
422 AUDIO_INFO_LOG("sinkName:%{public}s,device:%{public}d,sample rate:%{public}d,format:%{public}d,channel:%{public}d",
423 sinkName.c_str(), attr.deviceType, attr.sampleRate, attr.format, attr.channel);
424 int32_t ret = renderSink_->Init(attr);
425 if (ret != SUCCESS) {
426 return ret;
427 }
428 float volume = 1.0f;
429 ret = renderSink_->SetVolume(volume, volume);
430 uChannel_ = attr.channel;
431 uSampleRate_ = attr.sampleRate;
432 uFormat_ = GetDirectFormatByteSize(attr.format);
433
434 return ret;
435 }
436
SwitchSink(const AudioStreamInfo & streamInfo,bool isVoip)437 int32_t NoneMixEngine::SwitchSink(const AudioStreamInfo &streamInfo, bool isVoip)
438 {
439 Stop();
440 renderSink_->DeInit();
441 isVoip_ = isVoip;
442 return InitSink(streamInfo);
443 }
444 } // namespace AudioStandard
445 } // namespace OHOS
446