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