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