• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-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 "RendererInClientInner"
17 #endif
18 
19 #include "renderer_in_client.h"
20 #include "renderer_in_client_private.h"
21 
22 #include <atomic>
23 #include <cinttypes>
24 #include <condition_variable>
25 #include <sstream>
26 #include <string>
27 #include <mutex>
28 #include <thread>
29 
30 #include "iservice_registry.h"
31 #include "system_ability_definition.h"
32 #include "securec.h"
33 #include "hisysevent.h"
34 
35 #include "audio_errors.h"
36 #include "audio_policy_manager.h"
37 #include "audio_manager_base.h"
38 #include "audio_renderer_log.h"
39 #include "audio_ring_cache.h"
40 #include "audio_channel_blend.h"
41 #include "audio_server_death_recipient.h"
42 #include "audio_stream_tracker.h"
43 #include "audio_system_manager.h"
44 #include "futex_tool.h"
45 #include "ipc_stream_listener_impl.h"
46 #include "ipc_stream_listener_stub.h"
47 #include "volume_ramp.h"
48 #include "callback_handler.h"
49 #include "audio_speed.h"
50 #include "audio_spatial_channel_converter.h"
51 #include "audio_policy_manager.h"
52 #include "audio_spatialization_manager.h"
53 #include "policy_handler.h"
54 #include "volume_tools.h"
55 
56 #include "media_monitor_manager.h"
57 
58 using namespace OHOS::HiviewDFX;
59 using namespace OHOS::AppExecFwk;
60 
61 namespace OHOS {
62 namespace AudioStandard {
63 namespace {
64 const uint64_t OLD_BUF_DURATION_IN_USEC = 92880; // This value is used for compatibility purposes.
65 const uint64_t AUDIO_US_PER_S = 1000000;
66 const uint64_t MAX_BUF_DURATION_IN_USEC = 2000000; // 2S
67 static const size_t MAX_WRITE_SIZE = 20 * 1024 * 1024; // 20M
68 static const int32_t OPERATION_TIMEOUT_IN_MS = 1000; // 1000ms
69 static const int32_t OFFLOAD_OPERATION_TIMEOUT_IN_MS = 8000; // 8000ms for offload
70 static const int32_t WRITE_CACHE_TIMEOUT_IN_MS = 1500; // 1500ms
71 static const int32_t WRITE_BUFFER_TIMEOUT_IN_MS = 20; // ms
72 static const uint32_t WAIT_FOR_NEXT_CB = 5000; // 5ms
73 static constexpr int32_t ONE_MINUTE = 60;
74 static const int32_t MAX_WRITE_INTERVAL_MS = 40;
75 constexpr int32_t RETRY_WAIT_TIME_MS = 500; // 500ms
76 constexpr int32_t MAX_RETRY_COUNT = 8;
77 } // namespace
78 
79 static AppExecFwk::BundleInfo gBundleInfo_;
80 std::mutex g_serverProxyMutex;
81 sptr<IStandardAudioService> gServerProxy_ = nullptr;
82 
GetAudioServerProxy()83 const sptr<IStandardAudioService> RendererInClientInner::GetAudioServerProxy()
84 {
85     std::lock_guard<std::mutex> lock(g_serverProxyMutex);
86     if (gServerProxy_ == nullptr) {
87         auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
88         if (samgr == nullptr) {
89             AUDIO_ERR_LOG("GetAudioServerProxy: get sa manager failed");
90             return nullptr;
91         }
92         sptr<IRemoteObject> object = samgr->GetSystemAbility(AUDIO_DISTRIBUTED_SERVICE_ID);
93         if (object == nullptr) {
94             AUDIO_ERR_LOG("GetAudioServerProxy: get audio service remote object failed");
95             return nullptr;
96         }
97         gServerProxy_ = iface_cast<IStandardAudioService>(object);
98         if (gServerProxy_ == nullptr) {
99             AUDIO_ERR_LOG("GetAudioServerProxy: get audio service proxy failed");
100             return nullptr;
101         }
102 
103         // register death recipent to restore proxy
104         sptr<AudioServerDeathRecipient> asDeathRecipient =
105             new(std::nothrow) AudioServerDeathRecipient(getpid(), getuid());
106         if (asDeathRecipient != nullptr) {
107             asDeathRecipient->SetNotifyCb([] (pid_t pid, pid_t uid) { AudioServerDied(pid, uid); });
108             bool result = object->AddDeathRecipient(asDeathRecipient);
109             if (!result) {
110                 AUDIO_ERR_LOG("GetAudioServerProxy: failed to add deathRecipient");
111             }
112         }
113     }
114     sptr<IStandardAudioService> gasp = gServerProxy_;
115     return gasp;
116 }
117 
AudioServerDied(pid_t pid,pid_t uid)118 void RendererInClientInner::AudioServerDied(pid_t pid, pid_t uid)
119 {
120     AUDIO_INFO_LOG("audio server died clear proxy, will restore proxy in next call");
121     std::lock_guard<std::mutex> lock(g_serverProxyMutex);
122     gServerProxy_ = nullptr;
123 }
124 
RegisterTracker(const std::shared_ptr<AudioClientTracker> & proxyObj)125 void RendererInClientInner::RegisterTracker(const std::shared_ptr<AudioClientTracker> &proxyObj)
126 {
127     if (audioStreamTracker_ && audioStreamTracker_.get() && !streamTrackerRegistered_) {
128         // make sure sessionId_ is valid.
129         AUDIO_INFO_LOG("Calling register tracker, sessionid is %{public}d", sessionId_);
130         AudioRegisterTrackerInfo registerTrackerInfo;
131 
132         rendererInfo_.samplingRate = static_cast<AudioSamplingRate>(curStreamParams_.samplingRate);
133         rendererInfo_.format = static_cast<AudioSampleFormat>(curStreamParams_.format);
134         registerTrackerInfo.sessionId = sessionId_;
135         registerTrackerInfo.clientPid = clientPid_;
136         registerTrackerInfo.state = state_;
137         registerTrackerInfo.rendererInfo = rendererInfo_;
138         registerTrackerInfo.capturerInfo = capturerInfo_;
139         registerTrackerInfo.channelCount = curStreamParams_.channels;
140 
141         audioStreamTracker_->RegisterTracker(registerTrackerInfo, proxyObj);
142         streamTrackerRegistered_ = true;
143     }
144 }
145 
UpdateTracker(const std::string & updateCase)146 void RendererInClientInner::UpdateTracker(const std::string &updateCase)
147 {
148     if (audioStreamTracker_ && audioStreamTracker_.get()) {
149         AUDIO_DEBUG_LOG("Renderer:Calling Update tracker for %{public}s", updateCase.c_str());
150         audioStreamTracker_->UpdateTracker(sessionId_, state_, clientPid_, rendererInfo_, capturerInfo_);
151     }
152 }
153 
IsHighResolution() const154 bool RendererInClientInner::IsHighResolution() const noexcept
155 {
156     return eStreamType_ == STREAM_MUSIC && curStreamParams_.samplingRate >= SAMPLE_RATE_48000 &&
157            curStreamParams_.format >= SAMPLE_S24LE;
158 }
159 
InitDirectPipeType()160 void RendererInClientInner::InitDirectPipeType()
161 {
162     if (rendererInfo_.rendererFlags == AUDIO_FLAG_VOIP_DIRECT || IsHighResolution()) {
163         AudioPipeType originType = rendererInfo_.pipeType;
164         int32_t type = ipcStream_->GetStreamManagerType();
165         if (type == AUDIO_DIRECT_MANAGER_TYPE) {
166             rendererInfo_.pipeType = (rendererInfo_.rendererFlags == AUDIO_FLAG_VOIP_DIRECT) ?
167                 PIPE_TYPE_CALL_OUT : PIPE_TYPE_DIRECT_MUSIC;
168         } else if (originType == PIPE_TYPE_DIRECT_MUSIC) {
169             rendererInfo_.pipeType = PIPE_TYPE_NORMAL_OUT;
170         }
171     }
172 }
173 
174 // call this without lock, we should be able to call deinit in any case.
DeinitIpcStream()175 int32_t RendererInClientInner::DeinitIpcStream()
176 {
177     Trace trace("RendererInClientInner::DeinitIpcStream");
178     ipcStream_->Release();
179     ringCache_->ResetBuffer();
180     return SUCCESS;
181 }
182 
ConstructConfig()183 const AudioProcessConfig RendererInClientInner::ConstructConfig()
184 {
185     AudioProcessConfig config = {};
186 
187     config.appInfo.appPid = clientPid_;
188     config.appInfo.appUid = clientUid_;
189     config.appInfo.appTokenId = appTokenId_;
190     config.appInfo.appFullTokenId = fullTokenId_;
191 
192     config.streamInfo.channels = static_cast<AudioChannel>(curStreamParams_.channels);
193     config.streamInfo.encoding = static_cast<AudioEncodingType>(curStreamParams_.encoding);
194     config.streamInfo.format = static_cast<AudioSampleFormat>(curStreamParams_.format);
195     config.streamInfo.samplingRate = static_cast<AudioSamplingRate>(curStreamParams_.samplingRate);
196     config.streamInfo.channelLayout = static_cast<AudioChannelLayout>(curStreamParams_.channelLayout);
197     config.originalSessionId = curStreamParams_.originalSessionId;
198 
199     config.audioMode = AUDIO_MODE_PLAYBACK;
200 
201     if (rendererInfo_.rendererFlags != AUDIO_FLAG_NORMAL && rendererInfo_.rendererFlags != AUDIO_FLAG_VOIP_DIRECT) {
202         AUDIO_WARNING_LOG("ConstructConfig find renderer flag invalid:%{public}d", rendererInfo_.rendererFlags);
203         rendererInfo_.rendererFlags = 0;
204     }
205     config.rendererInfo = rendererInfo_;
206 
207     config.capturerInfo = {};
208 
209     config.streamType = eStreamType_;
210 
211     config.deviceType = AudioPolicyManager::GetInstance().GetActiveOutputDevice();
212 
213     config.privacyType = privacyType_;
214 
215     clientConfig_ = config;
216 
217     return config;
218 }
219 
InitSharedBuffer()220 int32_t RendererInClientInner::InitSharedBuffer()
221 {
222     CHECK_AND_RETURN_RET_LOG(ipcStream_ != nullptr, ERR_OPERATION_FAILED, "InitSharedBuffer failed, null ipcStream_.");
223     int32_t ret = ipcStream_->ResolveBuffer(clientBuffer_);
224 
225     CHECK_AND_RETURN_RET_LOG(ret == SUCCESS && clientBuffer_ != nullptr, ret, "ResolveBuffer failed:%{public}d", ret);
226 
227     uint32_t totalSizeInFrame = 0;
228     uint32_t byteSizePerFrame = 0;
229     ret = clientBuffer_->GetSizeParameter(totalSizeInFrame, spanSizeInFrame_, byteSizePerFrame);
230 
231     CHECK_AND_RETURN_RET_LOG(ret == SUCCESS && byteSizePerFrame == sizePerFrameInByte_, ret, "GetSizeParameter failed"
232         ":%{public}d, byteSizePerFrame:%{public}u, sizePerFrameInByte_:%{public}zu", ret, byteSizePerFrame,
233         sizePerFrameInByte_);
234 
235     clientSpanSizeInByte_ = spanSizeInFrame_ * byteSizePerFrame;
236 
237     AUDIO_INFO_LOG("totalSizeInFrame_[%{public}u] spanSizeInFrame[%{public}u] sizePerFrameInByte_[%{public}zu]"
238         "clientSpanSizeInByte_[%{public}zu]", totalSizeInFrame, spanSizeInFrame_, sizePerFrameInByte_,
239         clientSpanSizeInByte_);
240 
241     return SUCCESS;
242 }
243 
244 // InitCacheBuffer should be able to modify the cache size between clientSpanSizeInByte_ and 4 * clientSpanSizeInByte_
InitCacheBuffer(size_t targetSize)245 int32_t RendererInClientInner::InitCacheBuffer(size_t targetSize)
246 {
247     CHECK_AND_RETURN_RET_LOG(clientSpanSizeInByte_ != 0, ERR_OPERATION_FAILED, "clientSpanSizeInByte_ invalid");
248 
249     AUDIO_INFO_LOG("old size:%{public}zu, new size:%{public}zu", cacheSizeInByte_, targetSize);
250     cacheSizeInByte_ = targetSize;
251 
252     if (ringCache_ == nullptr) {
253         ringCache_ = AudioRingCache::Create(cacheSizeInByte_);
254     } else {
255         OptResult result = ringCache_->ReConfig(cacheSizeInByte_, false); // false --> clear buffer
256         if (result.ret != OPERATION_SUCCESS) {
257             AUDIO_ERR_LOG("ReConfig AudioRingCache to size %{public}u failed:ret%{public}zu", result.ret, targetSize);
258             return ERR_OPERATION_FAILED;
259         }
260     }
261 
262     return SUCCESS;
263 }
264 
InitIpcStream()265 int32_t RendererInClientInner::InitIpcStream()
266 {
267     Trace trace("RendererInClientInner::InitIpcStream");
268     AudioProcessConfig config = ConstructConfig();
269     bool resetSilentMode = (gServerProxy_ == nullptr) ? true : false;
270     sptr<IStandardAudioService> gasp = RendererInClientInner::GetAudioServerProxy();
271     CHECK_AND_RETURN_RET_LOG(gasp != nullptr, ERR_OPERATION_FAILED, "Create failed, can not get service.");
272     int32_t errorCode = 0;
273     sptr<IRemoteObject> ipcProxy = gasp->CreateAudioProcess(config, errorCode);
274     for (int32_t retrycount = 0; (errorCode == ERR_RETRY_IN_CLIENT) && (retrycount < MAX_RETRY_COUNT); retrycount++) {
275         AUDIO_WARNING_LOG("retry in client");
276         std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_WAIT_TIME_MS));
277         ipcProxy = gasp->CreateAudioProcess(config, errorCode);
278     }
279     CHECK_AND_RETURN_RET_LOG(ipcProxy != nullptr, ERR_OPERATION_FAILED, "failed with null ipcProxy.");
280     ipcStream_ = iface_cast<IpcStream>(ipcProxy);
281     CHECK_AND_RETURN_RET_LOG(ipcStream_ != nullptr, ERR_OPERATION_FAILED, "failed when iface_cast.");
282 
283     // in plan next: old listener_ is destoried here, will server receive dieth notify?
284     listener_ = sptr<IpcStreamListenerImpl>::MakeSptr(shared_from_this());
285     int32_t ret = ipcStream_->RegisterStreamListener(listener_->AsObject());
286     CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "RegisterStreamListener failed:%{public}d", ret);
287 
288     if (resetSilentMode && gServerProxy_ != nullptr && silentModeAndMixWithOthers_) {
289         ipcStream_->SetSilentModeAndMixWithOthers(silentModeAndMixWithOthers_);
290     }
291     ret = InitSharedBuffer();
292     CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "InitSharedBuffer failed:%{public}d", ret);
293 
294     ret = InitCacheBuffer(clientSpanSizeInByte_);
295     CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "InitCacheBuffer failed:%{public}d", ret);
296 
297     ret = ipcStream_->GetAudioSessionID(sessionId_);
298     CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "GetAudioSessionID failed:%{public}d", ret);
299     traceTag_ = "[" + std::to_string(sessionId_) + "]RendererInClient"; // [100001]RendererInClient
300     InitCallbackHandler();
301     return SUCCESS;
302 }
303 
SetInnerVolume(float volume)304 int32_t RendererInClientInner::SetInnerVolume(float volume)
305 {
306     CHECK_AND_RETURN_RET_LOG(clientBuffer_ != nullptr, ERR_OPERATION_FAILED, "buffer is not inited");
307     clientBuffer_->SetStreamVolume(volume);
308     CHECK_AND_RETURN_RET_LOG(ipcStream_ != nullptr, false, "ipcStream is not inited!");
309     int32_t ret = ipcStream_->SetClientVolume();
310     if (ret != SUCCESS) {
311         AUDIO_ERR_LOG("Set Client Volume failed:%{public}u", ret);
312         return ERROR;
313     }
314     AUDIO_PRERELEASE_LOGI("SetClientVolume success, volume: %{public}f", volume);
315     return SUCCESS;
316 }
317 
InitCallbackBuffer(uint64_t bufferDurationInUs)318 void RendererInClientInner::InitCallbackBuffer(uint64_t bufferDurationInUs)
319 {
320     if (bufferDurationInUs > MAX_BUF_DURATION_IN_USEC) {
321         AUDIO_ERR_LOG("InitCallbackBuffer with invalid duration %{public}" PRIu64", use default instead.",
322             bufferDurationInUs);
323         bufferDurationInUs = OLD_BUF_DURATION_IN_USEC;
324     }
325     // Calculate buffer size based on duration.
326 
327     size_t metaSize = 0;
328     if (curStreamParams_.encoding == ENCODING_AUDIOVIVID) {
329         CHECK_AND_RETURN_LOG(converter_ != nullptr, "converter is not inited");
330         metaSize = converter_->GetMetaSize();
331         converter_->GetInputBufferSize(cbBufferSize_);
332     } else {
333         cbBufferSize_ = static_cast<size_t>(bufferDurationInUs * curStreamParams_.samplingRate / AUDIO_US_PER_S) *
334             sizePerFrameInByte_;
335     }
336     AUDIO_INFO_LOG("duration %{public}" PRIu64 ", ecodingType: %{public}d, size: %{public}zu, metaSize: %{public}zu",
337         bufferDurationInUs, curStreamParams_.encoding, cbBufferSize_, metaSize);
338     std::lock_guard<std::mutex> lock(cbBufferMutex_);
339     cbBuffer_ = std::make_unique<uint8_t[]>(cbBufferSize_ + metaSize);
340 }
341 
342 // Sleep or wait in WaitForRunning to avoid dead looping.
WaitForRunning()343 bool RendererInClientInner::WaitForRunning()
344 {
345     Trace trace("RendererInClientInner::WaitForRunning");
346     // check renderer state_: call client write only in running else wait on statusMutex_
347     std::unique_lock<std::mutex> stateLock(statusMutex_);
348     if (state_ != RUNNING) {
349         bool stopWaiting = cbThreadCv_.wait_for(stateLock, std::chrono::milliseconds(OPERATION_TIMEOUT_IN_MS), [this] {
350             return state_ == RUNNING || cbThreadReleased_;
351         });
352         if (cbThreadReleased_) {
353             AUDIO_INFO_LOG("CBThread end in non-running status, sessionID :%{public}d", sessionId_);
354             return false;
355         }
356         if (!stopWaiting) {
357             AUDIO_DEBUG_LOG("Wait timeout, current state_ is %{public}d", state_.load()); // wait 0.5s
358             return false;
359         }
360     }
361     return true;
362 }
363 
ProcessWriteInner(BufferDesc & bufferDesc)364 int32_t RendererInClientInner::ProcessWriteInner(BufferDesc &bufferDesc)
365 {
366     int32_t result = 0; // Ensure result with default value.
367     if (curStreamParams_.encoding == ENCODING_AUDIOVIVID) {
368         result = WriteInner(bufferDesc.buffer, bufferDesc.bufLength, bufferDesc.metaBuffer, bufferDesc.metaLength);
369     }
370     if (curStreamParams_.encoding == ENCODING_PCM) {
371         if (bufferDesc.dataLength != 0) {
372             result = WriteInner(bufferDesc.buffer, bufferDesc.bufLength);
373             sleepCount_ = LOG_COUNT_LIMIT;
374         } else {
375             if (sleepCount_++ == LOG_COUNT_LIMIT) {
376                 sleepCount_ = 0;
377                 AUDIO_WARNING_LOG("OnWriteData Process 1st or 500 times INVALID buffer");
378             }
379             usleep(WAIT_FOR_NEXT_CB);
380         }
381     }
382     if (result < 0) {
383         AUDIO_WARNING_LOG("Call write fail, result:%{public}d, bufLength:%{public}zu", result, bufferDesc.bufLength);
384     }
385     return result;
386 }
387 
WriteCallbackFunc()388 bool RendererInClientInner::WriteCallbackFunc()
389 {
390     if (cbThreadReleased_) {
391         AUDIO_INFO_LOG("Callback thread released");
392         return false;
393     }
394     Trace traceLoop("RendererInClientInner::WriteCallbackFunc");
395     if (!WaitForRunning()) {
396         return true;
397     }
398     if (cbBufferQueue_.Size() > 1) { // One callback, one enqueue, queue size should always be 1.
399         AUDIO_WARNING_LOG("The queue is too long, reducing data through loops");
400     }
401     BufferDesc temp;
402     while (cbBufferQueue_.PopNotWait(temp)) {
403         Trace traceQueuePop("RendererInClientInner::QueueWaitPop");
404         if (state_ != RUNNING) {
405             cbBufferQueue_.Push(temp);
406             AUDIO_INFO_LOG("Repush left buffer in queue");
407             break;
408         }
409         traceQueuePop.End();
410         // call write here.
411         int32_t result = ProcessWriteInner(temp);
412         // only run in pause scene
413         if (result > 0 && static_cast<size_t>(result) < temp.dataLength) {
414             BufferDesc tmp = {temp.buffer + static_cast<size_t>(result),
415                 temp.bufLength - static_cast<size_t>(result), temp.dataLength - static_cast<size_t>(result)};
416             cbBufferQueue_.Push(tmp);
417             AUDIO_INFO_LOG("Repush %{public}zu bytes in queue", temp.dataLength - static_cast<size_t>(result));
418             break;
419         }
420     }
421     if (state_ != RUNNING) {
422         return true;
423     }
424     // call client write
425     std::unique_lock<std::mutex> lockCb(writeCbMutex_);
426     if (writeCb_ != nullptr) {
427         Trace traceCb("RendererInClientInner::OnWriteData");
428         writeCb_->OnWriteData(cbBufferSize_);
429     }
430     lockCb.unlock();
431 
432     Trace traceQueuePush("RendererInClientInner::QueueWaitPush");
433     std::unique_lock<std::mutex> lockBuffer(cbBufferMutex_);
434     cbBufferQueue_.WaitNotEmptyFor(std::chrono::milliseconds(WRITE_BUFFER_TIMEOUT_IN_MS));
435     return true;
436 }
437 
FlushRingCache()438 int32_t RendererInClientInner::FlushRingCache()
439 {
440     ringCache_->ResetBuffer();
441     return SUCCESS;
442 }
443 
DrainRingCache()444 int32_t RendererInClientInner::DrainRingCache()
445 {
446     // send all data in ringCache_ to server even if GetReadableSize() < clientSpanSizeInByte_.
447     Trace trace("RendererInClientInner::DrainRingCache " + std::to_string(sessionId_));
448 
449     OptResult result = ringCache_->GetReadableSize();
450     CHECK_AND_RETURN_RET_LOG(result.ret == OPERATION_SUCCESS, ERR_OPERATION_FAILED, "ring cache unreadable");
451     size_t readableSize = result.size;
452     if (readableSize == 0) {
453         AUDIO_WARNING_LOG("Readable size is already zero");
454         return SUCCESS;
455     }
456 
457     BufferDesc desc = {};
458     uint64_t curWriteIndex = clientBuffer_->GetCurWriteFrame();
459     int32_t ret = clientBuffer_->GetWriteBuffer(curWriteIndex, desc);
460     CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "GetWriteBuffer failed %{public}d", ret);
461 
462     // if readableSize < clientSpanSizeInByte_, server will recv a data with some empty data.
463     // it looks like this: |*******_____|
464     size_t minSize = std::min(readableSize, clientSpanSizeInByte_);
465     result = ringCache_->Dequeue({desc.buffer, minSize});
466     CHECK_AND_RETURN_RET_LOG(result.ret == OPERATION_SUCCESS, ERROR, "ringCache Dequeue failed %{public}d", result.ret);
467     clientBuffer_->SetCurWriteFrame(curWriteIndex + spanSizeInFrame_);
468     CHECK_AND_RETURN_RET_LOG(ipcStream_ != nullptr, ERR_ILLEGAL_STATE, "ipcStream is nullptr");
469     ipcStream_->UpdatePosition(); // notiify server update position
470     HandleRendererPositionChanges(minSize);
471     return SUCCESS;
472 }
473 
ProcessSpeed(uint8_t * & buffer,size_t & bufferSize,bool & speedCached)474 bool RendererInClientInner::ProcessSpeed(uint8_t *&buffer, size_t &bufferSize, bool &speedCached)
475 {
476     speedCached = false;
477 #ifdef SONIC_ENABLE
478     if (!isEqual(speed_, 1.0f)) {
479         Trace trace(traceTag_ + " ProcessSpeed");
480         if (audioSpeed_ == nullptr) {
481             AUDIO_ERR_LOG("audioSpeed_ is nullptr, use speed default 1.0");
482             return true;
483         }
484         int32_t outBufferSize = 0;
485         if (audioSpeed_->ChangeSpeedFunc(buffer, bufferSize, speedBuffer_, outBufferSize) == 0) {
486             bufferSize = 0;
487             AUDIO_ERR_LOG("process speed error");
488             return false;
489         }
490         if (outBufferSize == 0) {
491             AUDIO_DEBUG_LOG("speed buffer is not full");
492             return false;
493         }
494         buffer = speedBuffer_.get();
495         bufferSize = static_cast<size_t>(outBufferSize);
496         speedCached = true;
497     }
498 #endif
499     return true;
500 }
501 
DfxWriteInterval()502 void RendererInClientInner::DfxWriteInterval()
503 {
504     if (preWriteEndTime_ != 0 &&
505         ((ClockTime::GetCurNano() / AUDIO_US_PER_SECOND) - preWriteEndTime_) > MAX_WRITE_INTERVAL_MS) {
506         AUDIO_WARNING_LOG("[%{public}s] write interval too long cost %{public}" PRId64,
507             logUtilsTag_.c_str(), (ClockTime::GetCurNano() / AUDIO_US_PER_SECOND) - preWriteEndTime_);
508     }
509 }
WriteInner(uint8_t * pcmBuffer,size_t pcmBufferSize,uint8_t * metaBuffer,size_t metaBufferSize)510 int32_t RendererInClientInner::WriteInner(uint8_t *pcmBuffer, size_t pcmBufferSize, uint8_t *metaBuffer,
511     size_t metaBufferSize)
512 {
513     Trace trace("RendererInClient::Write with meta " + std::to_string(pcmBufferSize));
514     CHECK_AND_RETURN_RET_LOG(curStreamParams_.encoding == ENCODING_AUDIOVIVID, ERR_NOT_SUPPORTED,
515         "Write: Write not supported. encoding doesnot match.");
516     BufferDesc bufDesc = {pcmBuffer, pcmBufferSize, pcmBufferSize, metaBuffer, metaBufferSize};
517     CHECK_AND_RETURN_RET_LOG(converter_ != nullptr, ERR_WRITE_FAILED, "Write: converter isn't init.");
518     CHECK_AND_RETURN_RET_LOG(converter_->CheckInputValid(bufDesc), ERR_INVALID_PARAM, "Write: Invalid input.");
519 
520     WriteMuteDataSysEvent(pcmBuffer, pcmBufferSize);
521 
522     converter_->Process(bufDesc);
523     uint8_t *buffer;
524     uint32_t bufferSize;
525     converter_->GetOutputBufferStream(buffer, bufferSize);
526     return WriteInner(buffer, bufferSize);
527 }
528 
FirstFrameProcess()529 void RendererInClientInner::FirstFrameProcess()
530 {
531     if (ipcStream_ == nullptr) {
532         AUDIO_ERR_LOG("Error: ipcStream_ is not initialized!");
533         return;
534     }
535 
536     // if first call, call set thread priority. if thread tid change recall set thread priority
537     if (needSetThreadPriority_.exchange(false)) {
538         ipcStream_->RegisterThreadPriority(gettid(),
539             AudioSystemManager::GetInstance()->GetSelfBundleName(clientConfig_.appInfo.appUid));
540     }
541 
542     if (!hasFirstFrameWrited_.exchange(true)) { OnFirstFrameWriting(); }
543 }
544 
WriteRingCache(uint8_t * buffer,size_t bufferSize,bool speedCached,size_t oriBufferSize)545 int32_t RendererInClientInner::WriteRingCache(uint8_t *buffer, size_t bufferSize, bool speedCached,
546     size_t oriBufferSize)
547 {
548     size_t targetSize = bufferSize;
549     size_t offset = 0;
550     while (targetSize >= sizePerFrameInByte_) {
551         // 1. write data into ring cache
552         OptResult result = ringCache_->GetWritableSize();
553         CHECK_AND_RETURN_RET_LOG(result.ret == OPERATION_SUCCESS, speedCached ? oriBufferSize : bufferSize - targetSize,
554             "RingCache write status invalid size is:%{public}zu", result.size);
555 
556         size_t writableSize = result.size;
557         Trace::Count("RendererInClient::CacheBuffer->writableSize", writableSize);
558 
559         size_t writeSize = std::min(writableSize, targetSize);
560         BufferWrap bufferWrap = {buffer + offset, writeSize};
561 
562         if (writeSize > 0) {
563             result = ringCache_->Enqueue(bufferWrap);
564             if (result.ret != OPERATION_SUCCESS) {
565                 // in plan: recall enqueue in some cases
566                 AUDIO_ERR_LOG("RingCache Enqueue failed ret:%{public}d size:%{public}zu", result.ret, result.size);
567                 break;
568             }
569             offset += writeSize;
570             targetSize -= writeSize;
571             clientWrittenBytes_ += writeSize;
572         }
573 
574         // 2. copy data from cache to OHAudioBuffer
575         result = ringCache_->GetReadableSize();
576         CHECK_AND_RETURN_RET_LOG(result.ret == OPERATION_SUCCESS, speedCached ? oriBufferSize : bufferSize - targetSize,
577             "RingCache read status invalid size is:%{public}zu", result.size);
578         size_t readableSize = result.size;
579         Trace::Count("RendererInClient::CacheBuffer->readableSize", readableSize);
580 
581         if (readableSize < clientSpanSizeInByte_) { continue; }
582         // if readable size is enough, we will call write data to server
583         int32_t ret = WriteCacheData();
584         CHECK_AND_RETURN_RET_LOG(ret != ERR_ILLEGAL_STATE, speedCached ? oriBufferSize : bufferSize - targetSize,
585             "Status changed while write");
586         CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERROR, "WriteCacheData failed %{public}d", ret);
587     }
588     preWriteEndTime_ = ClockTime::GetCurNano() / AUDIO_US_PER_SECOND;
589     return speedCached ? oriBufferSize : bufferSize - targetSize;
590 }
591 
WriteInner(uint8_t * buffer,size_t bufferSize)592 int32_t RendererInClientInner::WriteInner(uint8_t *buffer, size_t bufferSize)
593 {
594     // eg: RendererInClient::sessionId:100001 WriteSize:3840
595     DfxWriteInterval();
596     Trace trace(traceTag_+ " WriteSize:" + std::to_string(bufferSize));
597     CHECK_AND_RETURN_RET_LOG(buffer != nullptr && bufferSize < MAX_WRITE_SIZE && bufferSize > 0, ERR_INVALID_PARAM,
598         "invalid size is %{public}zu", bufferSize);
599 
600     // Bugfix. Callback threadloop would go into infinite loop, consuming too much data from app
601     // but fail to play them due to audio server's death. Block and exit callback threadloop when server died.
602     if (gServerProxy_ == nullptr) {
603         cbThreadReleased_ = true;
604         uint32_t samplingRate = clientConfig_.streamInfo.samplingRate;
605         uint32_t channels = clientConfig_.streamInfo.channels;
606         uint32_t samplePerFrame = Util::GetSamplePerFrame(clientConfig_.streamInfo.format);
607         // calculate wait time by buffer size, 10e6 is converting seconds to microseconds
608         uint32_t waitTimeUs = bufferSize * 10e6 / (samplingRate * channels * samplePerFrame);
609         AUDIO_ERR_LOG("server is died! wait %{public}d us", waitTimeUs);
610         usleep(waitTimeUs);
611         return ERR_WRITE_BUFFER;
612     }
613 
614     CHECK_AND_RETURN_RET_LOG(gServerProxy_ != nullptr, ERROR, "server is died");
615     if (clientBuffer_->GetStreamStatus() == nullptr) {
616         AUDIO_ERR_LOG("The stream status is null!");
617         return ERR_INVALID_PARAM;
618     }
619 
620     if (clientBuffer_->GetStreamStatus()->load() == STREAM_STAND_BY) {
621         Trace trace2(traceTag_+ " call start to exit stand-by");
622         CHECK_AND_RETURN_RET_LOG(ipcStream_ != nullptr, ERROR, "ipcStream is not inited!");
623         int32_t ret = ipcStream_->Start();
624         AUDIO_INFO_LOG("%{public}u call start to exit stand-by ret %{public}u", sessionId_, ret);
625     }
626 
627     FirstFrameProcess();
628 
629     std::lock_guard<std::mutex> lock(writeMutex_);
630 
631     size_t oriBufferSize = bufferSize;
632     bool speedCached = false;
633     if (!ProcessSpeed(buffer, bufferSize, speedCached)) {
634         return bufferSize;
635     }
636 
637     WriteMuteDataSysEvent(buffer, bufferSize);
638 
639     CHECK_AND_RETURN_RET_PRELOG(state_ == RUNNING, ERR_ILLEGAL_STATE,
640         "Write: Illegal state:%{public}u sessionid: %{public}u", state_.load(), sessionId_);
641 
642     // hold lock
643     if (isBlendSet_) {
644         audioBlend_.Process(buffer, bufferSize);
645     }
646 
647     return WriteRingCache(buffer, bufferSize, speedCached, oriBufferSize);
648 }
649 
ResetFramePosition()650 void RendererInClientInner::ResetFramePosition()
651 {
652     Trace trace("RendererInClientInner::ResetFramePosition");
653     uint64_t timestampVal = 0;
654     uint64_t latency = 0;
655     CHECK_AND_RETURN_LOG(ipcStream_ != nullptr, "ipcStream is not inited!");
656     int32_t ret = ipcStream_->GetAudioPosition(lastFlushReadIndex_, timestampVal, latency);
657     if (ret != SUCCESS) {
658         AUDIO_PRERELEASE_LOGE("Get position failed: %{public}u", ret);
659         return;
660     }
661     lastFramePosition_ = 0;
662     lastReadIdx_ = 0;
663     lastLatency_ = latency;
664     lastLatencyPosition_ = latency * speed_;
665 }
666 
WriteMuteDataSysEvent(uint8_t * buffer,size_t bufferSize)667 void RendererInClientInner::WriteMuteDataSysEvent(uint8_t *buffer, size_t bufferSize)
668 {
669     if (silentModeAndMixWithOthers_) {
670         return;
671     }
672     if (IsInvalidBuffer(buffer, bufferSize)) {
673         if (startMuteTime_ == 0) {
674             startMuteTime_ = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
675         }
676         std::time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
677         if ((currentTime - startMuteTime_ >= ONE_MINUTE) && !isUpEvent_) {
678             AUDIO_WARNING_LOG("write silent data for some time");
679             isUpEvent_ = true;
680             std::shared_ptr<Media::MediaMonitor::EventBean> bean = std::make_shared<Media::MediaMonitor::EventBean>(
681                 Media::MediaMonitor::AUDIO, Media::MediaMonitor::BACKGROUND_SILENT_PLAYBACK,
682                 Media::MediaMonitor::FREQUENCY_AGGREGATION_EVENT);
683             bean->Add("CLIENT_UID", appUid_);
684             Media::MediaMonitor::MediaMonitorManager::GetInstance().WriteLogMsg(bean);
685         }
686     } else if (buffer[0] != 0 && startMuteTime_ != 0) {
687         startMuteTime_ = 0;
688     }
689 }
690 
IsInvalidBuffer(uint8_t * buffer,size_t bufferSize)691 bool RendererInClientInner::IsInvalidBuffer(uint8_t *buffer, size_t bufferSize)
692 {
693     bool isInvalid = false;
694     uint8_t ui8Data = 0;
695     int16_t i16Data = 0;
696     switch (clientConfig_.streamInfo.format) {
697         case SAMPLE_U8:
698             CHECK_AND_RETURN_RET_LOG(bufferSize > 0, false, "buffer size is too small");
699             ui8Data = *buffer;
700             isInvalid = ui8Data == 0;
701             break;
702         case SAMPLE_S16LE:
703             CHECK_AND_RETURN_RET_LOG(bufferSize > 1, false, "buffer size is too small");
704             i16Data = *(reinterpret_cast<const int16_t*>(buffer));
705             isInvalid = i16Data == 0;
706             break;
707         default:
708             break;
709     }
710     return isInvalid;
711 }
712 
DrainIncompleteFrame(OptResult result,bool stopFlag,size_t targetSize,BufferDesc * desc,bool & dropIncompleteFrame)713 int32_t RendererInClientInner::DrainIncompleteFrame(OptResult result, bool stopFlag,
714     size_t targetSize, BufferDesc *desc, bool &dropIncompleteFrame)
715 {
716     if (result.size < clientSpanSizeInByte_ && stopFlag) {
717         result = ringCache_->Dequeue({desc->buffer, targetSize});
718         CHECK_AND_RETURN_RET_LOG(result.ret == OPERATION_SUCCESS, ERROR,
719             "ringCache Dequeue failed %{public}d", result.ret);
720         int32_t ret = memset_s(desc->buffer, targetSize, 0, targetSize);
721         CHECK_AND_RETURN_RET_LOG(ret == EOK, ERROR, "DrainIncompleteFrame memset output failed");
722         AUDIO_WARNING_LOG("incomplete frame is set to 0");
723         dropIncompleteFrame = true;
724     }
725     return SUCCESS;
726 }
727 
728 
WriteCacheData(bool isDrain,bool stopFlag)729 int32_t RendererInClientInner::WriteCacheData(bool isDrain, bool stopFlag)
730 {
731     Trace traceCache(isDrain ? "RendererInClientInner::DrainCacheData" : "RendererInClientInner::WriteCacheData");
732 
733     OptResult result = ringCache_->GetReadableSize();
734     CHECK_AND_RETURN_RET_LOG(result.ret == OPERATION_SUCCESS, ERR_OPERATION_FAILED, "ring cache unreadable");
735     if (result.size == 0) {
736         AUDIO_WARNING_LOG("Readable size is already zero");
737         return SUCCESS;
738     }
739     size_t targetSize = isDrain ? std::min(result.size, clientSpanSizeInByte_) : clientSpanSizeInByte_;
740 
741     int32_t sizeInFrame = clientBuffer_->GetAvailableDataFrames();
742     CHECK_AND_RETURN_RET_LOG(sizeInFrame >= 0, ERROR, "GetAvailableDataFrames invalid, %{public}d", sizeInFrame);
743 
744     FutexCode futexRes = FUTEX_OPERATION_FAILED;
745     if (static_cast<uint32_t>(sizeInFrame) < spanSizeInFrame_) {
746         int32_t timeout = offloadEnable_ ? OFFLOAD_OPERATION_TIMEOUT_IN_MS : WRITE_CACHE_TIMEOUT_IN_MS;
747         futexRes = FutexTool::FutexWait(clientBuffer_->GetFutex(), static_cast<int64_t>(timeout) * AUDIO_US_PER_SECOND,
748             [this] () {
749                 return (state_ != RUNNING) ||
750                     (static_cast<uint32_t>(clientBuffer_->GetAvailableDataFrames()) >= spanSizeInFrame_);
751             });
752         CHECK_AND_RETURN_RET_LOG(state_ == RUNNING, ERR_ILLEGAL_STATE, "failed with state:%{public}d", state_.load());
753         CHECK_AND_RETURN_RET_LOG(futexRes != FUTEX_TIMEOUT, ERROR,
754             "write data time out, mode is %{public}s", (offloadEnable_ ? "offload" : "normal"));
755         sizeInFrame = clientBuffer_->GetAvailableDataFrames();
756     }
757 
758     if (sizeInFrame < 0 || static_cast<uint32_t>(clientBuffer_->GetAvailableDataFrames()) < spanSizeInFrame_) {
759         AUDIO_ERR_LOG("failed: sizeInFrame is:%{public}d, futexRes:%{public}d", sizeInFrame, futexRes);
760         return ERROR;
761     }
762     BufferDesc desc = {};
763     uint64_t curWriteIndex = clientBuffer_->GetCurWriteFrame();
764     int32_t ret = clientBuffer_->GetWriteBuffer(curWriteIndex, desc);
765     CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERROR, "GetWriteBuffer failed %{public}d", ret);
766     bool dropIncompleteFrame = false;
767     CHECK_AND_RETURN_RET_LOG(DrainIncompleteFrame(result, stopFlag, targetSize, &desc, dropIncompleteFrame) == SUCCESS,
768         ERROR, "DrainIncompleteFrame failed");
769     if (dropIncompleteFrame) {
770         return SUCCESS;
771     }
772     result = ringCache_->Dequeue({desc.buffer, targetSize});
773     CHECK_AND_RETURN_RET_LOG(result.ret == OPERATION_SUCCESS, ERROR, "ringCache Dequeue failed %{public}d", result.ret);
774     if (isDrain && targetSize < clientSpanSizeInByte_ && clientConfig_.streamInfo.format == SAMPLE_U8) {
775         size_t leftSize = clientSpanSizeInByte_ - targetSize;
776         int32_t ret = memset_s(desc.buffer + targetSize, leftSize, 0X7F, leftSize);
777         CHECK_AND_RETURN_RET_LOG(ret == EOK, ERROR, "left buffer memset output failed");
778     }
779     if (!ProcessVolume()) {
780         return ERR_OPERATION_FAILED;
781     }
782 
783     DumpFileUtil::WriteDumpFile(dumpOutFd_, static_cast<void *>(desc.buffer), desc.bufLength);
784     VolumeTools::DfxOperation(desc, clientConfig_.streamInfo, traceTag_, volumeDataCount_);
785     clientBuffer_->SetCurWriteFrame(curWriteIndex + spanSizeInFrame_);
786 
787     CHECK_AND_RETURN_RET_LOG(ipcStream_ != nullptr, ERR_OPERATION_FAILED, "WriteCacheData failed, null ipcStream_.");
788     ipcStream_->UpdatePosition(); // notiify server update position
789     HandleRendererPositionChanges(desc.bufLength);
790     return SUCCESS;
791 }
792 
ProcessVolume()793 bool RendererInClientInner::ProcessVolume()
794 {
795     // volume process in client
796     if (volumeRamp_.IsActive()) {
797         // do not call SetVolume here.
798         clientVolume_ = volumeRamp_.GetRampVolume();
799         AUDIO_INFO_LOG("clientVolume_:%{public}f", clientVolume_);
800         Trace traceVolume("RendererInClientInner::WriteCacheData:Ramp:clientVolume_:" + std::to_string(clientVolume_));
801         SetInnerVolume(clientVolume_);
802     }
803     return true;
804 }
805 
RegisterSpatializationStateEventListener()806 int32_t RendererInClientInner::RegisterSpatializationStateEventListener()
807 {
808     if (firstSpatializationRegistered_) {
809         firstSpatializationRegistered_ = false;
810     } else {
811         UnregisterSpatializationStateEventListener(spatializationRegisteredSessionID_);
812     }
813 
814     if (!spatializationStateChangeCallback_) {
815         spatializationStateChangeCallback_ = std::make_shared<SpatializationStateChangeCallbackImpl>();
816         CHECK_AND_RETURN_RET_LOG(spatializationStateChangeCallback_, ERROR, "Memory Allocation Failed !!");
817     }
818     spatializationStateChangeCallback_->SetRendererInClientPtr(shared_from_this());
819 
820     int32_t ret = AudioPolicyManager::GetInstance().RegisterSpatializationStateEventListener(
821         sessionId_, rendererInfo_.streamUsage, spatializationStateChangeCallback_);
822     CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "RegisterSpatializationStateEventListener failed");
823     spatializationRegisteredSessionID_ = sessionId_;
824 
825     return SUCCESS;
826 }
827 
UnregisterSpatializationStateEventListener(uint32_t sessionID)828 int32_t RendererInClientInner::UnregisterSpatializationStateEventListener(uint32_t sessionID)
829 {
830     int32_t ret = AudioPolicyManager::GetInstance().UnregisterSpatializationStateEventListener(sessionID);
831     CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "UnregisterSpatializationStateEventListener failed");
832     return SUCCESS;
833 }
834 
DrainAudioStreamInner(bool stopFlag)835 bool RendererInClientInner::DrainAudioStreamInner(bool stopFlag)
836 {
837     Trace trace("RendererInClientInner::DrainAudioStreamInner " + std::to_string(sessionId_));
838     if (state_ != RUNNING) {
839         AUDIO_ERR_LOG("Drain failed. Illegal state:%{public}u", state_.load());
840         return false;
841     }
842     CHECK_AND_RETURN_RET_LOG(WriteCacheData(true, stopFlag) == SUCCESS, false, "Drain cache failed");
843 
844     CHECK_AND_RETURN_RET_LOG(ipcStream_ != nullptr, false, "ipcStream is not inited!");
845     AUDIO_INFO_LOG("stopFlag:%{public}d", stopFlag);
846     int32_t ret = ipcStream_->Drain(stopFlag);
847     if (ret != SUCCESS) {
848         AUDIO_ERR_LOG("Drain call server failed:%{public}u", ret);
849         return false;
850     }
851     std::unique_lock<std::mutex> waitLock(callServerMutex_);
852     bool stopWaiting = callServerCV_.wait_for(waitLock, std::chrono::milliseconds(OPERATION_TIMEOUT_IN_MS), [this] {
853         return notifiedOperation_ == DRAIN_STREAM; // will be false when got notified.
854     });
855 
856     // clear cbBufferQueue
857     if (renderMode_ == RENDER_MODE_CALLBACK && stopFlag) {
858         cbBufferQueue_.Clear();
859         if (memset_s(cbBuffer_.get(), cbBufferSize_, 0, cbBufferSize_) != EOK) {
860             AUDIO_ERR_LOG("memset_s buffer failed");
861         };
862     }
863 
864     if (notifiedOperation_ != DRAIN_STREAM || notifiedResult_ != SUCCESS) {
865         AUDIO_ERR_LOG("Drain failed: %{public}s Operation:%{public}d result:%{public}" PRId64".",
866             (!stopWaiting ? "timeout" : "no timeout"), notifiedOperation_, notifiedResult_);
867         notifiedOperation_ = MAX_OPERATION_CODE;
868         return false;
869     }
870     notifiedOperation_ = MAX_OPERATION_CODE;
871     waitLock.unlock();
872     AUDIO_INFO_LOG("Drain stream SUCCESS, sessionId: %{public}d", sessionId_);
873     return true;
874 }
875 
SpatializationStateChangeCallbackImpl()876 SpatializationStateChangeCallbackImpl::SpatializationStateChangeCallbackImpl()
877 {
878     AUDIO_INFO_LOG("Instance create");
879 }
880 
~SpatializationStateChangeCallbackImpl()881 SpatializationStateChangeCallbackImpl::~SpatializationStateChangeCallbackImpl()
882 {
883     AUDIO_INFO_LOG("Instance destory");
884 }
885 
SetRendererInClientPtr(std::shared_ptr<RendererInClientInner> rendererInClientPtr)886 void SpatializationStateChangeCallbackImpl::SetRendererInClientPtr(
887     std::shared_ptr<RendererInClientInner> rendererInClientPtr)
888 {
889     rendererInClientPtr_ = rendererInClientPtr;
890 }
891 
OnSpatializationStateChange(const AudioSpatializationState & spatializationState)892 void SpatializationStateChangeCallbackImpl::OnSpatializationStateChange(
893     const AudioSpatializationState &spatializationState)
894 {
895     std::shared_ptr<RendererInClientInner> rendererInClient = rendererInClientPtr_.lock();
896     if (rendererInClient != nullptr) {
897         rendererInClient->OnSpatializationStateChange(spatializationState);
898     }
899 }
900 } // namespace AudioStandard
901 } // namespace OHOS