• 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_capturer_state_callback_napi.h"
17 
18 #include <uv.h>
19 
20 #include "audio_errors.h"
21 #include "audio_log.h"
22 
23 using namespace std;
24 
25 namespace OHOS {
26 namespace AudioStandard {
AudioCapturerStateCallbackNapi(napi_env env)27 AudioCapturerStateCallbackNapi::AudioCapturerStateCallbackNapi(napi_env env)
28     : env_(env)
29 {
30     AUDIO_DEBUG_LOG("AudioCapturerStateCallbackNapi: instance create");
31 }
32 
~AudioCapturerStateCallbackNapi()33 AudioCapturerStateCallbackNapi::~AudioCapturerStateCallbackNapi()
34 {
35     AUDIO_DEBUG_LOG("AudioCapturerStateCallbackNapi: instance destroy");
36 }
37 
SaveCallbackReference(napi_value args)38 void AudioCapturerStateCallbackNapi::SaveCallbackReference(napi_value args)
39 {
40     std::lock_guard<std::mutex> lock(mutex_);
41     napi_ref callback = nullptr;
42     const int32_t refCount = 1;
43     napi_status status = napi_create_reference(env_, args, refCount, &callback);
44     CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
45                          "AudioCapturerStateCallbackNapi: creating reference for callback fail");
46 
47     std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
48     CHECK_AND_RETURN_LOG(cb != nullptr, "AudioCapturerStateCallbackNapi: creating callback failed");
49 
50     capturerStateCallback_ = cb;
51 }
52 
OnCapturerStateChange(const std::vector<std::unique_ptr<AudioCapturerChangeInfo>> & audioCapturerChangeInfos)53 void AudioCapturerStateCallbackNapi::OnCapturerStateChange(
54     const std::vector<std::unique_ptr<AudioCapturerChangeInfo>> &audioCapturerChangeInfos)
55 {
56     AUDIO_INFO_LOG("OnCapturerStateChange is called");
57 
58     std::lock_guard<std::mutex> lock(mutex_);
59     std::unique_ptr<AudioCapturerStateJsCallback> cb = std::make_unique<AudioCapturerStateJsCallback>();
60     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
61 
62     std::vector<std::unique_ptr<AudioCapturerChangeInfo>> capturerChangeInfos;
63     for (const auto &changeInfo : audioCapturerChangeInfos) {
64         capturerChangeInfos.push_back(std::make_unique<AudioCapturerChangeInfo>(*changeInfo));
65     }
66 
67     cb->callback = capturerStateCallback_;
68     cb->changeInfos = move(capturerChangeInfos);
69 
70     return OnJsCallbackCapturerState(cb);
71 }
72 
SetValueInt32(const napi_env & env,const std::string & fieldStr,const int intValue,napi_value & obj)73 static void SetValueInt32(const napi_env& env, const std::string& fieldStr, const int intValue, napi_value& obj)
74 {
75     napi_value value = nullptr;
76     napi_create_int32(env, intValue, &value);
77     napi_set_named_property(env, obj, fieldStr.c_str(), value);
78 }
79 
SetValueString(const napi_env & env,const std::string & fieldStr,const std::string stringValue,napi_value & result)80 static void SetValueString(const napi_env &env, const std::string &fieldStr, const std::string stringValue,
81     napi_value &result)
82 {
83     napi_value value = nullptr;
84     napi_create_string_utf8(env, stringValue.c_str(), NAPI_AUTO_LENGTH, &value);
85     napi_set_named_property(env, result, fieldStr.c_str(), value);
86 }
87 
SetDeviceDescriptors(const napi_env & env,napi_value & jsChangeInfoObj,const DeviceInfo & deviceInfo)88 static void SetDeviceDescriptors(const napi_env& env, napi_value &jsChangeInfoObj, const DeviceInfo &deviceInfo)
89 {
90     napi_value jsDeviceDescriptorsObj = nullptr;
91     napi_value valueParam = nullptr;
92     napi_create_array_with_length(env, 1, &jsDeviceDescriptorsObj);
93 
94     (void)napi_create_object(env, &valueParam);
95     SetValueInt32(env, "deviceRole", static_cast<int32_t>(deviceInfo.deviceRole), valueParam);
96     SetValueInt32(env, "deviceType", static_cast<int32_t>(deviceInfo.deviceType), valueParam);
97     SetValueInt32(env, "id", static_cast<int32_t>(deviceInfo.deviceId), valueParam);
98     SetValueString(env, "name", deviceInfo.deviceName, valueParam);
99     SetValueString(env, "address", deviceInfo.macAddress, valueParam);
100     SetValueString(env, "displayName", deviceInfo.displayName, valueParam);
101     SetValueString(env, "networkId", deviceInfo.networkId, valueParam);
102     SetValueInt32(env, "interruptGroupId", static_cast<int32_t>(deviceInfo.interruptGroupId), valueParam);
103     SetValueInt32(env, "volumeGroupId", static_cast<int32_t>(deviceInfo.volumeGroupId), valueParam);
104 
105     napi_value value = nullptr;
106     napi_value sampleRates;
107     napi_create_array_with_length(env, 1, &sampleRates);
108     napi_create_int32(env, deviceInfo.audioStreamInfo.samplingRate, &value);
109     napi_set_element(env, sampleRates, 0, value);
110     napi_set_named_property(env, valueParam, "sampleRates", sampleRates);
111 
112     napi_value channelCounts;
113     napi_create_array_with_length(env, 1, &channelCounts);
114     napi_create_int32(env, deviceInfo.audioStreamInfo.channels, &value);
115     napi_set_element(env, channelCounts, 0, value);
116     napi_set_named_property(env, valueParam, "channelCounts", channelCounts);
117 
118     napi_value channelMasks;
119     napi_create_array_with_length(env, 1, &channelMasks);
120     napi_create_int32(env, deviceInfo.channelMasks, &value);
121     napi_set_element(env, channelMasks, 0, value);
122     napi_set_named_property(env, valueParam, "channelMasks", channelMasks);
123 
124     napi_set_element(env, jsDeviceDescriptorsObj, 0, valueParam);
125     napi_set_named_property(env, jsChangeInfoObj, "deviceDescriptors", jsDeviceDescriptorsObj);
126 }
127 
NativeCapturerChangeInfoToJsObj(const napi_env & env,napi_value & jsArrayChangeInfoObj,const vector<unique_ptr<AudioCapturerChangeInfo>> & changeInfos)128 static void NativeCapturerChangeInfoToJsObj(const napi_env &env, napi_value &jsArrayChangeInfoObj,
129     const vector<unique_ptr<AudioCapturerChangeInfo>> &changeInfos)
130 {
131     napi_value jsChangeInfoObj = nullptr;
132     napi_value jsCapInfoObj = nullptr;
133 
134     size_t size = changeInfos.size();
135     int32_t position = 0;
136 
137     napi_create_array_with_length(env, size, &jsArrayChangeInfoObj);
138     for (const unique_ptr<AudioCapturerChangeInfo> &changeInfo : changeInfos) {
139         AUDIO_DEBUG_LOG("AudioCapturerStateCallbackNapi: ChangeInfo to jsobj called");
140         napi_create_object(env, &jsChangeInfoObj);
141         SetValueInt32(env, "streamId", static_cast<int32_t>(changeInfo->sessionId), jsChangeInfoObj);
142         SetValueInt32(env, "capturerState", static_cast<int32_t>(changeInfo->capturerState), jsChangeInfoObj);
143         SetValueInt32(env, "clientUid", static_cast<int32_t>(changeInfo->clientUID), jsChangeInfoObj);
144 
145         napi_create_object(env, &jsCapInfoObj);
146         SetValueInt32(env, "source", static_cast<int32_t>(changeInfo->capturerInfo.sourceType), jsCapInfoObj);
147         SetValueInt32(env, "capturerFlags", changeInfo->capturerInfo.capturerFlags, jsCapInfoObj);
148         napi_set_named_property(env, jsChangeInfoObj, "capturerInfo", jsCapInfoObj);
149         SetDeviceDescriptors(env, jsChangeInfoObj, changeInfo->inputDeviceInfo);
150 
151         napi_set_element(env, jsArrayChangeInfoObj, position, jsChangeInfoObj);
152         position++;
153     }
154 }
155 
OnJsCallbackCapturerState(std::unique_ptr<AudioCapturerStateJsCallback> & jsCb)156 void AudioCapturerStateCallbackNapi::OnJsCallbackCapturerState(std::unique_ptr<AudioCapturerStateJsCallback> &jsCb)
157 {
158     uv_loop_s *loop = nullptr;
159     napi_get_uv_event_loop(env_, &loop);
160     if (loop == nullptr) {
161         return;
162     }
163 
164     uv_work_t *work = new(std::nothrow) uv_work_t;
165     if (work == nullptr) {
166         AUDIO_ERR_LOG("AudioCapturerStateCallbackNapi: OnJsCallbackCapturerState: No memory");
167         return;
168     }
169 
170     work->data = reinterpret_cast<void *>(jsCb.get());
171 
172     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
173         // Js Thread
174         AudioCapturerStateJsCallback *event = reinterpret_cast<AudioCapturerStateJsCallback *>(work->data);
175         if (event == nullptr || event->callback == nullptr) {
176             AUDIO_ERR_LOG("AudioCapturerStateCallbackNapi: OnJsCallbackCapturerState: data or callback is null.");
177             delete event;
178             delete work;
179             return;
180         }
181         napi_env env = event->callback->env_;
182         napi_ref callback = event->callback->cb_;
183 
184         do {
185             napi_value jsCallback = nullptr;
186             napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
187             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr,
188                 "callback get reference value fail");
189             // Call back function
190             napi_value args[1] = { nullptr };
191             NativeCapturerChangeInfoToJsObj(env, args[0], event->changeInfos);
192 
193             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr,
194                 " fail to convert to jsobj");
195 
196             const size_t argCount = 1;
197             napi_value result = nullptr;
198             nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
199             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "Fail to call renderstate callback");
200         } while (0);
201         delete event;
202         delete work;
203     });
204     if (ret != 0) {
205         AUDIO_ERR_LOG("Failed to execute libuv work queue");
206         delete work;
207     } else {
208         jsCb.release();
209     }
210 }
211 }  // namespace AudioStandard
212 }  // namespace OHOS
213