• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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