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