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 ¶m)
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