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