1 /*
2 * Copyright (c) 2022 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 "audio_stream_mgr_napi.h"
17
18 #include "audio_common_napi.h"
19 #include "audio_errors.h"
20 #include "audio_log.h"
21 #include "hilog/log.h"
22 #include "napi_base_context.h"
23 #include "audio_capturer_state_callback_napi.h"
24 #include "audio_renderer_state_callback_napi.h"
25
26 using namespace std;
27 using OHOS::HiviewDFX::HiLog;
28 using OHOS::HiviewDFX::HiLogLabel;
29
30 namespace OHOS {
31 namespace AudioStandard {
32 static __thread napi_ref g_streamMgrConstructor = nullptr;
33
34 namespace {
35 const std::string RENDERERCHANGE_CALLBACK_NAME = "audioRendererChange";
36 const std::string CAPTURERCHANGE_CALLBACK_NAME = "audioCapturerChange";
37
38 const int ARGS_ONE = 1;
39 const int ARGS_TWO = 2;
40
41 const int PARAM0 = 0;
42 const int PARAM1 = 1;
43 const int PARAM2 = 2;
44 const int PARAM3 = 3;
45
46 constexpr HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AudioStreamManagerNapi"};
47
48 #define GET_PARAMS(env, info, num) \
49 size_t argc = num; \
50 napi_value argv[num] = {0}; \
51 napi_value thisVar = nullptr; \
52 void *data; \
53 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data)
54 }
55
56 struct AudioStreamMgrAsyncContext {
57 napi_env env;
58 napi_async_work work;
59 napi_deferred deferred;
60 napi_ref callbackRef = nullptr;
61 int32_t status = SUCCESS;
62 int32_t volType;
63 bool isTrue;
64 bool isLowLatencySupported;
65 bool isActive;
66 AudioStreamInfo audioStreamInfo;
67 AudioStreamMgrNapi *objectInfo;
68 vector<unique_ptr<AudioRendererChangeInfo>> audioRendererChangeInfos;
69 vector<unique_ptr<AudioCapturerChangeInfo>> audioCapturerChangeInfos;
70 };
71
AudioStreamMgrNapi()72 AudioStreamMgrNapi::AudioStreamMgrNapi()
73 : env_(nullptr), audioStreamMngr_(nullptr) {}
74
75 AudioStreamMgrNapi::~AudioStreamMgrNapi() = default;
76
Destructor(napi_env env,void * nativeObject,void * finalize_hint)77 void AudioStreamMgrNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
78 {
79 if (nativeObject != nullptr) {
80 auto obj = static_cast<AudioStreamMgrNapi *>(nativeObject);
81 delete obj;
82 obj = nullptr;
83 }
84 }
85
86
GetNativeAudioVolumeType(int32_t volumeType)87 static AudioVolumeType GetNativeAudioVolumeType(int32_t volumeType)
88 {
89 AudioVolumeType result = STREAM_MUSIC;
90
91 switch (volumeType) {
92 case AudioManagerNapi::RINGTONE:
93 result = STREAM_RING;
94 break;
95 case AudioManagerNapi::MEDIA:
96 result = STREAM_MUSIC;
97 break;
98 case AudioManagerNapi::VOICE_CALL:
99 result = STREAM_VOICE_CALL;
100 break;
101 case AudioManagerNapi::VOICE_ASSISTANT:
102 result = STREAM_VOICE_ASSISTANT;
103 break;
104 case AudioManagerNapi::ALL:
105 result = STREAM_ALL;
106 break;
107 default:
108 result = STREAM_MUSIC;
109 HiLog::Error(LABEL, "Unknown volume type, Set it to default MEDIA!");
110 break;
111 }
112
113 return result;
114 }
SetValueInt32(const napi_env & env,const std::string & fieldStr,const int intValue,napi_value & result)115 static void SetValueInt32(const napi_env& env, const std::string& fieldStr, const int intValue, napi_value &result)
116 {
117 napi_value value = nullptr;
118 napi_create_int32(env, intValue, &value);
119 napi_set_named_property(env, result, fieldStr.c_str(), value);
120 }
121
SetValueString(const napi_env & env,const std::string & fieldStr,const std::string stringValue,napi_value & result)122 static void SetValueString(const napi_env &env, const std::string &fieldStr, const std::string stringValue,
123 napi_value &result)
124 {
125 napi_value value = nullptr;
126 napi_create_string_utf8(env, stringValue.c_str(), NAPI_AUTO_LENGTH, &value);
127 napi_set_named_property(env, result, fieldStr.c_str(), value);
128 }
129
SetDeviceDescriptors(const napi_env & env,napi_value & jsChangeInfoObj,const DeviceInfo & deviceInfo)130 static void SetDeviceDescriptors(const napi_env& env, napi_value &jsChangeInfoObj, const DeviceInfo &deviceInfo)
131 {
132 napi_value jsDeviceDescriptorsObj = nullptr;
133 napi_value valueParam = nullptr;
134 napi_create_array_with_length(env, 1, &jsDeviceDescriptorsObj);
135
136 (void)napi_create_object(env, &valueParam);
137 SetValueInt32(env, "deviceRole", static_cast<int32_t>(deviceInfo.deviceRole), valueParam);
138 SetValueInt32(env, "deviceType", static_cast<int32_t>(deviceInfo.deviceType), valueParam);
139 SetValueInt32(env, "id", static_cast<int32_t>(deviceInfo.deviceId), valueParam);
140 SetValueString(env, "name", deviceInfo.deviceName, valueParam);
141 SetValueString(env, "address", deviceInfo.macAddress, valueParam);
142 SetValueString(env, "networkId", deviceInfo.networkId, valueParam);
143
144 napi_value value = nullptr;
145 napi_value sampleRates;
146 napi_create_array_with_length(env, 1, &sampleRates);
147 napi_create_int32(env, deviceInfo.audioStreamInfo.samplingRate, &value);
148 napi_set_element(env, sampleRates, 0, value);
149 napi_set_named_property(env, valueParam, "sampleRates", sampleRates);
150
151 napi_value channelCounts;
152 napi_create_array_with_length(env, 1, &channelCounts);
153 napi_create_int32(env, deviceInfo.audioStreamInfo.channels, &value);
154 napi_set_element(env, channelCounts, 0, value);
155 napi_set_named_property(env, valueParam, "channelCounts", channelCounts);
156
157 napi_value channelMasks;
158 napi_create_array_with_length(env, 1, &channelMasks);
159 napi_create_int32(env, deviceInfo.channelMasks, &value);
160 napi_set_element(env, channelMasks, 0, value);
161 napi_set_named_property(env, valueParam, "channelMasks", channelMasks);
162
163 napi_set_element(env, jsDeviceDescriptorsObj, 0, valueParam);
164 napi_set_named_property(env, jsChangeInfoObj, "deviceDescriptors", jsDeviceDescriptorsObj);
165 }
166
GetCurrentRendererChangeInfosCallbackComplete(napi_env env,napi_status status,void * data)167 static void GetCurrentRendererChangeInfosCallbackComplete(napi_env env, napi_status status, void *data)
168 {
169 auto asyncContext = static_cast<AudioStreamMgrAsyncContext*>(data);
170 napi_value result[ARGS_TWO] = {0};
171 napi_value jsChangeInfoObj = nullptr;
172 napi_value jsRenInfoObj = nullptr;
173 napi_value retVal;
174
175 size_t size = asyncContext->audioRendererChangeInfos.size();
176 int32_t position = 0;
177
178 napi_create_array_with_length(env, size, &result[PARAM1]);
179 for (const unique_ptr<AudioRendererChangeInfo> &changeInfo: asyncContext->audioRendererChangeInfos) {
180 if (!changeInfo) {
181 AUDIO_ERR_LOG("AudioStreamMgrNapi:AudioRendererChangeInfo Null, something wrong!!");
182 continue;
183 }
184
185 napi_create_object(env, &jsChangeInfoObj);
186 SetValueInt32(env, "streamId", changeInfo->sessionId, jsChangeInfoObj);
187 SetValueInt32(env, "rendererState", static_cast<int32_t>(changeInfo->rendererState), jsChangeInfoObj);
188 SetValueInt32(env, "clientUid", changeInfo->clientUID, jsChangeInfoObj);
189
190 napi_create_object(env, &jsRenInfoObj);
191 SetValueInt32(env, "content", static_cast<int32_t>(changeInfo->rendererInfo.contentType), jsRenInfoObj);
192 SetValueInt32(env, "usage", static_cast<int32_t>(changeInfo->rendererInfo.streamUsage), jsRenInfoObj);
193 SetValueInt32(env, "rendererFlags", changeInfo->rendererInfo.rendererFlags, jsRenInfoObj);
194 napi_set_named_property(env, jsChangeInfoObj, "rendererInfo", jsRenInfoObj);
195 SetDeviceDescriptors(env, jsChangeInfoObj, changeInfo->outputDeviceInfo);
196
197 napi_set_element(env, result[PARAM1], position, jsChangeInfoObj);
198 position++;
199 }
200
201 napi_get_undefined(env, &result[PARAM0]);
202
203 if (asyncContext->deferred) {
204 napi_resolve_deferred(env, asyncContext->deferred, result[PARAM1]);
205 } else {
206 napi_value callback = nullptr;
207 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
208 napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal);
209 napi_delete_reference(env, asyncContext->callbackRef);
210 }
211 napi_delete_async_work(env, asyncContext->work);
212
213 delete asyncContext;
214 }
215
GetCurrentCapturerChangeInfosCallbackComplete(napi_env env,napi_status status,void * data)216 static void GetCurrentCapturerChangeInfosCallbackComplete(napi_env env, napi_status status, void *data)
217 {
218 auto asyncContext = static_cast<AudioStreamMgrAsyncContext*>(data);
219 napi_value result[ARGS_TWO] = {0};
220 napi_value jsChangeInfoObj = nullptr;
221 napi_value jsCapInfoObj = nullptr;
222 napi_value retVal;
223
224 size_t size = asyncContext->audioCapturerChangeInfos.size();
225 int32_t position = 0;
226
227 napi_create_array_with_length(env, size, &result[PARAM1]);
228 for (const unique_ptr<AudioCapturerChangeInfo> &changeInfo: asyncContext->audioCapturerChangeInfos) {
229 if (!changeInfo) {
230 AUDIO_ERR_LOG("AudioStreamMgrNapi:AudioCapturerChangeInfo Null, something wrong!!");
231 continue;
232 }
233
234 napi_create_object(env, &jsChangeInfoObj);
235 SetValueInt32(env, "streamId", changeInfo->sessionId, jsChangeInfoObj);
236 SetValueInt32(env, "capturerState", static_cast<int32_t>(changeInfo->capturerState), jsChangeInfoObj);
237 SetValueInt32(env, "clientUid", changeInfo->clientUID, jsChangeInfoObj);
238
239 napi_create_object(env, &jsCapInfoObj);
240 SetValueInt32(env, "source", static_cast<int32_t>(changeInfo->capturerInfo.sourceType), jsCapInfoObj);
241 SetValueInt32(env, "capturerFlags", changeInfo->capturerInfo.capturerFlags, jsCapInfoObj);
242 napi_set_named_property(env, jsChangeInfoObj, "capturerInfo", jsCapInfoObj);
243 SetDeviceDescriptors(env, jsChangeInfoObj, changeInfo->inputDeviceInfo);
244
245 napi_set_element(env, result[PARAM1], position, jsChangeInfoObj);
246 position++;
247 }
248
249 napi_get_undefined(env, &result[PARAM0]);
250
251 if (asyncContext->deferred) {
252 napi_resolve_deferred(env, asyncContext->deferred, result[PARAM1]);
253 } else {
254 napi_value callback = nullptr;
255 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
256 napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal);
257 napi_delete_reference(env, asyncContext->callbackRef);
258 }
259 napi_delete_async_work(env, asyncContext->work);
260
261 delete asyncContext;
262 }
263
Init(napi_env env,napi_value exports)264 napi_value AudioStreamMgrNapi::Init(napi_env env, napi_value exports)
265 {
266 AUDIO_INFO_LOG("AudioStreamMgrNapi::Init");
267 napi_status status;
268 napi_value constructor;
269 napi_value result = nullptr;
270 const int32_t refCount = 1;
271 napi_get_undefined(env, &result);
272
273 napi_property_descriptor audio_stream_mgr_properties[] = {
274 DECLARE_NAPI_FUNCTION("on", On),
275 DECLARE_NAPI_FUNCTION("off", Off),
276 DECLARE_NAPI_FUNCTION("getCurrentAudioRendererInfoArray", GetCurrentAudioRendererInfos),
277 DECLARE_NAPI_FUNCTION("getCurrentAudioCapturerInfoArray", GetCurrentAudioCapturerInfos),
278 DECLARE_NAPI_FUNCTION("isAudioRendererLowLatencySupported", IsAudioRendererLowLatencySupported),
279 DECLARE_NAPI_FUNCTION("isActive", IsStreamActive),
280
281 };
282
283 status = napi_define_class(env, AUDIO_STREAM_MGR_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Construct, nullptr,
284 sizeof(audio_stream_mgr_properties) / sizeof(audio_stream_mgr_properties[PARAM0]),
285 audio_stream_mgr_properties, &constructor);
286 if (status != napi_ok) {
287 return result;
288 }
289
290 status = napi_create_reference(env, constructor, refCount, &g_streamMgrConstructor);
291 if (status == napi_ok) {
292 status = napi_set_named_property(env, exports, AUDIO_STREAM_MGR_NAPI_CLASS_NAME.c_str(), constructor);
293 if (status == napi_ok) {
294 return exports;
295 }
296 }
297
298 HiLog::Error(LABEL, "Failure in AudioStreamMgrNapi::Init()");
299 return result;
300 }
301
CreateStreamManagerWrapper(napi_env env)302 napi_value AudioStreamMgrNapi::CreateStreamManagerWrapper(napi_env env)
303 {
304 napi_status status;
305 napi_value result = nullptr;
306 napi_value constructor;
307
308 status = napi_get_reference_value(env, g_streamMgrConstructor, &constructor);
309 if (status == napi_ok) {
310 status = napi_new_instance(env, constructor, 0, nullptr, &result);
311 if (status == napi_ok) {
312 return result;
313 }
314 }
315 HiLog::Error(LABEL, "Failed in AudioStreamManagerNapi::CreateStreamMngrWrapper!");
316 napi_get_undefined(env, &result);
317
318 return result;
319 }
320
Construct(napi_env env,napi_callback_info info)321 napi_value AudioStreamMgrNapi::Construct(napi_env env, napi_callback_info info)
322 {
323 AUDIO_INFO_LOG("AudioStreamMgrNapi::Construct");
324 napi_status status;
325 napi_value result = nullptr;
326 napi_get_undefined(env, &result);
327
328 GET_PARAMS(env, info, ARGS_TWO);
329
330 unique_ptr<AudioStreamMgrNapi> streamMgrNapi = make_unique<AudioStreamMgrNapi>();
331 CHECK_AND_RETURN_RET_LOG(streamMgrNapi != nullptr, result, "No memory");
332
333 streamMgrNapi->env_ = env;
334 streamMgrNapi->audioStreamMngr_ = AudioStreamManager::GetInstance();
335 streamMgrNapi->cachedClientId_ = getpid();
336
337 status = napi_wrap(env, thisVar, static_cast<void*>(streamMgrNapi.get()),
338 AudioStreamMgrNapi::Destructor, nullptr, nullptr);
339 if (status == napi_ok) {
340 streamMgrNapi.release();
341 return thisVar;
342 }
343
344 HiLog::Error(LABEL, "Failed in AudioStreamManager::Construct()!");
345 return result;
346 }
347
RegisterRendererStateChangeCallback(napi_env env,napi_value * args,const std::string & cbName,AudioStreamMgrNapi * streamMgrNapi)348 void AudioStreamMgrNapi::RegisterRendererStateChangeCallback(napi_env env, napi_value* args,
349 const std::string& cbName, AudioStreamMgrNapi *streamMgrNapi)
350 {
351 if (!streamMgrNapi->rendererStateChangeCallbackNapi_) {
352 streamMgrNapi->rendererStateChangeCallbackNapi_ = std::make_shared<AudioRendererStateCallbackNapi>(env);
353 if (!streamMgrNapi->rendererStateChangeCallbackNapi_) {
354 AUDIO_ERR_LOG("AudioStreamMgrNapi: Memory Allocation Failed !!");
355 return;
356 }
357
358 int32_t ret =
359 streamMgrNapi->audioStreamMngr_->RegisterAudioRendererEventListener(streamMgrNapi->cachedClientId_,
360 streamMgrNapi->rendererStateChangeCallbackNapi_);
361 if (ret) {
362 AUDIO_ERR_LOG("AudioStreamMgrNapi: Registering of Renderer State Change Callback Failed");
363 return;
364 }
365 }
366
367 std::shared_ptr<AudioRendererStateCallbackNapi> cb =
368 std::static_pointer_cast<AudioRendererStateCallbackNapi>(streamMgrNapi->rendererStateChangeCallbackNapi_);
369 cb->SaveCallbackReference(args[PARAM1]);
370
371 AUDIO_INFO_LOG("AudioStreamMgrNapi::OnRendererStateChangeCallback is successful");
372 }
373
RegisterCapturerStateChangeCallback(napi_env env,napi_value * args,const std::string & cbName,AudioStreamMgrNapi * streamMgrNapi)374 void AudioStreamMgrNapi::RegisterCapturerStateChangeCallback(napi_env env, napi_value* args,
375 const std::string& cbName, AudioStreamMgrNapi *streamMgrNapi)
376 {
377 if (!streamMgrNapi->capturerStateChangeCallbackNapi_) {
378 streamMgrNapi->capturerStateChangeCallbackNapi_ = std::make_shared<AudioCapturerStateCallbackNapi>(env);
379 if (!streamMgrNapi->capturerStateChangeCallbackNapi_) {
380 AUDIO_ERR_LOG("AudioStreamMgrNapi: Memory Allocation Failed !!");
381 return;
382 }
383
384 int32_t ret =
385 streamMgrNapi->audioStreamMngr_->RegisterAudioCapturerEventListener(streamMgrNapi->cachedClientId_,
386 streamMgrNapi->capturerStateChangeCallbackNapi_);
387 if (ret) {
388 AUDIO_ERR_LOG("AudioStreamMgrNapi: Registering of Capturer State Change Callback Failed");
389 return;
390 }
391 }
392
393 std::shared_ptr<AudioCapturerStateCallbackNapi> cb =
394 std::static_pointer_cast<AudioCapturerStateCallbackNapi>(streamMgrNapi->capturerStateChangeCallbackNapi_);
395 cb->SaveCallbackReference(args[PARAM1]);
396
397 AUDIO_INFO_LOG("AudioStreamMgrNapi::OnCapturerStateChangeCallback is successful");
398 }
399
RegisterCallback(napi_env env,napi_value jsThis,napi_value * args,const std::string & cbName)400 void AudioStreamMgrNapi::RegisterCallback(napi_env env, napi_value jsThis,
401 napi_value* args, const std::string& cbName)
402 {
403 AudioStreamMgrNapi *streamMgrNapi = nullptr;
404 napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&streamMgrNapi));
405 if ((status != napi_ok) || (streamMgrNapi == nullptr) || (streamMgrNapi->audioStreamMngr_ == nullptr)) {
406 AUDIO_ERR_LOG("AudioStreamMgrNapi::Failed to retrieve stream mgr napi instance.");
407 return;
408 }
409
410 if (!cbName.compare(RENDERERCHANGE_CALLBACK_NAME)) {
411 RegisterRendererStateChangeCallback(env, args, cbName, streamMgrNapi);
412 } else if (!cbName.compare(CAPTURERCHANGE_CALLBACK_NAME)) {
413 RegisterCapturerStateChangeCallback(env, args, cbName, streamMgrNapi);
414 } else {
415 AUDIO_ERR_LOG("AudioStreamMgrNapi::No such callback supported");
416 AudioCommonNapi::throwError(env, NAPI_ERR_INVALID_PARAM);
417 }
418 }
419
On(napi_env env,napi_callback_info info)420 napi_value AudioStreamMgrNapi::On(napi_env env, napi_callback_info info)
421 {
422 const size_t requireArgc = PARAM2;
423 size_t argc = PARAM3;
424
425 napi_value undefinedResult = nullptr;
426 napi_get_undefined(env, &undefinedResult);
427
428 napi_value args[requireArgc + 1] = {nullptr, nullptr, nullptr};
429 napi_value jsThis = nullptr;
430 napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
431 THROW_ERROR_ASSERT(env, status == napi_ok && argc == requireArgc, NAPI_ERR_INPUT_INVALID);
432
433 napi_valuetype eventType = napi_undefined;
434 napi_typeof(env, args[0], &eventType);
435 THROW_ERROR_ASSERT(env, eventType == napi_string, NAPI_ERR_INPUT_INVALID);
436
437 std::string callbackName = AudioCommonNapi::GetStringArgument(env, args[0]);
438 AUDIO_DEBUG_LOG("AudioStreamMgrNapi: On callbackName: %{public}s", callbackName.c_str());
439
440 napi_valuetype handler = napi_undefined;
441
442 napi_typeof(env, args[1], &handler);
443 THROW_ERROR_ASSERT(env, handler == napi_function, NAPI_ERR_INPUT_INVALID);
444
445 RegisterCallback(env, jsThis, args, callbackName);
446
447 return undefinedResult;
448 }
449
UnregisterCallback(napi_env env,napi_value jsThis,const std::string & cbName)450 void AudioStreamMgrNapi::UnregisterCallback(napi_env env, napi_value jsThis, const std::string& cbName)
451 {
452 AUDIO_INFO_LOG("AudioStreamMgrNapi::UnregisterCallback");
453 AudioStreamMgrNapi *streamMgrNapi = nullptr;
454 napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&streamMgrNapi));
455 if ((status != napi_ok) || (streamMgrNapi == nullptr) || (streamMgrNapi->audioStreamMngr_ == nullptr)) {
456 AUDIO_ERR_LOG("AudioStreamMgrNapi::Failed to retrieve stream mgr napi instance.");
457 return;
458 }
459
460 if (!cbName.compare(RENDERERCHANGE_CALLBACK_NAME)) {
461 int32_t ret = streamMgrNapi->audioStreamMngr_->
462 UnregisterAudioRendererEventListener(streamMgrNapi->cachedClientId_);
463 if (ret) {
464 AUDIO_ERR_LOG("AudioStreamMgrNapi:UnRegistering of Renderer State Change Callback Failed");
465 return;
466 }
467 if (streamMgrNapi->rendererStateChangeCallbackNapi_ != nullptr) {
468 streamMgrNapi->rendererStateChangeCallbackNapi_.reset();
469 streamMgrNapi->rendererStateChangeCallbackNapi_ = nullptr;
470 }
471 AUDIO_INFO_LOG("AudioStreamMgrNapi:UnRegistering of renderer State Change Callback successful");
472 } else if (!cbName.compare(CAPTURERCHANGE_CALLBACK_NAME)) {
473 int32_t ret = streamMgrNapi->audioStreamMngr_->
474 UnregisterAudioCapturerEventListener(streamMgrNapi->cachedClientId_);
475 if (ret) {
476 AUDIO_ERR_LOG("AudioStreamMgrNapi:UnRegistering of capturer State Change Callback Failed");
477 return;
478 }
479 if (streamMgrNapi->capturerStateChangeCallbackNapi_ != nullptr) {
480 streamMgrNapi->capturerStateChangeCallbackNapi_.reset();
481 streamMgrNapi->capturerStateChangeCallbackNapi_ = nullptr;
482 }
483 AUDIO_INFO_LOG("AudioStreamMgrNapi:UnRegistering of capturer State Change Callback successful");
484 } else {
485 AUDIO_ERR_LOG("AudioStreamMgrNapi::No such callback supported");
486 AudioCommonNapi::throwError(env, NAPI_ERR_INVALID_PARAM);
487 }
488 }
489
Off(napi_env env,napi_callback_info info)490 napi_value AudioStreamMgrNapi::Off(napi_env env, napi_callback_info info)
491 {
492 const size_t requireArgc = 1;
493 size_t argc = 1;
494
495 napi_value undefinedResult = nullptr;
496 napi_get_undefined(env, &undefinedResult);
497
498 napi_value args[requireArgc] = {nullptr};
499 napi_value jsThis = nullptr;
500 napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
501 THROW_ERROR_ASSERT(env, status == napi_ok && argc >= requireArgc, NAPI_ERR_INPUT_INVALID);
502
503 napi_valuetype eventType = napi_undefined;
504 napi_typeof(env, args[0], &eventType);
505 THROW_ERROR_ASSERT(env, eventType == napi_string, NAPI_ERR_INPUT_INVALID);
506
507 std::string callbackName = AudioCommonNapi::GetStringArgument(env, args[0]);
508 AUDIO_DEBUG_LOG("AudioStreamMgrNapi: Off callbackName: %{public}s", callbackName.c_str());
509
510 UnregisterCallback(env, jsThis, callbackName);
511 return undefinedResult;
512 }
513
GetCurrentAudioRendererInfos(napi_env env,napi_callback_info info)514 napi_value AudioStreamMgrNapi::GetCurrentAudioRendererInfos(napi_env env, napi_callback_info info)
515 {
516 napi_status status;
517 const int32_t refCount = 1;
518 napi_value result = nullptr;
519
520 GET_PARAMS(env, info, ARGS_ONE);
521
522 unique_ptr<AudioStreamMgrAsyncContext> asyncContext = make_unique<AudioStreamMgrAsyncContext>();
523 if (!asyncContext) {
524 AUDIO_ERR_LOG("AudioStreamMgrNapi:Audio manager async context failed");
525 return result;
526 }
527
528 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
529 if ((status == napi_ok && asyncContext->objectInfo != nullptr)
530 && (asyncContext->objectInfo->audioStreamMngr_ != nullptr)) {
531 for (size_t i = PARAM0; i < argc; i++) {
532 napi_valuetype valueType = napi_undefined;
533 napi_typeof(env, argv[i], &valueType);
534
535 if (i == PARAM0) {
536 if (valueType == napi_function) {
537 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
538 }
539 break;
540 } else {
541 asyncContext->status = NAPI_ERR_INVALID_PARAM;
542 }
543 }
544
545 if (asyncContext->callbackRef == nullptr) {
546 napi_create_promise(env, &asyncContext->deferred, &result);
547 } else {
548 napi_get_undefined(env, &result);
549 }
550
551 napi_value resource = nullptr;
552 napi_create_string_utf8(env, "getCurrentAudioRendererInfoArray", NAPI_AUTO_LENGTH, &resource);
553
554 status = napi_create_async_work(
555 env, nullptr, resource,
556 [](napi_env env, void *data) {
557 auto context = static_cast<AudioStreamMgrAsyncContext *>(data);
558 if (context->status == SUCCESS) {
559 context->status = context->objectInfo->audioStreamMngr_->
560 GetCurrentRendererChangeInfos(context->audioRendererChangeInfos);
561 context->status = context->status == SUCCESS ? SUCCESS : NAPI_ERR_SYSTEM;
562 }
563 },
564 GetCurrentRendererChangeInfosCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
565 if (status != napi_ok) {
566 result = nullptr;
567 } else {
568 status = napi_queue_async_work(env, asyncContext->work);
569 if (status == napi_ok) {
570 asyncContext.release();
571 } else {
572 result = nullptr;
573 }
574 }
575 }
576
577 return result;
578 }
579
GetCurrentAudioCapturerInfos(napi_env env,napi_callback_info info)580 napi_value AudioStreamMgrNapi::GetCurrentAudioCapturerInfos(napi_env env, napi_callback_info info)
581 {
582 napi_status status;
583 const int32_t refCount = 1;
584 napi_value result = nullptr;
585
586 GET_PARAMS(env, info, ARGS_ONE);
587
588 unique_ptr<AudioStreamMgrAsyncContext> asyncContext = make_unique<AudioStreamMgrAsyncContext>();
589 if (!asyncContext) {
590 AUDIO_ERR_LOG("AudioStreamMgrNapi:async context memory alloc failed");
591 return result;
592 }
593
594 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
595 if ((status == napi_ok && asyncContext->objectInfo != nullptr)
596 && (asyncContext->objectInfo->audioStreamMngr_ != nullptr)) {
597 for (size_t i = PARAM0; i < argc; i++) {
598 napi_valuetype valueType = napi_undefined;
599 napi_typeof(env, argv[i], &valueType);
600
601 if (i == PARAM0) {
602 if (valueType == napi_function) {
603 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
604 }
605 break;
606 } else {
607 asyncContext->status = NAPI_ERR_INVALID_PARAM;
608 }
609 }
610
611 if (asyncContext->callbackRef == nullptr) {
612 napi_create_promise(env, &asyncContext->deferred, &result);
613 } else {
614 napi_get_undefined(env, &result);
615 }
616
617 napi_value resource = nullptr;
618 napi_create_string_utf8(env, "getCurrentAudioCapturerInfoArray", NAPI_AUTO_LENGTH, &resource);
619
620 status = napi_create_async_work(
621 env, nullptr, resource,
622 [](napi_env env, void *data) {
623 auto context = static_cast<AudioStreamMgrAsyncContext*>(data);
624 if (context->status == SUCCESS) {
625 context->objectInfo->audioStreamMngr_->
626 GetCurrentCapturerChangeInfos(context->audioCapturerChangeInfos);
627 context->status = SUCCESS;
628 }
629 },
630 GetCurrentCapturerChangeInfosCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
631 if (status != napi_ok) {
632 result = nullptr;
633 } else {
634 status = napi_queue_async_work(env, asyncContext->work);
635 if (status == napi_ok) {
636 asyncContext.release();
637 } else {
638 result = nullptr;
639 }
640 }
641 }
642
643 return result;
644 }
645
IsAudioRendererLowLatencySupported(napi_env env,napi_callback_info info)646 napi_value AudioStreamMgrNapi::IsAudioRendererLowLatencySupported(napi_env env, napi_callback_info info)
647 {
648 napi_status status;
649 napi_value result = nullptr;
650 const int32_t refCount = 1;
651 napi_get_undefined(env, &result);
652 GET_PARAMS(env, info, ARGS_TWO);
653 unique_ptr<AudioStreamMgrAsyncContext> asyncContext = make_unique<AudioStreamMgrAsyncContext>();
654 CHECK_AND_RETURN_RET_LOG(asyncContext != nullptr, result, "No memory");
655 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
656 if (status != napi_ok) {
657 return result;
658 }
659
660 for (size_t i = PARAM0; i < argc; i++) {
661 napi_valuetype valueType = napi_undefined;
662 napi_typeof(env, argv[i], &valueType);
663 if (i == PARAM0 && valueType == napi_object) {
664 if (!ParseAudioStreamInfo(env, argv[i], asyncContext->audioStreamInfo)) {
665 HiLog::Error(LABEL, "Parsing of audiostream failed");
666 asyncContext->status = asyncContext->status ==
667 NAPI_ERR_INVALID_PARAM ? NAPI_ERR_INVALID_PARAM : NAPI_ERR_UNSUPPORTED;
668 }
669 } else if (i == PARAM1) {
670 if (valueType == napi_function) {
671 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
672 }
673 break;
674 } else {
675 asyncContext->status = NAPI_ERR_INVALID_PARAM;
676 }
677 }
678 if (asyncContext->callbackRef == nullptr) {
679 napi_create_promise(env, &asyncContext->deferred, &result);
680 } else {
681 napi_get_undefined(env, &result);
682 }
683
684 napi_value resource = nullptr;
685 napi_create_string_utf8(env, "IsAudioRendererLowLatencySupported", NAPI_AUTO_LENGTH, &resource);
686 status = napi_create_async_work(
687 env, nullptr, resource,
688 [](napi_env env, void *data) {
689 auto context = static_cast<AudioStreamMgrAsyncContext*>(data);
690 if (context->status == SUCCESS) {
691 context->isLowLatencySupported =
692 context->objectInfo->audioStreamMngr_->IsAudioRendererLowLatencySupported(context->audioStreamInfo);
693 context->isTrue = context->isLowLatencySupported;
694 context->status = SUCCESS;
695 }
696 },
697 IsLowLatencySupportedCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
698 if (status != napi_ok) {
699 result = nullptr;
700 } else {
701 status = napi_queue_async_work(env, asyncContext->work);
702 if (status == napi_ok) {
703 asyncContext.release();
704 } else {
705 result = nullptr;
706 }
707 }
708
709 return result;
710 }
711
ParseAudioStreamInfo(napi_env env,napi_value root,AudioStreamInfo & audioStreamInfo)712 bool AudioStreamMgrNapi::ParseAudioStreamInfo(napi_env env, napi_value root, AudioStreamInfo &audioStreamInfo)
713 {
714 napi_value tempValue = nullptr;
715 int32_t intValue = {0};
716
717 if (napi_get_named_property(env, root, "samplingRate", &tempValue) == napi_ok) {
718 napi_get_value_int32(env, tempValue, &intValue);
719 audioStreamInfo.samplingRate = static_cast<AudioSamplingRate>(intValue);
720 }
721
722 if (napi_get_named_property(env, root, "channels", &tempValue) == napi_ok) {
723 napi_get_value_int32(env, tempValue, &intValue);
724 audioStreamInfo.channels = static_cast<AudioChannel>(intValue);
725 }
726
727 if (napi_get_named_property(env, root, "sampleFormat", &tempValue) == napi_ok) {
728 napi_get_value_int32(env, tempValue, &intValue);
729 audioStreamInfo.format = static_cast<OHOS::AudioStandard::AudioSampleFormat>(intValue);
730 }
731
732 if (napi_get_named_property(env, root, "encodingType", &tempValue) == napi_ok) {
733 napi_get_value_int32(env, tempValue, &intValue);
734 audioStreamInfo.encoding = static_cast<AudioEncodingType>(intValue);
735 }
736
737 return true;
738 }
739
CommonCallbackRoutine(napi_env env,AudioStreamMgrAsyncContext * & asyncContext,const napi_value & valueParam)740 static void CommonCallbackRoutine(napi_env env, AudioStreamMgrAsyncContext* &asyncContext,
741 const napi_value &valueParam)
742 {
743 napi_value result[ARGS_TWO] = {0};
744 napi_value retVal;
745
746 if (!asyncContext->status) {
747 napi_get_undefined(env, &result[PARAM0]);
748 result[PARAM1] = valueParam;
749 } else {
750 napi_value message = nullptr;
751 std::string messageValue = AudioCommonNapi::getMessageByCode(asyncContext->status);
752 napi_create_string_utf8(env, messageValue.c_str(), NAPI_AUTO_LENGTH, &message);
753
754 napi_value code = nullptr;
755 napi_create_string_utf8(env, (std::to_string(asyncContext->status)).c_str(), NAPI_AUTO_LENGTH, &code);
756
757 napi_create_error(env, code, message, &result[PARAM0]);
758 napi_get_undefined(env, &result[PARAM1]);
759 }
760
761 if (asyncContext->deferred) {
762 if (!asyncContext->status) {
763 napi_resolve_deferred(env, asyncContext->deferred, result[PARAM1]);
764 } else {
765 napi_reject_deferred(env, asyncContext->deferred, result[PARAM0]);
766 }
767 } else {
768 napi_value callback = nullptr;
769 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
770 napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal);
771 napi_delete_reference(env, asyncContext->callbackRef);
772 }
773 napi_delete_async_work(env, asyncContext->work);
774
775 delete asyncContext;
776 asyncContext = nullptr;
777 }
778
IsLowLatencySupportedCallback(napi_env env,napi_status status,void * data)779 void AudioStreamMgrNapi::IsLowLatencySupportedCallback(napi_env env, napi_status status, void *data)
780 {
781 auto asyncContext = static_cast<AudioStreamMgrAsyncContext*>(data);
782 napi_value valueParam = nullptr;
783
784 if (asyncContext != nullptr) {
785 if (!asyncContext->status) {
786 napi_get_boolean(env, asyncContext->isTrue, &valueParam);
787 }
788 CommonCallbackRoutine(env, asyncContext, valueParam);
789 } else {
790 HiLog::Error(LABEL, "ERROR: AudioStreamMgrAsyncContext* is Null!");
791 }
792 }
793
794
IsTrueAsyncCallbackComplete(napi_env env,napi_status status,void * data)795 static void IsTrueAsyncCallbackComplete(napi_env env, napi_status status, void *data)
796 {
797 auto asyncContext = static_cast<AudioStreamMgrAsyncContext*>(data);
798 napi_value valueParam = nullptr;
799
800 if (asyncContext != nullptr) {
801 if (!asyncContext->status) {
802 napi_get_boolean(env, asyncContext->isTrue, &valueParam);
803 }
804 CommonCallbackRoutine(env, asyncContext, valueParam);
805 } else {
806 HiLog::Error(LABEL, "ERROR: AudioStreamMgrAsyncContext* is Null!");
807 }
808 }
809
IsStreamActive(napi_env env,napi_callback_info info)810 napi_value AudioStreamMgrNapi::IsStreamActive(napi_env env, napi_callback_info info)
811 {
812 napi_status status;
813 const int32_t refCount = 1;
814 napi_value result = nullptr;
815
816 GET_PARAMS(env, info, ARGS_TWO);
817
818 unique_ptr<AudioStreamMgrAsyncContext> asyncContext = make_unique<AudioStreamMgrAsyncContext>();
819
820 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
821 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
822 if (argc < ARGS_ONE) {
823 asyncContext->status = NAPI_ERR_INVALID_PARAM;
824 }
825 for (size_t i = PARAM0; i < argc; i++) {
826 napi_valuetype valueType = napi_undefined;
827 napi_typeof(env, argv[i], &valueType);
828
829 if (i == PARAM0 && valueType == napi_number) {
830 napi_get_value_int32(env, argv[i], &asyncContext->volType);
831 if (!AudioCommonNapi::IsLegalInputArgumentVolType(asyncContext->volType)) {
832 asyncContext->status = (asyncContext->status ==
833 NAPI_ERR_INVALID_PARAM) ? NAPI_ERR_INVALID_PARAM : NAPI_ERR_UNSUPPORTED;
834 }
835 } else if (i == PARAM1) {
836 if (valueType == napi_function) {
837 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
838 }
839 break;
840 } else {
841 asyncContext->status = NAPI_ERR_INVALID_PARAM;
842 }
843 }
844
845 if (asyncContext->callbackRef == nullptr) {
846 napi_create_promise(env, &asyncContext->deferred, &result);
847 } else {
848 napi_get_undefined(env, &result);
849 }
850
851 napi_value resource = nullptr;
852 napi_create_string_utf8(env, "IsStreamActive", NAPI_AUTO_LENGTH, &resource);
853
854 status = napi_create_async_work(
855 env, nullptr, resource,
856 [](napi_env env, void *data) {
857 auto context = static_cast<AudioStreamMgrAsyncContext*>(data);
858 if (context->status == SUCCESS) {
859 context->isActive =
860 context->objectInfo->audioMngr_->IsStreamActive(GetNativeAudioVolumeType(context->volType));
861 context->isTrue = context->isActive;
862 context->status = SUCCESS;
863 }
864 },
865 IsTrueAsyncCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
866 if (status != napi_ok) {
867 result = nullptr;
868 } else {
869 status = napi_queue_async_work(env, asyncContext->work);
870 if (status == napi_ok) {
871 asyncContext.release();
872 } else {
873 result = nullptr;
874 }
875 }
876 }
877
878 return result;
879 }
880 } // namespace AudioStandard
881 } // namespace OHOS
882