1 /*
2  * Copyright (c) 2022-2024 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 
16 #include "dspeaker_dev.h"
17 
18 #include <algorithm>
19 #include <condition_variable>
20 #include <mutex>
21 #include <string>
22 #include <thread>
23 #include <securec.h>
24 
25 #include "daudio_constants.h"
26 #include "daudio_errorcode.h"
27 #include "daudio_hidumper.h"
28 #include "daudio_hisysevent.h"
29 #include "daudio_hitrace.h"
30 #include "daudio_log.h"
31 #include "daudio_source_manager.h"
32 #include "daudio_util.h"
33 
34 #undef DH_LOG_TAG
35 #define DH_LOG_TAG "DSpeakerDev"
36 
37 namespace OHOS {
38 namespace DistributedHardware {
EnableDevice(const int32_t dhId,const std::string & capability)39 int32_t DSpeakerDev::EnableDevice(const int32_t dhId, const std::string &capability)
40 {
41     DHLOGI("Enable IO device, device pin: %{public}d.", dhId);
42     int32_t ret = DAudioHdiHandler::GetInstance().RegisterAudioDevice(devId_, dhId, capability, shared_from_this());
43     if (ret != DH_SUCCESS) {
44         DHLOGE("Register device failed, ret: %{public}d.", ret);
45         DAudioHisysevent::GetInstance().SysEventWriteFault(DAUDIO_REGISTER_FAIL, devId_, std::to_string(dhId), ret,
46             "daudio register device failed.");
47         return ret;
48     }
49     dhId_ = dhId;
50     return DH_SUCCESS;
51 }
52 
DisableDevice(const int32_t dhId)53 int32_t DSpeakerDev::DisableDevice(const int32_t dhId)
54 {
55     DHLOGI("Disable IO device, device pin: %{public}d.", dhId);
56     int32_t ret = DAudioHdiHandler::GetInstance().UnRegisterAudioDevice(devId_, dhId);
57     if (ret != DH_SUCCESS) {
58         DHLOGE("UnRegister failed, ret: %{public}d.", ret);
59         DAudioHisysevent::GetInstance().SysEventWriteFault(DAUDIO_UNREGISTER_FAIL, devId_, std::to_string(dhId), ret,
60             "daudio unregister device failed.");
61         return ret;
62     }
63     return DH_SUCCESS;
64 }
65 
InitReceiverEngine(IAVEngineProvider * providerPtr)66 int32_t DSpeakerDev::InitReceiverEngine(IAVEngineProvider *providerPtr)
67 {
68     DHLOGI("InitReceiverEngine enter.");
69     return DH_SUCCESS;
70 }
71 
InitSenderEngine(IAVEngineProvider * providerPtr)72 int32_t DSpeakerDev::InitSenderEngine(IAVEngineProvider *providerPtr)
73 {
74     DHLOGI("InitSenderEngine enter");
75     if (speakerTrans_ == nullptr) {
76         speakerTrans_ = std::make_shared<AVTransSenderTransport>(devId_, shared_from_this());
77     }
78     int32_t ret = speakerTrans_->InitEngine(providerPtr);
79     if (ret != DH_SUCCESS) {
80         DHLOGE("Speaker dev initialize av sender adapter failed.");
81         return ret;
82     }
83     ret = speakerTrans_->CreateCtrl();
84     if (ret != DH_SUCCESS) {
85         DHLOGE("Create ctrl channel failed.");
86     }
87     return ret;
88 }
89 
OnEngineTransEvent(const AVTransEvent & event)90 void DSpeakerDev::OnEngineTransEvent(const AVTransEvent &event)
91 {
92     if (event.type == EventType::EVENT_START_SUCCESS) {
93         OnStateChange(DATA_OPENED);
94     } else if ((event.type == EventType::EVENT_STOP_SUCCESS) ||
95         (event.type == EventType::EVENT_CHANNEL_CLOSED) ||
96         (event.type == EventType::EVENT_START_FAIL)) {
97         OnStateChange(DATA_CLOSED);
98     }
99 }
100 
OnEngineTransMessage(const std::shared_ptr<AVTransMessage> & message)101 void DSpeakerDev::OnEngineTransMessage(const std::shared_ptr<AVTransMessage> &message)
102 {
103     CHECK_NULL_VOID(message);
104     DHLOGI("On Engine message, type : %{public}s.", GetEventNameByType(message->type_).c_str());
105     DAudioSourceManager::GetInstance().HandleDAudioNotify(message->dstDevId_, message->dstDevId_,
106         message->type_, message->content_);
107 }
108 
CreateStream(const int32_t streamId)109 int32_t DSpeakerDev::CreateStream(const int32_t streamId)
110 {
111     DHLOGI("Open stream of speaker device, streamId: %{public}d.", streamId);
112     std::shared_ptr<IAudioEventCallback> cbObj = audioEventCallback_.lock();
113     CHECK_NULL_RETURN(cbObj, ERR_DH_AUDIO_NULLPTR);
114 
115     cJSON *jParam = cJSON_CreateObject();
116     CHECK_NULL_RETURN(jParam, ERR_DH_AUDIO_NULLPTR);
117     cJSON_AddStringToObject(jParam, KEY_DH_ID, std::to_string(dhId_).c_str());
118     char *jsonData = cJSON_PrintUnformatted(jParam);
119     if (jsonData == nullptr) {
120         DHLOGE("Failed to create JSON data.");
121         cJSON_Delete(jParam);
122         return ERR_DH_AUDIO_NULLPTR;
123     }
124     std::string jsonDataStr(jsonData);
125     AudioEvent event(AudioEventType::OPEN_SPEAKER, jsonDataStr);
126     cbObj->NotifyEvent(event);
127     DAudioHisysevent::GetInstance().SysEventWriteBehavior(DAUDIO_OPEN, devId_, std::to_string(dhId_),
128         "daudio spk device open success.");
129     streamId_ = streamId;
130     cJSON_Delete(jParam);
131     cJSON_free(jsonData);
132     return DH_SUCCESS;
133 }
134 
DestroyStream(const int32_t streamId)135 int32_t DSpeakerDev::DestroyStream(const int32_t streamId)
136 {
137     DHLOGI("Close stream of speaker device streamId: %{public}d.",  streamId);
138     std::shared_ptr<IAudioEventCallback> cbObj = audioEventCallback_.lock();
139     CHECK_NULL_RETURN(cbObj, ERR_DH_AUDIO_NULLPTR);
140 
141     cJSON *jParam = cJSON_CreateObject();
142     CHECK_NULL_RETURN(jParam, ERR_DH_AUDIO_NULLPTR);
143     cJSON_AddStringToObject(jParam, KEY_DH_ID, std::to_string(dhId_).c_str());
144     char *jsonData = cJSON_PrintUnformatted(jParam);
145     if (jsonData == nullptr) {
146         DHLOGE("Failed to create JSON data.");
147         cJSON_Delete(jParam);
148         return ERR_DH_AUDIO_NULLPTR;
149     }
150     std::string jsonDataStr(jsonData);
151     AudioEvent event(AudioEventType::CLOSE_SPEAKER, jsonDataStr);
152     cbObj->NotifyEvent(event);
153     DAudioHisysevent::GetInstance().SysEventWriteBehavior(DAUDIO_CLOSE, devId_, std::to_string(dhId_),
154         "daudio spk device close success.");
155     curPort_ = 0;
156     cJSON_Delete(jParam);
157     cJSON_free(jsonData);
158     return DH_SUCCESS;
159 }
160 
SetParameters(const int32_t streamId,const AudioParamHDF & param)161 int32_t DSpeakerDev::SetParameters(const int32_t streamId, const AudioParamHDF &param)
162 {
163     DHLOGD("Set speaker parameters {samplerate: %{public}d, channelmask: %{public}d, format: %{public}d, "
164         "streamusage: %{public}d, period: %{public}d, framesize: %{public}d, renderFlags: %{public}d, "
165         "ext{%{public}s}}.", param.sampleRate, param.channelMask, param.bitFormat, param.streamUsage,
166         param.period, param.frameSize, param.renderFlags, param.ext.c_str());
167     curPort_ = dhId_;
168     paramHDF_ = param;
169 
170     param_.comParam.sampleRate = paramHDF_.sampleRate;
171     param_.comParam.channelMask = paramHDF_.channelMask;
172     param_.comParam.bitFormat = paramHDF_.bitFormat;
173     param_.comParam.codecType = AudioCodecType::AUDIO_CODEC_AAC;
174     param_.comParam.frameSize = paramHDF_.frameSize;
175     param_.renderOpts.contentType = CONTENT_TYPE_MUSIC;
176     param_.renderOpts.renderFlags = paramHDF_.renderFlags;
177     param_.renderOpts.streamUsage = paramHDF_.streamUsage;
178     return DH_SUCCESS;
179 }
180 
NotifyEvent(const int32_t streamId,const AudioEvent & event)181 int32_t DSpeakerDev::NotifyEvent(const int32_t streamId, const AudioEvent &event)
182 {
183     DHLOGD("Notify speaker event.");
184     std::shared_ptr<IAudioEventCallback> cbObj = audioEventCallback_.lock();
185     CHECK_NULL_RETURN(cbObj, ERR_DH_AUDIO_NULLPTR);
186     AudioEvent audioEvent(event.type, event.content);
187     cbObj->NotifyEvent(audioEvent);
188     return DH_SUCCESS;
189 }
190 
SetUp()191 int32_t DSpeakerDev::SetUp()
192 {
193     DHLOGI("Set up speaker device.");
194     CHECK_NULL_RETURN(speakerTrans_, ERR_DH_AUDIO_NULLPTR);
195 
196     int32_t ret = speakerTrans_->SetUp(param_, param_, shared_from_this(), CAP_SPK);
197     if (ret != DH_SUCCESS) {
198         DHLOGE("Speaker trans set up failed. ret:%{public}d", ret);
199         return ret;
200     }
201     DumpFileUtil::OpenDumpFile(DUMP_SERVER_PARA, SPK_DEV_FILENAME, &dumpFileCommn_);
202     DumpFileUtil::OpenDumpFile(DUMP_SERVER_PARA, SPK_LOWLATENCY_FILENAME, &dumpFileFast_);
203     return DH_SUCCESS;
204 }
205 
Start()206 int32_t DSpeakerDev::Start()
207 {
208     DHLOGI("Start speaker device.");
209     CHECK_NULL_RETURN(speakerTrans_, ERR_DH_AUDIO_NULLPTR);
210     int32_t ret = speakerTrans_->Start();
211     if (ret != DH_SUCCESS) {
212         DHLOGE("Speaker trans start failed, ret: %{public}d.", ret);
213         return ret;
214     }
215     std::unique_lock<std::mutex> lck(channelWaitMutex_);
216     auto status = channelWaitCond_.wait_for(lck, std::chrono::seconds(CHANNEL_WAIT_SECONDS),
217         [this]() { return isTransReady_.load(); });
218     if (!status) {
219         DHLOGE("Wait channel open timeout(%{public}ds).", CHANNEL_WAIT_SECONDS);
220         return ERR_DH_AUDIO_SA_WAIT_TIMEOUT;
221     }
222     isOpened_.store(true);
223     return DH_SUCCESS;
224 }
225 
Stop()226 int32_t DSpeakerDev::Stop()
227 {
228     DHLOGI("Stop speaker device.");
229     CHECK_NULL_RETURN(speakerTrans_, DH_SUCCESS);
230     isOpened_.store(false);
231     isTransReady_.store(false);
232     int32_t ret = speakerTrans_->Stop();
233     if (ret != DH_SUCCESS) {
234         DHLOGE("Stop speaker trans failed, ret: %{public}d.", ret);
235         return ret;
236     }
237     return DH_SUCCESS;
238 }
239 
Release()240 int32_t DSpeakerDev::Release()
241 {
242     DHLOGI("Release speaker device.");
243     if (ashmem_ != nullptr) {
244         ashmem_->UnmapAshmem();
245         ashmem_->CloseAshmem();
246         ashmem_ = nullptr;
247         DHLOGI("UnInit ashmem success.");
248     }
249     CHECK_NULL_RETURN(speakerTrans_, DH_SUCCESS);
250     int32_t ret = speakerTrans_->Release();
251     if (ret != DH_SUCCESS) {
252         DHLOGE("Release speaker trans failed, ret: %{public}d.", ret);
253     }
254     DumpFileUtil::CloseDumpFile(&dumpFileCommn_);
255     DumpFileUtil::CloseDumpFile(&dumpFileFast_);
256     return DH_SUCCESS;
257 }
258 
Pause()259 int32_t DSpeakerDev::Pause()
260 {
261     DHLOGI("Pause.");
262     CHECK_NULL_RETURN(speakerTrans_, ERR_DH_AUDIO_NULLPTR);
263     int32_t ret = speakerTrans_->Pause();
264     if (ret != DH_SUCCESS) {
265         DHLOGE("Pause speaker trans failed, ret: %{public}d.", ret);
266         return ret;
267     }
268     DHLOGD("Pause success.");
269     return DH_SUCCESS;
270 }
271 
Restart()272 int32_t DSpeakerDev::Restart()
273 {
274     DHLOGI("Restart.");
275     CHECK_NULL_RETURN(speakerTrans_, ERR_DH_AUDIO_NULLPTR);
276     int32_t ret = speakerTrans_->Restart(param_, param_);
277     if (ret != DH_SUCCESS) {
278         DHLOGE("Restart speaker trans failed, ret: %{public}d.", ret);
279         return ret;
280     }
281     DHLOGD("Restart success.");
282     return DH_SUCCESS;
283 }
284 
IsOpened()285 bool DSpeakerDev::IsOpened()
286 {
287     return isOpened_.load();
288 }
289 
ReadStreamData(const int32_t streamId,std::shared_ptr<AudioData> & data)290 int32_t DSpeakerDev::ReadStreamData(const int32_t streamId, std::shared_ptr<AudioData> &data)
291 {
292     (void)streamId;
293     (void)data;
294     DHLOGD("Dspeaker dev not support read stream data.");
295     return DH_SUCCESS;
296 }
297 
WriteStreamData(const int32_t streamId,std::shared_ptr<AudioData> & data)298 int32_t DSpeakerDev::WriteStreamData(const int32_t streamId, std::shared_ptr<AudioData> &data)
299 {
300     DHLOGD("Write stream data, streamId:%{public}d", streamId);
301     int64_t startTime = GetNowTimeUs();
302     CHECK_NULL_RETURN(speakerTrans_, ERR_DH_AUDIO_NULLPTR);
303     CHECK_NULL_RETURN(data, ERR_DH_AUDIO_NULLPTR);
304     DumpFileUtil::WriteDumpFile(dumpFileCommn_, static_cast<void *>(data->Data()), data->Size());
305     int32_t ret = speakerTrans_->FeedAudioData(data);
306     if (ret != DH_SUCCESS) {
307         DHLOGE("Write stream data failed, ret: %{public}d.", ret);
308         return ret;
309     }
310     int64_t endTime = GetNowTimeUs();
311     if (IsOutDurationRange(startTime, endTime, lastwriteStartTime_)) {
312         DHLOGE("This time write data spend: %{public}" PRId64" us, The interval of write data this time and "
313             "the last time: %{public}" PRId64" us", endTime - startTime, startTime - lastwriteStartTime_);
314     }
315     lastwriteStartTime_ = startTime;
316     return DH_SUCCESS;
317 }
318 
ReadMmapPosition(const int32_t streamId,uint64_t & frames,CurrentTimeHDF & time)319 int32_t DSpeakerDev::ReadMmapPosition(const int32_t streamId,
320     uint64_t &frames, CurrentTimeHDF &time)
321 {
322     DHLOGD("Read mmap position. frames: %{public}" PRIu64", tvsec: %{public}" PRId64", tvNSec:%{public}" PRId64,
323         readNum_, readTvSec_, readTvNSec_);
324     frames = readNum_;
325     time.tvSec = readTvSec_;
326     time.tvNSec = readTvNSec_;
327     return DH_SUCCESS;
328 }
329 
RefreshAshmemInfo(const int32_t streamId,int32_t fd,int32_t ashmemLength,int32_t lengthPerTrans)330 int32_t DSpeakerDev::RefreshAshmemInfo(const int32_t streamId,
331     int32_t fd, int32_t ashmemLength, int32_t lengthPerTrans)
332 {
333     DHLOGD("RefreshAshmemInfo: fd:%{public}d, ashmemLength: %{public}d, lengthPerTrans: %{public}d",
334         fd, ashmemLength, lengthPerTrans);
335     if (param_.renderOpts.renderFlags == MMAP_MODE) {
336         DHLOGI("DSpeaker dev low-latency mode");
337         if (ashmem_ != nullptr) {
338             return DH_SUCCESS;
339         }
340         if (ashmemLength < ASHMEM_MAX_LEN) {
341             ashmem_ = sptr<Ashmem>(new Ashmem(fd, ashmemLength));
342             ashmemLength_ = ashmemLength;
343             lengthPerTrans_ = lengthPerTrans;
344             DHLOGI("Create ashmem success. fd:%{public}d, ashmem length: %{public}d, lengthPreTrans: %{public}d",
345                 fd, ashmemLength_, lengthPerTrans_);
346             bool mapRet = ashmem_->MapReadAndWriteAshmem();
347             if (!mapRet) {
348                 DHLOGE("Mmap ashmem failed.");
349                 return ERR_DH_AUDIO_NULLPTR;
350             }
351         }
352     }
353     return DH_SUCCESS;
354 }
355 
MmapStart()356 int32_t DSpeakerDev::MmapStart()
357 {
358     CHECK_NULL_RETURN(ashmem_, ERR_DH_AUDIO_NULLPTR);
359     isEnqueueRunning_.store(true);
360     enqueueDataThread_ = std::thread([this]() { this->EnqueueThread(); });
361     if (pthread_setname_np(enqueueDataThread_.native_handle(), ENQUEUE_THREAD) != DH_SUCCESS) {
362         DHLOGE("Enqueue data thread setname failed.");
363     }
364     return DH_SUCCESS;
365 }
366 
EnqueueThread()367 void DSpeakerDev::EnqueueThread()
368 {
369     readIndex_ = 0;
370     readNum_ = 0;
371     frameIndex_ = 0;
372     int64_t timeIntervalns = static_cast<int64_t>(paramHDF_.period * AUDIO_NS_PER_SECOND / AUDIO_MS_PER_SECOND);
373     DHLOGI("Enqueue thread start, lengthPerRead length: %{public}d, interval: %{pubic}d.", lengthPerTrans_,
374         paramHDF_.period);
375     while (ashmem_ != nullptr && isEnqueueRunning_.load()) {
376         int64_t timeOffset = UpdateTimeOffset(frameIndex_, timeIntervalns, startTime_);
377         DHLOGD("Read frameIndex: %{public}" PRId64", timeOffset: %{public}" PRId64, frameIndex_, timeOffset);
378         auto readData = ashmem_->ReadFromAshmem(lengthPerTrans_, readIndex_);
379         DHLOGD("Read from ashmem success! read index: %{public}d, readLength: %{public}d.",
380             readIndex_, lengthPerTrans_);
381         std::shared_ptr<AudioData> audioData = std::make_shared<AudioData>(lengthPerTrans_);
382         if (readData != nullptr) {
383             const uint8_t *readAudioData = reinterpret_cast<const uint8_t *>(readData);
384             if (memcpy_s(audioData->Data(), audioData->Capacity(), readAudioData, param_.comParam.frameSize) != EOK) {
385                 DHLOGE("Copy audio data failed.");
386             }
387         }
388         CHECK_NULL_VOID(speakerTrans_);
389         DumpFileUtil::WriteDumpFile(dumpFileFast_, static_cast<void *>(audioData->Data()), audioData->Size());
390         int32_t ret = speakerTrans_->FeedAudioData(audioData);
391         if (ret != DH_SUCCESS) {
392             DHLOGE("Speaker enqueue thread, write stream data failed, ret: %{public}d.", ret);
393         }
394         readIndex_ += lengthPerTrans_;
395         if (readIndex_ >= ashmemLength_) {
396             readIndex_ = 0;
397         }
398         readNum_ += static_cast<uint64_t>(CalculateSampleNum(param_.comParam.sampleRate, paramHDF_.period));
399         GetCurrentTime(readTvSec_, readTvNSec_);
400         frameIndex_++;
401         AbsoluteSleep(startTime_ + frameIndex_ * timeIntervalns - timeOffset);
402     }
403 }
404 
MmapStop()405 int32_t DSpeakerDev::MmapStop()
406 {
407     isEnqueueRunning_.store(false);
408     if (enqueueDataThread_.joinable()) {
409         enqueueDataThread_.join();
410     }
411     DHLOGI("Spk mmap stop end.");
412     return DH_SUCCESS;
413 }
414 
GetAudioParam() const415 AudioParam DSpeakerDev::GetAudioParam() const
416 {
417     return param_;
418 }
419 
SendMessage(uint32_t type,std::string content,std::string dstDevId)420 int32_t DSpeakerDev::SendMessage(uint32_t type, std::string content, std::string dstDevId)
421 {
422     DHLOGD("Send message to remote.");
423     if (type != static_cast<uint32_t>(OPEN_SPEAKER) && type != static_cast<uint32_t>(CLOSE_SPEAKER) &&
424         type != static_cast<uint32_t>(CHANGE_PLAY_STATUS) && type != static_cast<uint32_t>(VOLUME_SET) &&
425         type != static_cast<uint32_t>(VOLUME_MUTE_SET)) {
426         DHLOGE("Send message to remote. not OPEN_SPK or CLOSE_SPK. type: %{public}u", type);
427         return ERR_DH_AUDIO_NULLPTR;
428     }
429     CHECK_NULL_RETURN(speakerTrans_, ERR_DH_AUDIO_NULLPTR);
430     speakerTrans_->SendMessage(type, content, dstDevId);
431     return DH_SUCCESS;
432 }
433 
NotifyHdfAudioEvent(const AudioEvent & event,const int32_t portId)434 int32_t DSpeakerDev::NotifyHdfAudioEvent(const AudioEvent &event, const int32_t portId)
435 {
436     int32_t ret = DAudioHdiHandler::GetInstance().NotifyEvent(devId_, portId, streamId_, event);
437     if (ret != DH_SUCCESS) {
438         DHLOGE("Notify event: %{public}d, result: %{public}s, streamId: %{public}d.",
439             event.type, event.content.c_str(), streamId_);
440     }
441     return DH_SUCCESS;
442 }
443 
OnStateChange(const AudioEventType type)444 int32_t DSpeakerDev::OnStateChange(const AudioEventType type)
445 {
446     DHLOGI("On speaker device state change, type: %{public}d.", type);
447     AudioEvent event;
448     switch (type) {
449         case AudioEventType::DATA_OPENED:
450             isTransReady_.store(true);
451             channelWaitCond_.notify_all();
452             event.type = AudioEventType::SPEAKER_OPENED;
453             break;
454         case AudioEventType::DATA_CLOSED:
455             isOpened_.store(false);
456             isTransReady_.store(false);
457             event.type = AudioEventType::SPEAKER_CLOSED;
458             break;
459         default:
460             break;
461     }
462     event.content = GetCJsonString(KEY_DH_ID, std::to_string(dhId_).c_str());
463     std::shared_ptr<IAudioEventCallback> cbObj = audioEventCallback_.lock();
464     CHECK_NULL_RETURN(cbObj, ERR_DH_AUDIO_NULLPTR);
465     cbObj->NotifyEvent(event);
466     return DH_SUCCESS;
467 }
468 
OnDecodeTransDataDone(const std::shared_ptr<AudioData> & audioData)469 int32_t DSpeakerDev::OnDecodeTransDataDone(const std::shared_ptr<AudioData> &audioData)
470 {
471     (void) audioData;
472     return DH_SUCCESS;
473 }
474 } // DistributedHardware
475 } // OHOS
476