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