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