1 /*
2 * Copyright (c) 2025 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 "DirectPlayBackEngine"
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 "common/hdi_adapter_info.h"
24 #include "direct_playback_engine.h"
25 #include "manager/hdi_adapter_manager.h"
26 #include "sink/i_audio_render_sink.h"
27 #include "audio_performance_monitor.h"
28 #include "audio_volume.h"
29 #include "format_converter.h"
30 #include "audio_service.h"
31
32 namespace OHOS {
33 namespace AudioStandard {
34 static constexpr int32_t MAX_FAILURE_NUM = 50;
35 static constexpr int32_t DIRECT_STOP_TIMEOUT_IN_SEC = 8; // 8S
36 static const std::string EAC3_SINK_NAME = "eac3";
37 static const char *PRIMARY_ADAPTER_TYPE = "primary";
38
DirectPlayBackEngine()39 DirectPlayBackEngine::DirectPlayBackEngine()
40 : isStart_(false),
41 isInit_(false),
42 failedCount_(0),
43 latency_(0),
44 stream_(nullptr),
45 uChannel_(0),
46 format_(sizeof(int32_t)),
47 uSampleRate_(0)
48 {
49 AUDIO_INFO_LOG("Constructor");
50 }
51
~DirectPlayBackEngine()52 DirectPlayBackEngine::~DirectPlayBackEngine()
53 {
54 failedCount_ = 0;
55 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
56 if (sink && sink->IsInited()) {
57 sink->Stop();
58 sink->DeInit();
59 }
60 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
61 isStart_ = false;
62 }
63
Init(const AudioDeviceDescriptor & type,bool isVoip)64 int32_t DirectPlayBackEngine::Init(const AudioDeviceDescriptor &type, bool isVoip)
65 {
66 if (!isInit_) {
67 device_ = type;
68 return SUCCESS;
69 }
70 if (type.deviceType_ != device_.deviceType_) {
71 device_ = type;
72 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
73 if (sink && sink->IsInited()) {
74 sink->Stop();
75 sink->DeInit();
76 }
77 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
78 }
79 return SUCCESS;
80 }
81
Start()82 int32_t DirectPlayBackEngine::Start()
83 {
84 AUDIO_INFO_LOG("Enter in");
85 int32_t ret = SUCCESS;
86 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
87 CHECK_AND_RETURN_RET_LOG(sink != nullptr, ERR_INVALID_HANDLE, "null sink!");
88 CHECK_AND_RETURN_RET_LOG(sink->IsInited(), ERR_NOT_STARTED, "sink Not Inited! Init the sink first!");
89 failedCount_ = 0;
90 latency_ = 0;
91 if (!isStart_) {
92 ret = sink->Start();
93 isStart_ = true;
94 }
95 return ret;
96 }
97
Stop()98 int32_t DirectPlayBackEngine::Stop()
99 {
100 AUDIO_INFO_LOG("Enter");
101 int32_t ret = SUCCESS;
102 if (!isStart_) {
103 AUDIO_INFO_LOG("already stopped");
104 return ret;
105 }
106 AudioXCollie audioXCollie(
107 "DirectPlayBackEngine::Stop", DIRECT_STOP_TIMEOUT_IN_SEC,
108 [](void *) { AUDIO_ERR_LOG("stop timeout"); }, nullptr,
109 AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
110 failedCount_ = 0;
111 ret = StopAudioSink();
112 isStart_ = false;
113 return ret;
114 }
115
StopAudioSink()116 int32_t DirectPlayBackEngine::StopAudioSink()
117 {
118 int32_t ret = SUCCESS;
119 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
120 if (sink && sink->IsInited()) {
121 ret = sink->Stop();
122 } else {
123 AUDIO_ERR_LOG("sink is null or not init");
124 }
125 return ret;
126 }
127
Pause()128 int32_t DirectPlayBackEngine::Pause()
129 {
130 AUDIO_INFO_LOG("Enter");
131 if (!isStart_) {
132 AUDIO_INFO_LOG("already stopped");
133 return SUCCESS;
134 }
135 AudioXCollie audioXCollie(
136 "DirectPlayBackEngine::Pause", DIRECT_STOP_TIMEOUT_IN_SEC,
137 [](void *) { AUDIO_ERR_LOG("stop timeout"); }, nullptr,
138 AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
139 failedCount_ = 0;
140 int32_t ret = StopAudioSink();
141 isStart_ = false;
142 return ret;
143 }
144
Flush()145 int32_t DirectPlayBackEngine::Flush()
146 {
147 AUDIO_INFO_LOG("Enter");
148 return SUCCESS;
149 }
150
DirectCallback(const RenderCallbackType type)151 void DirectPlayBackEngine::DirectCallback(const RenderCallbackType type)
152 {
153 switch (type) {
154 case CB_NONBLOCK_WRITE_COMPLETED: { //need more data
155 MixStreams();
156 break;
157 }
158 case CB_DRAIN_COMPLETED:
159 case CB_FLUSH_COMPLETED:
160 case CB_RENDER_FULL:
161 case CB_ERROR_OCCUR:
162 break;
163 default:
164 break;
165 }
166 }
167
RegisterWriteCallback()168 int32_t DirectPlayBackEngine::RegisterWriteCallback()
169 {
170 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
171 CHECK_AND_RETURN_RET_LOG(sink != nullptr, ERR_INVALID_HANDLE, "null sink");
172 CHECK_AND_RETURN_RET_LOG(sink->IsInited(), ERR_NOT_STARTED, "sink Not Inited! Init the sink first");
173
174 std::function<void(const RenderCallbackType type)> callback =
175 std::bind(&DirectPlayBackEngine::DirectCallback, this, std::placeholders::_1);
176 return sink->RegistDirectHdiCallback(callback);
177 }
178
DoRenderFrame(std::vector<char> & audioBufferConverted,int32_t index,int32_t appUid)179 void DirectPlayBackEngine::DoRenderFrame(std::vector<char> &audioBufferConverted, int32_t index, int32_t appUid)
180 {
181 uint64_t written = 0;
182 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
183 CHECK_AND_RETURN(sink != nullptr);
184 sink->RenderFrame(*audioBufferConverted.data(), audioBufferConverted.size(), written);
185 CHECK_AND_RETURN(stream_ != nullptr);
186 stream_->ReturnIndex(index);
187 }
188
MixStreams()189 void DirectPlayBackEngine::MixStreams()
190 {
191 if (stream_ == nullptr) {
192 AUDIO_INFO_LOG("stream is nullptr");
193 return;
194 }
195 if (failedCount_ >= MAX_FAILURE_NUM) {
196 AUDIO_WARNING_LOG("failed count is overflow.");
197 return;
198 }
199 std::vector<char> audioBuffer;
200 int32_t appUid = stream_->GetAudioProcessConfig().appInfo.appUid;
201 int32_t index = -1;
202 int32_t result = stream_->Peek(&audioBuffer, index);
203 uint32_t sessionId = stream_->GetStreamIndex();
204 if (index < 0) {
205 AUDIO_WARNING_LOG("peek buffer failed.result:%{public}d,buffer size:%{public}d", result, index);
206 AudioPerformanceMonitor::GetInstance().RecordSilenceState(sessionId, true, PIPE_TYPE_DIRECT_OUT, appUid);
207 stream_->ReturnIndex(index);
208 failedCount_++;
209 return;
210 }
211 AudioPerformanceMonitor::GetInstance().RecordSilenceState(sessionId, false, PIPE_TYPE_DIRECT_OUT, appUid);
212 failedCount_ = 0;
213 DoRenderFrame(audioBuffer, index, appUid);
214 }
215
AddRenderer(const std::shared_ptr<IRendererStream> & stream)216 int32_t DirectPlayBackEngine::AddRenderer(const std::shared_ptr<IRendererStream> &stream)
217 {
218 AUDIO_INFO_LOG("Enter add");
219 CHECK_AND_RETURN_RET_LOG(stream != nullptr, ERR_INVALID_PARAM, "stream is null");
220 if (!stream_) {
221 AudioProcessConfig config = stream->GetAudioProcessConfig();
222 int32_t result = InitSink(config.streamInfo);
223 if (result == SUCCESS) {
224 stream_ = stream;
225 isInit_ = true;
226 RegisterWriteCallback();
227 }
228 return result;
229 } else if (stream->GetStreamIndex() != stream_->GetStreamIndex()) {
230 return ERROR_UNSUPPORTED;
231 }
232 return SUCCESS;
233 }
234
RemoveRenderer(const std::shared_ptr<IRendererStream> & stream)235 void DirectPlayBackEngine::RemoveRenderer(const std::shared_ptr<IRendererStream> &stream)
236 {
237 AUDIO_INFO_LOG("step in remove");
238 CHECK_AND_RETURN_LOG(stream != nullptr, "stream is null");
239 if (stream_ == nullptr) {
240 AUDIO_INFO_LOG("stream already removed.");
241 return;
242 }
243 if (stream->GetStreamIndex() == stream_->GetStreamIndex()) {
244 Stop();
245 stream_ = nullptr;
246 }
247 }
248
IsPlaybackEngineRunning() const249 bool DirectPlayBackEngine::IsPlaybackEngineRunning() const noexcept
250 {
251 return isStart_;
252 }
253
GetDirectFormatByteSize(AudioSampleFormat format)254 int32_t DirectPlayBackEngine::GetDirectFormatByteSize(AudioSampleFormat format)
255 {
256 switch (format) {
257 case AudioSampleFormat::SAMPLE_S16LE:
258 return sizeof(int16_t);
259 case AudioSampleFormat::SAMPLE_S32LE:
260 case AudioSampleFormat::SAMPLE_F32LE:
261 return sizeof(int32_t);
262 default:
263 return sizeof(int32_t);
264 }
265 }
266
InitSink(const AudioStreamInfo & clientStreamInfo)267 int32_t DirectPlayBackEngine::InitSink(const AudioStreamInfo &clientStreamInfo)
268 {
269 uint32_t channel = clientStreamInfo.channels;
270 uint32_t samplingRate = clientStreamInfo.samplingRate;
271 AudioSampleFormat format = clientStreamInfo.format;
272 AudioChannelLayout channelLayout = clientStreamInfo.channelLayout;
273
274 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
275 if (isInit_ && sink) {
276 if (uChannel_ != channel || format_ != format || uSampleRate_ != samplingRate) {
277 if (sink && sink->IsInited()) {
278 sink->Stop();
279 sink->DeInit();
280 }
281 } else {
282 return SUCCESS;
283 }
284 }
285 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
286 return InitSink(channel, format, samplingRate, channelLayout);
287 }
288
InitSink(uint32_t channel,AudioSampleFormat format,uint32_t rate,AudioChannelLayout layout)289 int32_t DirectPlayBackEngine::InitSink(uint32_t channel, AudioSampleFormat format, uint32_t rate,
290 AudioChannelLayout layout)
291 {
292 std::string sinkName = EAC3_SINK_NAME;
293 renderId_ = HdiAdapterManager::GetInstance().GetId(HDI_ID_BASE_RENDER, HDI_ID_TYPE_EAC3, sinkName, true);
294 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_, true);
295 if (sink == nullptr) {
296 AUDIO_ERR_LOG("get render fail, sinkName: %{public}s", sinkName.c_str());
297 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
298 return ERR_INVALID_HANDLE;
299 }
300 IAudioSinkAttr attr = {};
301 attr.adapterName = PRIMARY_ADAPTER_TYPE;
302 attr.sampleRate = rate;
303 attr.channel = channel;
304 attr.format = format;
305 attr.channelLayout = layout;
306 attr.deviceType = device_.deviceType_;
307 attr.volume = 1.0f;
308 attr.openMicSpeaker = 1;
309 AUDIO_INFO_LOG("sinkName:%{public}s,device:%{public}d,sample rate:%{public}d,format:%{public}d,channel:%{public}d",
310 sinkName.c_str(), attr.deviceType, attr.sampleRate, attr.format, attr.channel);
311 int32_t ret = sink->Init(attr);
312 if (ret != SUCCESS) {
313 AUDIO_ERR_LOG("init sink fail, sinkName: %{public}s", sinkName.c_str());
314 return ret;
315 }
316 float volume = 1.0f;
317 ret = sink->SetVolume(volume, volume);
318 uChannel_ = attr.channel;
319 uSampleRate_ = attr.sampleRate;
320 format_ = GetDirectFormatByteSize(attr.format);
321
322 return ret;
323 }
324
GetLatency()325 uint64_t DirectPlayBackEngine::GetLatency() noexcept
326 {
327 return latency_;
328 }
329 } // namespace AudioStandard
330 } // namespace OHOS
331