• 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_volume_manager_napi.h"
17 #include "audio_volume_group_manager_napi.h"
18 
19 #include "audio_common_napi.h"
20 #include "audio_volume_key_event_napi.h"
21 #include "audio_errors.h"
22 #include "audio_log.h"
23 #include "hilog/log.h"
24 #include "napi_base_context.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_volumeManagerConstructor = nullptr;
33 
34 namespace {
35     const int ARGS_ONE = 1;
36     const int ARGS_TWO = 2;
37     const int PARAM0 = 0;
38     const int PARAM1 = 1;
39     constexpr HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AudioVolumeManagerNapi"};
40     const std::string VOLUME_CHANGE_CALLBACK_NAME = "volumeChange";
41 }
42 
43 struct AudioVolumeManagerAsyncContext {
44     napi_env env;
45     napi_async_work work;
46     napi_deferred deferred;
47     napi_ref callbackRef = nullptr;
48     int32_t deviceFlag;
49     bool bArgTransFlag = true;
50     int32_t status = SUCCESS;
51     int32_t groupId;
52     int32_t intValue;
53     int32_t ringMode;
54     bool isMute;
55     bool isTrue;
56     std::string networkId;
57     AudioVolumeManagerNapi *objectInfo;
58     vector<sptr<VolumeGroupInfo>> volumeGroupInfos;
59 };
60 
AudioVolumeManagerNapi()61 AudioVolumeManagerNapi::AudioVolumeManagerNapi()
62     : audioSystemMngr_(nullptr), env_(nullptr) {}
63 
64 AudioVolumeManagerNapi::~AudioVolumeManagerNapi() = default;
65 
Destructor(napi_env env,void * nativeObject,void * finalize_hint)66 void AudioVolumeManagerNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
67 {
68     if (nativeObject != nullptr) {
69         auto obj = static_cast<AudioVolumeManagerNapi *>(nativeObject);
70         delete obj;
71         obj = nullptr;
72     }
73 }
74 
Construct(napi_env env,napi_callback_info info)75 napi_value AudioVolumeManagerNapi::Construct(napi_env env, napi_callback_info info)
76 {
77     AUDIO_INFO_LOG("AudioVolumeManagerNapi::Construct");
78     napi_status status;
79     napi_value result = nullptr;
80     napi_get_undefined(env, &result);
81 
82     size_t argc = ARGS_TWO;
83     napi_value argv[ARGS_TWO] = {0};
84     napi_value thisVar = nullptr;
85     void *data = nullptr;
86 
87     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
88     unique_ptr<AudioVolumeManagerNapi> audioVolumeManagerNapi = make_unique<AudioVolumeManagerNapi>();
89     CHECK_AND_RETURN_RET_LOG(audioVolumeManagerNapi != nullptr, result, "No memory");
90 
91     audioVolumeManagerNapi->audioSystemMngr_ = AudioSystemManager::GetInstance();
92     audioVolumeManagerNapi->env_ = env;
93     audioVolumeManagerNapi->cachedClientId_ = getpid();
94 
95     status = napi_wrap(env, thisVar, static_cast<void*>(audioVolumeManagerNapi.get()),
96         AudioVolumeManagerNapi::Destructor, nullptr, nullptr);
97     if (status == napi_ok) {
98         audioVolumeManagerNapi.release();
99         return thisVar;
100     }
101 
102     HiLog::Error(LABEL, "Failed in AudioVolumeManager::Construct()!");
103     return result;
104 }
105 
CreateVolumeManagerWrapper(napi_env env)106 napi_value AudioVolumeManagerNapi::CreateVolumeManagerWrapper(napi_env env)
107 {
108     napi_status status;
109     napi_value result = nullptr;
110     napi_value constructor;
111 
112     status = napi_get_reference_value(env, g_volumeManagerConstructor, &constructor);
113     if (status == napi_ok) {
114         status = napi_new_instance(env, constructor, 0, nullptr, &result);
115         if (status == napi_ok) {
116             return result;
117         }
118     }
119     HiLog::Error(LABEL, "Failed in AudioVolumeManagerNapi::CreateVolumeManagerWrapper!");
120     napi_get_undefined(env, &result);
121 
122     return result;
123 }
124 
Init(napi_env env,napi_value exports)125 napi_value AudioVolumeManagerNapi::Init(napi_env env, napi_value exports)
126 {
127     AUDIO_INFO_LOG("AudioVolumeManagerNapi::Init");
128     napi_status status;
129     napi_value constructor;
130     napi_value result = nullptr;
131     const int32_t refCount = 1;
132     napi_get_undefined(env, &result);
133 
134     napi_property_descriptor audio_volume_manager_properties[] = {
135         DECLARE_NAPI_FUNCTION("getVolumeGroupInfos", GetVolumeGroupInfos),
136         DECLARE_NAPI_FUNCTION("getVolumeGroupManager", GetVolumeGroupManager),
137         DECLARE_NAPI_FUNCTION("on", On),
138 
139     };
140 
141     status = napi_define_class(env, AUDIO_VOLUME_MANAGER_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Construct, nullptr,
142         sizeof(audio_volume_manager_properties) / sizeof(audio_volume_manager_properties[PARAM0]),
143         audio_volume_manager_properties, &constructor);
144     if (status != napi_ok) {
145         return result;
146     }
147     status = napi_create_reference(env, constructor, refCount, &g_volumeManagerConstructor);
148     if (status == napi_ok) {
149         status = napi_set_named_property(env, exports, AUDIO_VOLUME_MANAGER_NAPI_CLASS_NAME.c_str(), constructor);
150         if (status == napi_ok) {
151             return exports;
152         }
153     }
154 
155     HiLog::Error(LABEL, "Failure in AudioVolumeManagerNapi::Init()");
156     return result;
157 }
158 
SetValueInt32(const napi_env & env,const std::string & fieldStr,const int intValue,napi_value & result)159 static void SetValueInt32(const napi_env& env, const std::string& fieldStr, const int intValue, napi_value& result)
160 {
161     napi_value value = nullptr;
162     napi_create_int32(env, intValue, &value);
163     napi_set_named_property(env, result, fieldStr.c_str(), value);
164 }
165 
SetValueString(const napi_env & env,const std::string & fieldStr,const std::string stringValue,napi_value & result)166 static void SetValueString(const napi_env& env, const std::string& fieldStr, const std::string stringValue,
167     napi_value& result)
168 {
169     napi_value value = nullptr;
170     napi_create_string_utf8(env, stringValue.c_str(), NAPI_AUTO_LENGTH, &value);
171     napi_set_named_property(env, result, fieldStr.c_str(), value);
172 }
173 
CommonCallbackRoutine(napi_env env,AudioVolumeManagerAsyncContext * & asyncContext,const napi_value & valueParam)174 static void CommonCallbackRoutine(napi_env env, AudioVolumeManagerAsyncContext *&asyncContext,
175     const napi_value &valueParam)
176 {
177     napi_value result[ARGS_TWO] = {0};
178     napi_value retVal;
179 
180     if (!asyncContext->status) {
181         napi_get_undefined(env, &result[PARAM0]);
182         result[PARAM1] = valueParam;
183     } else {
184         napi_value message = nullptr;
185         std::string messageValue = AudioCommonNapi::getMessageByCode(asyncContext->status);
186         napi_create_string_utf8(env, messageValue.c_str(), NAPI_AUTO_LENGTH, &message);
187 
188         napi_value code = nullptr;
189         napi_create_string_utf8(env, (std::to_string(asyncContext->status)).c_str(), NAPI_AUTO_LENGTH, &code);
190 
191         napi_create_error(env, code, message, &result[PARAM0]);
192         napi_get_undefined(env, &result[PARAM1]);
193     }
194 
195     if (asyncContext->deferred) {
196         if (!asyncContext->status) {
197             napi_resolve_deferred(env, asyncContext->deferred, result[PARAM1]);
198         } else {
199             napi_reject_deferred(env, asyncContext->deferred, result[PARAM0]);
200         }
201     } else {
202         napi_value callback = nullptr;
203         napi_get_reference_value(env, asyncContext->callbackRef, &callback);
204         napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal);
205         napi_delete_reference(env, asyncContext->callbackRef);
206     }
207     napi_delete_async_work(env, asyncContext->work);
208 
209     delete asyncContext;
210     asyncContext = nullptr;
211 }
212 
GetVolumeGroupInfosAsyncCallbackComplete(napi_env env,napi_status status,void * data)213 static void GetVolumeGroupInfosAsyncCallbackComplete(napi_env env, napi_status status, void *data)
214 {
215     auto asyncContext = static_cast<AudioVolumeManagerAsyncContext*>(data);
216 
217     napi_value result[ARGS_TWO] = { 0 };
218     napi_value valueParam = nullptr;
219     if (asyncContext != nullptr) {
220         if (asyncContext->status) {
221             napi_get_undefined(env, &valueParam);
222         } else {
223             size_t size = asyncContext->volumeGroupInfos.size();
224             HiLog::Info(LABEL, "number of devices = %{public}zu", size);
225             napi_create_array_with_length(env, size, &result[PARAM1]);
226             for (size_t i = 0; i < size; i++) {
227                 if (asyncContext->volumeGroupInfos[i] != nullptr) {
228                     (void)napi_create_object(env, &valueParam);
229                     SetValueString(env, "networkId", static_cast<std::string>(
230                         asyncContext->volumeGroupInfos[i]->networkId_), valueParam);
231                     SetValueInt32(env, "groupId", static_cast<int32_t>(
232                         asyncContext->volumeGroupInfos[i]->volumeGroupId_), valueParam);
233                     SetValueInt32(env, "mappingId", static_cast<int32_t>(
234                         asyncContext->volumeGroupInfos[i]->mappingId_), valueParam);
235                     SetValueString(env, "groupName", static_cast<std::string>(
236                         asyncContext->volumeGroupInfos[i]->groupName_), valueParam);
237                     SetValueInt32(env, "ConnectType", static_cast<int32_t>(
238                         asyncContext->volumeGroupInfos[i]->connectType_), valueParam);
239                     napi_set_element(env, result[PARAM1], i, valueParam);
240                 }
241             }
242         }
243         CommonCallbackRoutine(env, asyncContext, result[PARAM1]);
244     } else {
245         HiLog::Error(LABEL, "ERROR: AudioRoutingManagerAsyncContext* is Null!");
246     }
247 }
248 
GetVolumeGroupInfos(napi_env env,napi_callback_info info)249 napi_value AudioVolumeManagerNapi::GetVolumeGroupInfos(napi_env env, napi_callback_info info)
250 {
251     HiLog::Info(LABEL, " %{public}s IN", __func__);
252 
253     napi_status status;
254     const int32_t refCount = 1;
255     napi_value result = nullptr;
256 
257     GET_PARAMS(env, info, ARGS_TWO);
258 
259     unique_ptr<AudioVolumeManagerAsyncContext> asyncContext = make_unique<AudioVolumeManagerAsyncContext>();
260     if (argc < ARGS_ONE) {
261         asyncContext->status = NAPI_ERR_INVALID_PARAM;
262     }
263     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
264     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
265         for (size_t i = PARAM0; i < argc; i++) {
266             napi_valuetype valueType = napi_undefined;
267             napi_typeof(env, argv[i], &valueType);
268             if (i == PARAM0 && valueType == napi_string) {
269                 asyncContext->networkId = AudioCommonNapi::GetStringArgument(env, argv[i]);
270             } else if (i == PARAM1) {
271                 if (valueType == napi_function) {
272                     napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
273                 }
274                 break;
275             } else {
276                 asyncContext->status = NAPI_ERR_INVALID_PARAM;
277             }
278         }
279 
280         if (asyncContext->callbackRef == nullptr) {
281             napi_create_promise(env, &asyncContext->deferred, &result);
282         } else {
283             napi_get_undefined(env, &result);
284         }
285 
286         napi_value resource = nullptr;
287         napi_create_string_utf8(env, "GetVolumeGroupInfos", NAPI_AUTO_LENGTH, &resource);
288 
289         status = napi_create_async_work(
290             env, nullptr, resource,
291             [](napi_env env, void* data) {
292                 auto context = static_cast<AudioVolumeManagerAsyncContext*>(data);
293                 if (!context->status) {
294                     context->volumeGroupInfos = context->objectInfo->audioSystemMngr_->
295                         GetVolumeGroups(context->networkId);
296                     context->status = 0;
297                 }
298             },
299             GetVolumeGroupInfosAsyncCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
300         if (status != napi_ok) {
301             AudioCommonNapi::throwError(env, NAPI_ERR_SYSTEM);
302             result = nullptr;
303         } else {
304             status = napi_queue_async_work(env, asyncContext->work);
305             if (status == napi_ok) {
306                 asyncContext.release();
307             } else {
308                 result = nullptr;
309             }
310         }
311     }
312 
313     return result;
314 }
315 
GetGroupMgrAsyncCallbackComplete(napi_env env,napi_status status,void * data)316 static void GetGroupMgrAsyncCallbackComplete(napi_env env, napi_status status, void* data)
317 {
318     napi_value valueParam = nullptr;
319     auto asyncContext = static_cast<AudioVolumeManagerAsyncContext *>(data);
320 
321     if (asyncContext != nullptr) {
322         if (!asyncContext->status) {
323             valueParam = AudioVolumeGroupManagerNapi::CreateAudioVolumeGroupManagerWrapper(env, asyncContext->groupId);
324             asyncContext->status = AudioVolumeGroupManagerNapi::isConstructSuccess_;
325             AudioVolumeGroupManagerNapi::isConstructSuccess_ = SUCCESS;
326         }
327         CommonCallbackRoutine(env, asyncContext, valueParam);
328     } else {
329         HiLog::Error(LABEL, "ERROR: GetStreamMgrAsyncCallbackComplete asyncContext is Null!");
330     }
331 }
332 
GetVolumeGroupManager(napi_env env,napi_callback_info info)333 napi_value AudioVolumeManagerNapi::GetVolumeGroupManager(napi_env env, napi_callback_info info)
334 {
335     HiLog::Info(LABEL, " %{public}s IN", __func__);
336     napi_status status;
337     const int32_t refCount = 1;
338     napi_value result = nullptr;
339 
340     GET_PARAMS(env, info, ARGS_TWO);
341 
342     unique_ptr<AudioVolumeManagerAsyncContext> asyncContext = make_unique<AudioVolumeManagerAsyncContext>();
343     CHECK_AND_RETURN_RET_LOG(asyncContext != nullptr, nullptr, "AudioVolumeManagerAsyncContext object creation failed");
344     if (argc < ARGS_ONE) {
345         asyncContext->status = NAPI_ERR_INVALID_PARAM;
346     }
347     for (size_t i = PARAM0; i < argc; i++) {
348         napi_valuetype valueType = napi_undefined;
349         napi_typeof(env, argv[i], &valueType);
350         if (i == PARAM0 && valueType == napi_number) {
351             napi_get_value_int32(env, argv[i], &asyncContext->groupId);
352         } else if (i == PARAM1) {
353             if (valueType == napi_function) {
354                 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
355             }
356             break;
357         } else {
358             asyncContext->status = NAPI_ERR_INVALID_PARAM;
359         }
360     }
361 
362     if (asyncContext->callbackRef == nullptr) {
363         napi_create_promise(env, &asyncContext->deferred, &result);
364     } else {
365         napi_get_undefined(env, &result);
366     }
367 
368     napi_value resource = nullptr;
369     napi_create_string_utf8(env, "GetVolumeGroupManager", NAPI_AUTO_LENGTH, &resource);
370 
371     status = napi_create_async_work(
372         env, nullptr, resource,
373         [](napi_env env, void *data) {
374             auto context = static_cast<AudioVolumeManagerAsyncContext *>(data);
375             if (!context->status) {
376                 context->status = SUCCESS;
377             }
378         },
379         GetGroupMgrAsyncCallbackComplete, static_cast<void *>(asyncContext.get()), &asyncContext->work);
380     if (status != napi_ok) {
381         result = nullptr;
382     } else {
383         status = napi_queue_async_work(env, asyncContext->work);
384         if (status == napi_ok) {
385             asyncContext.release();
386         } else {
387             result = nullptr;
388         }
389     }
390 
391     return result;
392 }
393 
On(napi_env env,napi_callback_info info)394 napi_value AudioVolumeManagerNapi::On(napi_env env, napi_callback_info info)
395 {
396     napi_value undefinedResult = nullptr;
397     napi_get_undefined(env, &undefinedResult);
398 
399     const size_t minArgCount = 2;
400     size_t argCount = 3;
401     napi_value args[minArgCount + 1] = {nullptr, nullptr, nullptr};
402     napi_value jsThis = nullptr;
403     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
404     if (status != napi_ok || argCount < minArgCount) {
405         AUDIO_ERR_LOG("On fail to napi_get_cb_info/Requires min 2 parameters");
406         AudioCommonNapi::throwError(env, NAPI_ERR_INPUT_INVALID);
407     }
408 
409     napi_valuetype eventType = napi_undefined;
410     if (napi_typeof(env, args[PARAM0], &eventType) != napi_ok || eventType != napi_string) {
411         AudioCommonNapi::throwError(env, NAPI_ERR_INPUT_INVALID);
412         return undefinedResult;
413     }
414     std::string callbackName = AudioCommonNapi::GetStringArgument(env, args[0]);
415     AUDIO_INFO_LOG("AudioVolumeManagerNapi::On callbackName: %{public}s", callbackName.c_str());
416 
417     AudioVolumeManagerNapi *volumeManagerNapi = nullptr;
418     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&volumeManagerNapi));
419     NAPI_ASSERT(env, status == napi_ok && volumeManagerNapi != nullptr,
420         "Failed to retrieve audio manager napi instance.");
421     NAPI_ASSERT(env, volumeManagerNapi->audioSystemMngr_ != nullptr,
422         "audio system manager instance is null.");
423 
424     napi_valuetype handler = napi_undefined;
425     if (napi_typeof(env, args[PARAM1], &handler) != napi_ok || handler != napi_function) {
426         AUDIO_ERR_LOG("AudioVolumeManagerNapi::On type mismatch for parameter 2");
427         AudioCommonNapi::throwError(env, NAPI_ERR_INPUT_INVALID);
428         return undefinedResult;
429     }
430 
431     if (!callbackName.compare(VOLUME_CHANGE_CALLBACK_NAME)) {
432         if (volumeManagerNapi->volumeKeyEventCallbackNapi_ == nullptr) {
433             volumeManagerNapi->volumeKeyEventCallbackNapi_ = std::make_shared<AudioVolumeKeyEventNapi>(env);
434             int32_t ret = volumeManagerNapi->audioSystemMngr_->RegisterVolumeKeyEventCallback(
435                 volumeManagerNapi->cachedClientId_, volumeManagerNapi->volumeKeyEventCallbackNapi_);
436             if (ret) {
437                 AUDIO_ERR_LOG("AudioVolumeManagerNapi:: RegisterVolumeKeyEventCallback Failed");
438             } else {
439                 AUDIO_DEBUG_LOG("AudioVolumeManagerNapi:: RegisterVolumeKeyEventCallback Success");
440             }
441         }
442         std::shared_ptr<AudioVolumeKeyEventNapi> cb =
443             std::static_pointer_cast<AudioVolumeKeyEventNapi>(volumeManagerNapi->volumeKeyEventCallbackNapi_);
444         cb->SaveCallbackReference(callbackName, args[PARAM1]);
445     } else {
446         AUDIO_ERR_LOG("AudioVolumeManagerNapi::No such callback supported");
447         AudioCommonNapi::throwError(env, NAPI_ERR_INVALID_PARAM);
448     }
449     return undefinedResult;
450 }
451 } // namespace AudioStandard
452 } // namespace OHOS
453