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