1 /*
2 * Copyright (c) 2023 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 "AudioEndpointSeparate"
17 #endif
18
19 #include "audio_endpoint.h"
20
21 #include <atomic>
22 #include <cinttypes>
23 #include <condition_variable>
24 #include <thread>
25 #include <vector>
26 #include <mutex>
27
28 #include "securec.h"
29
30 #include "audio_errors.h"
31 #include "audio_service_log.h"
32 #include "audio_schedule.h"
33 #include "audio_utils.h"
34 #include "common/hdi_adapter_info.h"
35 #include "manager/hdi_adapter_manager.h"
36 #include "sink/i_audio_render_sink.h"
37 #include "linear_pos_time_model.h"
38 #include "policy_handler.h"
39 #include "audio_service.h"
40 namespace OHOS {
41 namespace AudioStandard {
42 namespace {
43 static constexpr int32_t VOLUME_SHIFT_NUMBER = 16; // 1 >> 16 = 65536, max volume
44 static constexpr int64_t MAX_SPAN_DURATION_NS = 100000000; // 100ms
45 static constexpr int64_t DELTA_TO_REAL_READ_START_TIME = 0; // 0ms
46 }
47
AudioEndpointSeparate(EndpointType type,uint64_t id,AudioStreamType streamType)48 AudioEndpointSeparate::AudioEndpointSeparate(EndpointType type, uint64_t id,
49 AudioStreamType streamType) : endpointType_(type), id_(id), streamType_(streamType)
50 {
51 AUDIO_INFO_LOG("AudioEndpoint type:%{public}d", endpointType_);
52 }
53
GetEndpointName()54 std::string AudioEndpointSeparate::GetEndpointName()
55 {
56 // temp method to get device key, should be same with AudioService::GetAudioEndpointForDevice.
57 return deviceInfo_.networkId_ + std::to_string(deviceInfo_.deviceId_) + "_" + std::to_string(id_);
58 }
59
ShouldInnerCap(int32_t innerCapId)60 bool AudioEndpointSeparate::ShouldInnerCap(int32_t innerCapId)
61 {
62 AUDIO_WARNING_LOG("AudioEndpointSeparate is not supported");
63 return false;
64 }
65
EnableFastInnerCap(int32_t innerCapId)66 int32_t AudioEndpointSeparate::EnableFastInnerCap(int32_t innerCapId)
67 {
68 AUDIO_WARNING_LOG("AudioEndpointSeparate is not supported");
69 return ERR_INVALID_OPERATION;
70 }
71
DisableFastInnerCap()72 int32_t AudioEndpointSeparate::DisableFastInnerCap()
73 {
74 AUDIO_WARNING_LOG("AudioEndpointSeparate is not supported");
75 return ERR_INVALID_OPERATION;
76 }
77
DisableFastInnerCap(int32_t innerCapId)78 int32_t AudioEndpointSeparate::DisableFastInnerCap(int32_t innerCapId)
79 {
80 AUDIO_WARNING_LOG("AudioEndpointSeparate is not supported");
81 return ERR_INVALID_OPERATION;
82 }
83
SetVolume(AudioStreamType streamType,float volume)84 int32_t AudioEndpointSeparate::SetVolume(AudioStreamType streamType, float volume)
85 {
86 if (streamType_ == streamType) {
87 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(fastRenderId_);
88 CHECK_AND_RETURN_RET(sink != nullptr, ERR_INVALID_HANDLE);
89 return sink->SetVolume(volume, volume);
90 }
91 return SUCCESS;
92 }
93
ResolveBuffer(std::shared_ptr<OHAudioBuffer> & buffer)94 int32_t AudioEndpointSeparate::ResolveBuffer(std::shared_ptr<OHAudioBuffer> &buffer)
95 {
96 if (!isInited_.load()) {
97 AUDIO_ERR_LOG("ResolveBuffer failed, buffer is not configured.");
98 return ERR_ILLEGAL_STATE;
99 }
100 buffer = dstAudioBuffer_;
101
102 CHECK_AND_RETURN_RET_LOG(buffer != nullptr, ERR_ILLEGAL_STATE, "ResolveBuffer failed, processBuffer_ is null.");
103
104 return SUCCESS;
105 }
106
GetBuffer()107 std::shared_ptr<OHAudioBuffer> AudioEndpointSeparate::GetBuffer()
108 {
109 return dstAudioBuffer_;
110 }
111
GetStatus()112 AudioEndpoint::EndpointStatus AudioEndpointSeparate::GetStatus()
113 {
114 AUDIO_INFO_LOG("AudioEndpoint get status:%{public}s", GetStatusStr(endpointStatus_).c_str());
115 return endpointStatus_.load();
116 }
117
Release()118 void AudioEndpointSeparate::Release()
119 {
120 // Wait for thread end and then clear other data to avoid using any cleared data in thread.
121 AUDIO_INFO_LOG("%{public}s enter.", __func__);
122 if (!isInited_.load()) {
123 AUDIO_WARNING_LOG("already released");
124 return;
125 }
126
127 isInited_.store(false);
128 workThreadCV_.notify_all();
129
130 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(fastRenderId_);
131 if (sink != nullptr) {
132 sink->DeInit();
133 }
134 HdiAdapterManager::GetInstance().ReleaseId(fastRenderId_);
135
136 endpointStatus_.store(INVALID);
137
138 if (dstAudioBuffer_ != nullptr) {
139 AUDIO_INFO_LOG("Set device buffer null");
140 dstAudioBuffer_ = nullptr;
141 }
142 }
143
~AudioEndpointSeparate()144 AudioEndpointSeparate::~AudioEndpointSeparate()
145 {
146 if (isInited_.load()) {
147 AudioEndpointSeparate::Release();
148 }
149 AUDIO_INFO_LOG("~AudioEndpoint()");
150 }
151
Dump(std::string & dumpString)152 void AudioEndpointSeparate::Dump(std::string &dumpString)
153 {
154 // dump endpoint stream info
155 dumpString += "Endpoint stream info:\n";
156 AppendFormat(dumpString, " - samplingRate: %d\n", dstStreamInfo_.samplingRate);
157 AppendFormat(dumpString, " - channels: %u\n", dstStreamInfo_.channels);
158 AppendFormat(dumpString, " - format: %u\n", dstStreamInfo_.format);
159
160 // dump status info
161 AppendFormat(dumpString, " - Current endpoint status: %s\n", GetStatusStr(endpointStatus_).c_str());
162 if (dstAudioBuffer_ != nullptr) {
163 AppendFormat(dumpString, " - Currend hdi read position: %u\n", dstAudioBuffer_->GetCurReadFrame());
164 AppendFormat(dumpString, " - Currend hdi write position: %u\n", dstAudioBuffer_->GetCurWriteFrame());
165 }
166
167 // dump linked process info
168 std::lock_guard<std::mutex> lock(listLock_);
169 AppendFormat(dumpString, " - linked process:: %zu\n", processBufferList_.size());
170 for (auto item : processBufferList_) {
171 AppendFormat(dumpString, " - process read position: %u\n", item->GetCurReadFrame());
172 AppendFormat(dumpString, " - process write position: %u\n", item->GetCurWriteFrame());
173 }
174 dumpString += "\n";
175 }
176
InitSinkAttr(IAudioSinkAttr & attr,const AudioDeviceDescriptor & deviceInfo)177 void AudioEndpointSeparate::InitSinkAttr(IAudioSinkAttr &attr, const AudioDeviceDescriptor &deviceInfo)
178 {
179 bool isDefaultAdapterEnable = AudioService::GetInstance()->GetDefaultAdapterEnable();
180 attr.adapterName = isDefaultAdapterEnable ? "dp" : "primary";
181 attr.sampleRate = dstStreamInfo_.samplingRate; // 48000hz
182 attr.channel = dstStreamInfo_.channels; // STEREO = 2
183 attr.format = ConvertToHdiAdapterFormat(dstStreamInfo_.format); // SAMPLE_S16LE = 1
184 attr.deviceNetworkId = deviceInfo.networkId_.c_str();
185 attr.deviceType = static_cast<int32_t>(deviceInfo.deviceType_);
186 }
187
Config(const AudioDeviceDescriptor & deviceInfo)188 bool AudioEndpointSeparate::Config(const AudioDeviceDescriptor &deviceInfo)
189 {
190 AUDIO_INFO_LOG("%{public}s enter, deviceRole %{public}d.", __func__, deviceInfo.deviceRole_);
191 if (deviceInfo.deviceRole_ == INPUT_DEVICE || deviceInfo.networkId_ != LOCAL_NETWORK_ID) {
192 return false;
193 }
194
195 deviceInfo_ = deviceInfo;
196 if (!deviceInfo_.audioStreamInfo_.CheckParams()) {
197 AUDIO_ERR_LOG("%{public}s samplingRate or channels size is 0", __func__);
198 return false;
199 }
200 dstStreamInfo_ = {
201 *deviceInfo.audioStreamInfo_.samplingRate.rbegin(),
202 deviceInfo.audioStreamInfo_.encoding,
203 deviceInfo.audioStreamInfo_.format,
204 *deviceInfo.audioStreamInfo_.channels.rbegin()
205 };
206 dstStreamInfo_.channelLayout = deviceInfo.audioStreamInfo_.channelLayout;
207
208 HdiAdapterManager &manager = HdiAdapterManager::GetInstance();
209 fastRenderId_ = manager.GetId(HDI_ID_BASE_RENDER, HDI_ID_TYPE_FAST, "endpoint_sep_" + std::to_string(id_), true);
210 std::shared_ptr<IAudioRenderSink> sink = manager.GetRenderSink(fastRenderId_, true);
211 if (sink == nullptr) {
212 AUDIO_ERR_LOG("fast sink is nullptr");
213 manager.ReleaseId(fastRenderId_);
214 return false;
215 }
216
217 IAudioSinkAttr attr = {};
218 InitSinkAttr(attr, deviceInfo);
219
220 sink->Init(attr);
221 if (!sink->IsInited()) {
222 AUDIO_ERR_LOG("fastSinkInit failed");
223 manager.ReleaseId(fastRenderId_);
224 return false;
225 }
226 if (PrepareDeviceBuffer(deviceInfo) != SUCCESS) {
227 sink->DeInit();
228 manager.ReleaseId(fastRenderId_);
229 return false;
230 }
231
232 Volume vol = {true, 1.0f, 0};
233 AudioVolumeType volumeType = VolumeUtils::GetVolumeTypeFromStreamType(streamType_);
234 DeviceType deviceType = PolicyHandler::GetInstance().GetActiveOutPutDevice();
235 PolicyHandler::GetInstance().GetSharedVolume(volumeType, deviceType, vol);
236 sink->SetVolume(vol.volumeFloat, vol.volumeFloat);
237 AUDIO_DEBUG_LOG("Init hdi volume to %{public}f", vol.volumeFloat);
238
239 endpointStatus_ = UNLINKED;
240 isInited_.store(true);
241 return true;
242 }
243
GetAdapterBufferInfo(const AudioDeviceDescriptor & deviceInfo)244 int32_t AudioEndpointSeparate::GetAdapterBufferInfo(const AudioDeviceDescriptor &deviceInfo)
245 {
246 int32_t ret = 0;
247 AUDIO_INFO_LOG("%{public}s enter, deviceRole %{public}d.", __func__, deviceInfo.deviceRole_);
248
249 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(fastRenderId_);
250 CHECK_AND_RETURN_RET_LOG(sink != nullptr, ERR_INVALID_HANDLE, "%{public}s fast sink is null.", __func__);
251 ret = sink->GetMmapBufferInfo(dstBufferFd_, dstTotalSizeInframe_, dstSpanSizeInframe_, dstByteSizePerFrame_);
252 if (ret != SUCCESS || dstBufferFd_ == -1 || dstTotalSizeInframe_ == 0 || dstSpanSizeInframe_ == 0 ||
253 dstByteSizePerFrame_ == 0) {
254 AUDIO_ERR_LOG("%{public}s get mmap buffer info fail, ret %{public}d, dstBufferFd %{public}d, \
255 dstTotalSizeInframe %{public}d, dstSpanSizeInframe %{public}d, dstByteSizePerFrame %{public}d.",
256 __func__, ret, dstBufferFd_, dstTotalSizeInframe_, dstSpanSizeInframe_, dstByteSizePerFrame_);
257 return ERR_ILLEGAL_STATE;
258 }
259 AUDIO_DEBUG_LOG("%{public}s end, fd %{public}d.", __func__, dstBufferFd_);
260 return SUCCESS;
261 }
262
PrepareDeviceBuffer(const AudioDeviceDescriptor & deviceInfo)263 int32_t AudioEndpointSeparate::PrepareDeviceBuffer(const AudioDeviceDescriptor &deviceInfo)
264 {
265 AUDIO_INFO_LOG("%{public}s enter, deviceRole %{public}d.", __func__, deviceInfo.deviceRole_);
266 if (dstAudioBuffer_ != nullptr) {
267 AUDIO_INFO_LOG("%{public}s endpoint buffer is preapred, fd:%{public}d", __func__, dstBufferFd_);
268 return SUCCESS;
269 }
270
271 int32_t ret = GetAdapterBufferInfo(deviceInfo);
272 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED,
273 "%{public}s get adapter buffer Info fail, ret %{public}d.", __func__, ret);
274
275 // spanDuration_ may be less than the correct time of dstSpanSizeInframe_.
276 spanDuration_ = static_cast<int64_t>(dstSpanSizeInframe_ * AUDIO_NS_PER_SECOND / dstStreamInfo_.samplingRate);
277 int64_t temp = spanDuration_ / 5 * 3; // 3/5 spanDuration
278 serverAheadReadTime_ = temp < ONE_MILLISECOND_DURATION ? ONE_MILLISECOND_DURATION : temp; // at least 1ms ahead.
279 AUDIO_DEBUG_LOG("%{public}s spanDuration %{public}" PRIu64" ns, serverAheadReadTime %{public}" PRIu64" ns.",
280 __func__, spanDuration_, serverAheadReadTime_);
281
282 if (spanDuration_ <= 0 || spanDuration_ >= MAX_SPAN_DURATION_NS) {
283 AUDIO_ERR_LOG("%{public}s mmap span info error, spanDuration %{public}" PRIu64".", __func__, spanDuration_);
284 return ERR_INVALID_PARAM;
285 }
286 dstAudioBuffer_ = OHAudioBuffer::CreateFromRemote(dstTotalSizeInframe_, dstSpanSizeInframe_, dstByteSizePerFrame_,
287 AUDIO_SERVER_INDEPENDENT, dstBufferFd_, OHAudioBuffer::INVALID_BUFFER_FD);
288 CHECK_AND_RETURN_RET_LOG((dstAudioBuffer_ != nullptr && (dstAudioBuffer_->GetStreamStatus() != nullptr)),
289 ERR_ILLEGAL_STATE, "%{public}s create buffer from remote fail.", __func__);
290 dstAudioBuffer_->GetStreamStatus()->store(StreamStatus::STREAM_IDEL);
291 // clear data buffer
292 ret = memset_s(dstAudioBuffer_->GetDataBase(), dstAudioBuffer_->GetDataSize(), 0, dstAudioBuffer_->GetDataSize());
293 if (ret != EOK) {
294 AUDIO_WARNING_LOG("%{public}s memset buffer fail, ret %{public}d, fd %{public}d.", __func__, ret, dstBufferFd_);
295 }
296 InitAudiobuffer(true);
297
298 AUDIO_DEBUG_LOG("%{public}s end, fd %{public}d.", __func__, dstBufferFd_);
299 return SUCCESS;
300 }
301
InitAudiobuffer(bool resetReadWritePos)302 void AudioEndpointSeparate::InitAudiobuffer(bool resetReadWritePos)
303 {
304 CHECK_AND_RETURN_LOG((dstAudioBuffer_ != nullptr), "%{public}s: dst audio buffer is null.", __func__);
305 if (resetReadWritePos) {
306 dstAudioBuffer_->ResetCurReadWritePos(0, 0);
307 }
308
309 uint32_t spanCount = dstAudioBuffer_->GetSpanCount();
310 for (uint32_t i = 0; i < spanCount; i++) {
311 SpanInfo *spanInfo = dstAudioBuffer_->GetSpanInfoByIndex(i);
312 if (spanInfo == nullptr) {
313 AUDIO_ERR_LOG("InitAudiobuffer failed.");
314 return;
315 }
316 if (deviceInfo_.deviceRole_ == INPUT_DEVICE) {
317 spanInfo->spanStatus = SPAN_WRITE_DONE;
318 } else {
319 spanInfo->spanStatus = SPAN_READ_DONE;
320 }
321 spanInfo->offsetInFrame = 0;
322
323 spanInfo->readStartTime = 0;
324 spanInfo->readDoneTime = 0;
325
326 spanInfo->writeStartTime = 0;
327 spanInfo->writeDoneTime = 0;
328
329 spanInfo->volumeStart = 1 << VOLUME_SHIFT_NUMBER; // 65536 for initialize
330 spanInfo->volumeEnd = 1 << VOLUME_SHIFT_NUMBER; // 65536 for initialize
331 spanInfo->isMute = false;
332 }
333 return;
334 }
335
GetPreferBufferInfo(uint32_t & totalSizeInframe,uint32_t & spanSizeInframe)336 int32_t AudioEndpointSeparate::GetPreferBufferInfo(uint32_t &totalSizeInframe, uint32_t &spanSizeInframe)
337 {
338 totalSizeInframe = dstTotalSizeInframe_;
339 spanSizeInframe = dstSpanSizeInframe_;
340 return SUCCESS;
341 }
342
IsAnyProcessRunning()343 bool AudioEndpointSeparate::IsAnyProcessRunning()
344 {
345 std::lock_guard<std::mutex> lock(listLock_);
346 bool isRunning = false;
347 for (size_t i = 0; i < processBufferList_.size(); i++) {
348 if (processBufferList_[i]->GetStreamStatus() == nullptr) {
349 AUDIO_ERR_LOG("%{public}s process buffer %{public}zu has a null stream status.", __func__, i);
350 continue;
351 }
352 if (processBufferList_[i]->GetStreamStatus() &&
353 processBufferList_[i]->GetStreamStatus()->load() == STREAM_RUNNING) {
354 isRunning = true;
355 break;
356 }
357 }
358 return isRunning;
359 }
360
ResyncPosition()361 void AudioEndpointSeparate::ResyncPosition()
362 {
363 Trace loopTrace("AudioEndpoint::ResyncPosition");
364 uint64_t curHdiReadPos = 0;
365 int64_t readTime = 0;
366 if (!GetDeviceHandleInfo(curHdiReadPos, readTime)) {
367 AUDIO_ERR_LOG("ResyncPosition call GetDeviceHandleInfo failed.");
368 return;
369 }
370 int64_t curTime = ClockTime::GetCurNano();
371 int64_t temp = curTime - readTime;
372 if (temp > spanDuration_) {
373 AUDIO_ERR_LOG("GetDeviceHandleInfo may cost long time.");
374 }
375
376 dstAudioBuffer_->SetHandleInfo(curHdiReadPos, readTime);
377 }
378
StartDevice()379 bool AudioEndpointSeparate::StartDevice()
380 {
381 AUDIO_INFO_LOG("%{public}s enter.", __func__);
382 // how to modify the status while unlinked and started?
383 if (endpointStatus_ != IDEL) {
384 AUDIO_ERR_LOG("Endpoint status is not IDEL");
385 return false;
386 }
387 endpointStatus_ = STARTING;
388
389 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(fastRenderId_);
390 if (sink == nullptr || sink->Start() != SUCCESS) {
391 AUDIO_ERR_LOG("Sink start failed.");
392 return false;
393 }
394
395 std::unique_lock<std::mutex> lock(loopThreadLock_);
396 needResyncPosition_ = true;
397 endpointStatus_ = IsAnyProcessRunning() ? RUNNING : IDEL;
398 workThreadCV_.notify_all();
399 AUDIO_DEBUG_LOG("StartDevice out, status is %{public}s", GetStatusStr(endpointStatus_).c_str());
400 return true;
401 }
402
StopDevice()403 bool AudioEndpointSeparate::StopDevice()
404 {
405 AUDIO_INFO_LOG("StopDevice with status:%{public}s", GetStatusStr(endpointStatus_).c_str());
406 endpointStatus_ = STOPPING;
407 // Clear data buffer to avoid noise in some case.
408 if (dstAudioBuffer_ != nullptr) {
409 int32_t ret = memset_s(dstAudioBuffer_->GetDataBase(), dstAudioBuffer_->GetDataSize(), 0,
410 dstAudioBuffer_->GetDataSize());
411 if (ret != EOK) {
412 AUDIO_WARNING_LOG("memset_s failed. ret:%{public}d", ret);
413 }
414 }
415
416 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(fastRenderId_);
417 if (sink == nullptr || sink->Stop() != SUCCESS) {
418 AUDIO_ERR_LOG("Sink stop failed.");
419 return false;
420 }
421
422 endpointStatus_ = STOPPED;
423 return true;
424 }
425
OnStart(IAudioProcessStream * processStream)426 int32_t AudioEndpointSeparate::OnStart(IAudioProcessStream *processStream)
427 {
428 AUDIO_INFO_LOG("OnStart endpoint status:%{public}s", GetStatusStr(endpointStatus_).c_str());
429 if (endpointStatus_ == RUNNING) {
430 AUDIO_INFO_LOG("OnStart find endpoint already in RUNNING.");
431 return SUCCESS;
432 }
433 if (endpointStatus_ == IDEL && !isDeviceRunningInIdel_) {
434 // call sink start
435 StartDevice();
436 endpointStatus_ = RUNNING;
437 }
438 return SUCCESS;
439 }
440
OnPause(IAudioProcessStream * processStream)441 int32_t AudioEndpointSeparate::OnPause(IAudioProcessStream *processStream)
442 {
443 AUDIO_INFO_LOG("OnPause endpoint status:%{public}s", GetStatusStr(endpointStatus_).c_str());
444 if (endpointStatus_ == RUNNING) {
445 endpointStatus_ = IsAnyProcessRunning() ? RUNNING : IDEL;
446 }
447 if (endpointStatus_ == IDEL && !isDeviceRunningInIdel_) {
448 // call sink stop when no process running?
449 AUDIO_INFO_LOG("OnPause status is IDEL, call stop");
450 }
451 return SUCCESS;
452 }
453
GetProcLastWriteDoneInfo(const std::shared_ptr<OHAudioBuffer> processBuffer,uint64_t curWriteFrame,uint64_t & proHandleFrame,int64_t & proHandleTime)454 int32_t AudioEndpointSeparate::GetProcLastWriteDoneInfo(const std::shared_ptr<OHAudioBuffer> processBuffer,
455 uint64_t curWriteFrame, uint64_t &proHandleFrame, int64_t &proHandleTime)
456 {
457 CHECK_AND_RETURN_RET_LOG(processBuffer != nullptr, ERR_INVALID_HANDLE, "Process found but buffer is null");
458 uint64_t curReadFrame = processBuffer->GetCurReadFrame();
459 SpanInfo *curWriteSpan = processBuffer->GetSpanInfo(curWriteFrame);
460 CHECK_AND_RETURN_RET_LOG(curWriteSpan != nullptr, ERR_INVALID_HANDLE,
461 "%{public}s curWriteSpan of curWriteFrame %{public}" PRIu64" is null", __func__, curWriteFrame);
462 if (curWriteSpan->spanStatus == SpanStatus::SPAN_WRITE_DONE || curWriteFrame < dstSpanSizeInframe_ ||
463 curWriteFrame < curReadFrame) {
464 proHandleFrame = curWriteFrame;
465 proHandleTime = curWriteSpan->writeDoneTime;
466 } else {
467 int32_t ret = GetProcLastWriteDoneInfo(processBuffer, curWriteFrame - dstSpanSizeInframe_,
468 proHandleFrame, proHandleTime);
469 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret,
470 "%{public}s get process last write done info fail, ret %{public}d.", __func__, ret);
471 }
472
473 AUDIO_INFO_LOG("%{public}s end, curWriteFrame %{public}" PRIu64", proHandleFrame %{public}" PRIu64", "
474 "proHandleTime %{public}" PRId64".", __func__, curWriteFrame, proHandleFrame, proHandleTime);
475 return SUCCESS;
476 }
477
OnUpdateHandleInfo(IAudioProcessStream * processStream)478 int32_t AudioEndpointSeparate::OnUpdateHandleInfo(IAudioProcessStream *processStream)
479 {
480 Trace trace("separate AudioEndpoint::OnUpdateHandleInfo");
481 bool isFind = false;
482 std::lock_guard<std::mutex> lock(listLock_);
483 auto processItr = processList_.begin();
484 while (processItr != processList_.end()) {
485 if (*processItr != processStream) {
486 processItr++;
487 continue;
488 }
489 std::shared_ptr<OHAudioBuffer> processBuffer = (*processItr)->GetStreamBuffer();
490 CHECK_AND_RETURN_RET_LOG(processBuffer != nullptr, ERR_OPERATION_FAILED, "Process found but buffer is null");
491
492 ResyncPosition();
493 isFind = true;
494 break;
495 }
496 if (!isFind) {
497 AUDIO_ERR_LOG("Can not find any process to UpdateHandleInfo");
498 return ERR_OPERATION_FAILED;
499 }
500 return SUCCESS;
501 }
502
LinkProcessStream(IAudioProcessStream * processStream,bool startWhenLinking)503 int32_t AudioEndpointSeparate::LinkProcessStream(IAudioProcessStream *processStream, bool startWhenLinking)
504 {
505 CHECK_AND_RETURN_RET_LOG(processStream != nullptr, ERR_INVALID_PARAM, "IAudioProcessStream is null");
506 std::shared_ptr<OHAudioBuffer> processBuffer = processStream->GetStreamBuffer();
507 CHECK_AND_RETURN_RET_LOG(processBuffer != nullptr, ERR_INVALID_PARAM, "processBuffer is null");
508 CHECK_AND_RETURN_RET_LOG(processBuffer->GetStreamStatus() != nullptr, ERR_INVALID_PARAM,
509 "stream status is null");
510 CHECK_AND_RETURN_RET_LOG(processList_.size() < MAX_LINKED_PROCESS, ERR_OPERATION_FAILED, "reach link limit.");
511
512 AUDIO_INFO_LOG("LinkProcessStream endpoint status:%{public}s.", GetStatusStr(endpointStatus_).c_str());
513
514 bool needEndpointRunning = processBuffer->GetStreamStatus()->load() == STREAM_RUNNING;
515
516 if (endpointStatus_ == STARTING) {
517 AUDIO_INFO_LOG("LinkProcessStream wait start begin.");
518 std::unique_lock<std::mutex> lock(loopThreadLock_);
519 workThreadCV_.wait(lock, [this] {
520 return endpointStatus_ != STARTING;
521 });
522 AUDIO_DEBUG_LOG("LinkProcessStream wait start end.");
523 }
524
525 if (endpointStatus_ == RUNNING) {
526 std::lock_guard<std::mutex> lock(listLock_);
527 processList_.push_back(processStream);
528 processBufferList_.push_back(processBuffer);
529 AUDIO_DEBUG_LOG("LinkProcessStream success.");
530 return SUCCESS;
531 }
532
533 if (endpointStatus_ == UNLINKED) {
534 endpointStatus_ = IDEL; // handle push_back in IDEL
535 if (isDeviceRunningInIdel_) {
536 StartDevice();
537 }
538 }
539
540 if (endpointStatus_ == IDEL) {
541 {
542 std::lock_guard<std::mutex> lock(listLock_);
543 processList_.push_back(processStream);
544 processBufferList_.push_back(processBuffer);
545 }
546 if (!needEndpointRunning) {
547 AUDIO_DEBUG_LOG("LinkProcessStream success, process stream status is not running.");
548 return SUCCESS;
549 }
550 // needEndpointRunning = true
551 if (isDeviceRunningInIdel_) {
552 endpointStatus_ = IsAnyProcessRunning() ? RUNNING : IDEL;
553 } else {
554 // KeepWorkloopRunning will wait on IDEL
555 StartDevice();
556 }
557 AUDIO_DEBUG_LOG("LinkProcessStream success.");
558 return SUCCESS;
559 }
560
561 return SUCCESS;
562 }
563
UnlinkProcessStream(IAudioProcessStream * processStream)564 int32_t AudioEndpointSeparate::UnlinkProcessStream(IAudioProcessStream *processStream)
565 {
566 AUDIO_INFO_LOG("UnlinkProcessStream in status:%{public}s.", GetStatusStr(endpointStatus_).c_str());
567 CHECK_AND_RETURN_RET_LOG(processStream != nullptr, ERR_INVALID_PARAM, "IAudioProcessStream is null");
568 std::shared_ptr<OHAudioBuffer> processBuffer = processStream->GetStreamBuffer();
569 CHECK_AND_RETURN_RET_LOG(processBuffer != nullptr, ERR_INVALID_PARAM, "processBuffer is null");
570
571 bool isFind = false;
572 std::lock_guard<std::mutex> lock(listLock_);
573 auto processItr = processList_.begin();
574 auto bufferItr = processBufferList_.begin();
575 while (processItr != processList_.end()) {
576 if (*processItr == processStream && *bufferItr == processBuffer) {
577 processList_.erase(processItr);
578 processBufferList_.erase(bufferItr);
579 isFind = true;
580 break;
581 } else {
582 processItr++;
583 bufferItr++;
584 }
585 }
586 if (processList_.size() == 0) {
587 StopDevice();
588 endpointStatus_ = UNLINKED;
589 }
590
591 AUDIO_DEBUG_LOG("UnlinkProcessStream end, %{public}s the process.", (isFind ? "find and remove" : "not find"));
592 return SUCCESS;
593 }
594
ProcessData(const std::vector<AudioStreamData> & srcDataList,const AudioStreamData & dstData)595 void AudioEndpointSeparate::ProcessData(const std::vector<AudioStreamData> &srcDataList, const AudioStreamData &dstData)
596 {
597 size_t srcListSize = srcDataList.size();
598
599 for (size_t i = 0; i < srcListSize; i++) {
600 if (srcDataList[i].streamInfo.format != SAMPLE_S16LE || srcDataList[i].streamInfo.channels != STEREO ||
601 srcDataList[i].bufferDesc.bufLength != dstData.bufferDesc.bufLength ||
602 srcDataList[i].bufferDesc.dataLength != dstData.bufferDesc.dataLength) {
603 AUDIO_ERR_LOG("ProcessData failed, streamInfo are different");
604 return;
605 }
606 }
607
608 // Assum using the same format and same size
609 if (dstData.streamInfo.format != SAMPLE_S16LE || dstData.streamInfo.channels != STEREO) {
610 AUDIO_ERR_LOG("ProcessData failed, streamInfo are not support");
611 return;
612 }
613
614 size_t dataLength = dstData.bufferDesc.dataLength;
615 dataLength /= 2; // SAMPLE_S16LE--> 2 byte
616 int16_t *dstPtr = reinterpret_cast<int16_t *>(dstData.bufferDesc.buffer);
617 for (size_t offset = 0; dataLength > 0; dataLength--) {
618 int32_t sum = 0;
619 for (size_t i = 0; i < srcListSize; i++) {
620 int32_t vol = srcDataList[i].volumeStart; // change to modify volume of each channel
621 int16_t *srcPtr = reinterpret_cast<int16_t *>(srcDataList[i].bufferDesc.buffer) + offset;
622 sum += (*srcPtr * static_cast<int64_t>(vol)) >> VOLUME_SHIFT_NUMBER; // 1/65536
623 }
624 offset++;
625 *dstPtr++ = sum > INT16_MAX ? INT16_MAX : (sum < INT16_MIN ? INT16_MIN : sum);
626 }
627 }
628
GetDeviceHandleInfo(uint64_t & frames,int64_t & nanoTime)629 bool AudioEndpointSeparate::GetDeviceHandleInfo(uint64_t &frames, int64_t &nanoTime)
630 {
631 Trace trace("AE::GetMmapHP");
632 int64_t timeSec = 0;
633 int64_t timeNanoSec = 0;
634 int32_t ret = 0;
635
636 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(fastRenderId_);
637 if (sink == nullptr || !sink->IsInited()) {
638 AUDIO_ERR_LOG("GetDeviceHandleInfo failed: sink is not inited.");
639 return false;
640 }
641 // GetMmapHandlePosition will call using ipc.
642 ret = sink->GetMmapHandlePosition(frames, timeSec, timeNanoSec);
643 if (ret != SUCCESS) {
644 AUDIO_ERR_LOG("Call adapter GetMmapHandlePosition failed: %{public}d", ret);
645 return false;
646 }
647 trace.End();
648 nanoTime = timeNanoSec + timeSec * AUDIO_NS_PER_SECOND;
649 Trace infoTrace("AudioEndpoint::GetDeviceHandleInfo frames=>" + std::to_string(frames) + " " +
650 std::to_string(nanoTime) + " at " + std::to_string(ClockTime::GetCurNano()));
651 nanoTime += DELTA_TO_REAL_READ_START_TIME; // global delay in server
652 return true;
653 }
654
GetStatusStr(EndpointStatus status)655 std::string AudioEndpointSeparate::GetStatusStr(EndpointStatus status)
656 {
657 switch (status) {
658 case INVALID:
659 return "INVALID";
660 case UNLINKED:
661 return "UNLINKED";
662 case IDEL:
663 return "IDEL";
664 case STARTING:
665 return "STARTING";
666 case RUNNING:
667 return "RUNNING";
668 case STOPPING:
669 return "STOPPING";
670 case STOPPED:
671 return "STOPPED";
672 default:
673 break;
674 }
675 return "NO_SUCH_STATUS";
676 }
677
WriteToSpecialProcBuf(const std::shared_ptr<OHAudioBuffer> & procBuf,const BufferDesc & readBuf)678 int32_t AudioEndpointSeparate::WriteToSpecialProcBuf(const std::shared_ptr<OHAudioBuffer> &procBuf,
679 const BufferDesc &readBuf)
680 {
681 CHECK_AND_RETURN_RET_LOG(procBuf != nullptr, ERR_INVALID_HANDLE, "%{public}s process buffer is null.", __func__);
682 uint64_t curWritePos = procBuf->GetCurWriteFrame();
683 Trace trace("AudioEndpoint::WriteProcessData-<" + std::to_string(curWritePos));
684 SpanInfo *curWriteSpan = procBuf->GetSpanInfo(curWritePos);
685 CHECK_AND_RETURN_RET_LOG(curWriteSpan != nullptr, ERR_INVALID_HANDLE,
686 "%{public}s get write span info of procBuf fail.", __func__);
687
688 AUDIO_DEBUG_LOG("%{public}s process buffer write start, curWritePos %{public}" PRIu64".", __func__, curWritePos);
689 curWriteSpan->spanStatus.store(SpanStatus::SPAN_WRITTING);
690 curWriteSpan->writeStartTime = ClockTime::GetCurNano();
691
692 BufferDesc writeBuf;
693 int32_t ret = procBuf->GetWriteBuffer(curWritePos, writeBuf);
694 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "%{public}s get write buffer fail, ret %{public}d.", __func__, ret);
695 ret = memcpy_s(static_cast<void *>(writeBuf.buffer), writeBuf.bufLength,
696 static_cast<void *>(readBuf.buffer), readBuf.bufLength);
697 CHECK_AND_RETURN_RET_LOG(ret == EOK, ERR_WRITE_FAILED, "%{public}s memcpy data to process buffer fail, "
698 "curWritePos %{public}" PRIu64", ret %{public}d.", __func__, curWritePos, ret);
699
700 curWriteSpan->writeDoneTime = ClockTime::GetCurNano();
701 procBuf->SetHandleInfo(curWritePos, curWriteSpan->writeDoneTime);
702 ret = procBuf->SetCurWriteFrame(curWritePos + dstSpanSizeInframe_);
703 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "%{public}s set procBuf next write frame fail, ret %{public}d.",
704 __func__, ret);
705 curWriteSpan->spanStatus.store(SpanStatus::SPAN_WRITE_DONE);
706 return SUCCESS;
707 }
708
WriteToProcessBuffers(const BufferDesc & readBuf)709 void AudioEndpointSeparate::WriteToProcessBuffers(const BufferDesc &readBuf)
710 {
711 std::lock_guard<std::mutex> lock(listLock_);
712 for (size_t i = 0; i < processBufferList_.size(); i++) {
713 if (processBufferList_[i] == nullptr) {
714 AUDIO_ERR_LOG("%{public}s process buffer %{public}zu is null.", __func__, i);
715 continue;
716 }
717 if (processBufferList_[i]->GetStreamStatus() == nullptr) {
718 AUDIO_ERR_LOG("%{public}s process buffer %{public}zu has a null stream status.", __func__, i);
719 continue;
720 }
721 if (processBufferList_[i]->GetStreamStatus() &&
722 processBufferList_[i]->GetStreamStatus()->load() != STREAM_RUNNING) {
723 AUDIO_WARNING_LOG("%{public}s process buffer %{public}zu not running, stream status %{public}d.",
724 __func__, i, processBufferList_[i]->GetStreamStatus()->load());
725 continue;
726 }
727
728 int32_t ret = WriteToSpecialProcBuf(processBufferList_[i], readBuf);
729 if (ret != SUCCESS) {
730 AUDIO_ERR_LOG("%{public}s endpoint write to process buffer %{public}zu fail, ret %{public}d.",
731 __func__, i, ret);
732 continue;
733 }
734 AUDIO_DEBUG_LOG("%{public}s endpoint process buffer %{public}zu write success.", __func__, i);
735 }
736 }
737
GetMaxAmplitude()738 float AudioEndpointSeparate::GetMaxAmplitude()
739 {
740 AUDIO_WARNING_LOG("getMaxAmplitude in audioEndpointSeparate not support");
741 return 0;
742 }
743
GetLinkedProcessCount()744 uint32_t AudioEndpointSeparate::GetLinkedProcessCount()
745 {
746 std::lock_guard<std::mutex> lock(listLock_);
747 return processList_.size();
748 }
749
GetAudioMode() const750 AudioMode AudioEndpointSeparate::GetAudioMode() const
751 {
752 // AudioEndpointSeparate only support playback for now
753 return AUDIO_MODE_PLAYBACK;
754 }
755 } // namespace AudioStandard
756 } // namespace OHOS