1 /*
2 * Copyright (c) 2025 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 "RecorderNative.h"
17 #include <bits/alltypes.h>
18
19 #undef LOG_DOMAIN
20 #undef LOG_TAG
21 #define LOG_DOMAIN 0xFF00
22 #define LOG_TAG "recorder"
23
24 namespace {
25 constexpr int RGBA = 3;
26 }
27
28 struct AsyncCallbackInfo {
29 napi_env env;
30 napi_async_work asyncWork;
31 napi_deferred deferred;
32 int32_t resultCode = 0;
33 std::string surfaceId = "";
34 SampleInfo sampleInfo;
35 };
36
DealCallBack(napi_env env,void * data)37 void DealCallBack(napi_env env, void *data)
38 {
39 AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
40 napi_value code;
41 napi_create_int32(env, asyncCallbackInfo->resultCode, &code);
42 napi_value surfaceId;
43 napi_create_string_utf8(env, asyncCallbackInfo->surfaceId.data(), NAPI_AUTO_LENGTH, &surfaceId);
44 napi_value obj;
45 napi_create_object(env, &obj);
46
47 napi_set_named_property(env, obj, "code", code);
48 napi_set_named_property(env, obj, "surfaceId", surfaceId);
49 napi_resolve_deferred(asyncCallbackInfo->env, asyncCallbackInfo->deferred, obj);
50 napi_delete_async_work(env, asyncCallbackInfo->asyncWork);
51 delete asyncCallbackInfo;
52 }
53
SetCallBackResult(AsyncCallbackInfo * asyncCallbackInfo,int32_t code)54 void SetCallBackResult(AsyncCallbackInfo *asyncCallbackInfo, int32_t code)
55 {
56 asyncCallbackInfo->resultCode = code;
57 }
58
SurfaceIdCallBack(AsyncCallbackInfo * asyncCallbackInfo,std::string surfaceId)59 void SurfaceIdCallBack(AsyncCallbackInfo *asyncCallbackInfo, std::string surfaceId)
60 {
61 asyncCallbackInfo->surfaceId = surfaceId;
62 }
63
NativeInit(void * data)64 void NativeInit(void *data)
65 {
66 AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
67 int32_t ret = Recorder::GetInstance().Init(asyncCallbackInfo->sampleInfo);
68 if (ret != AVCODEC_SAMPLE_ERR_OK) {
69 SetCallBackResult(asyncCallbackInfo, -1);
70 }
71
72 uint64_t id = 0;
73 ret = OH_NativeWindow_GetSurfaceId(asyncCallbackInfo->sampleInfo.window, &id);
74 if (ret != AVCODEC_SAMPLE_ERR_OK) {
75 SetCallBackResult(asyncCallbackInfo, -1);
76 }
77 asyncCallbackInfo->surfaceId = std::to_string(id);
78 SurfaceIdCallBack(asyncCallbackInfo, asyncCallbackInfo->surfaceId);
79 }
80
ParseSampleInfo(napi_env env,napi_value args[])81 static SampleInfo ParseSampleInfo(napi_env env, napi_value args[])
82 {
83 SampleInfo sampleInfo;
84 int index = 0;
85 napi_get_value_int32(env, args[index++], &sampleInfo.outputFd);
86 char videoCodecMime[20] = {0};
87 size_t videoCodecMimeStrlen;
88 size_t len = 20;
89 napi_get_value_string_utf8(env, args[index++], videoCodecMime, len, &videoCodecMimeStrlen);
90 napi_get_value_int32(env, args[index++], &sampleInfo.videoWidth);
91 napi_get_value_int32(env, args[index++], &sampleInfo.videoHeight);
92 napi_get_value_double(env, args[index++], &sampleInfo.frameRate);
93 napi_get_value_int32(env, args[index++], &sampleInfo.isHDRVivid);
94 napi_get_value_int64(env, args[index++], &sampleInfo.bitrate);
95
96 int32_t format;
97 if (napi_ok == napi_get_value_int32(env, args[index], &format)) {
98 sampleInfo.pixelFormat = (format == RGBA) ? AV_PIXEL_FORMAT_RGBA : AV_PIXEL_FORMAT_NV12;
99 }
100
101 sampleInfo.videoCodecMime = videoCodecMime;
102 if (sampleInfo.isHDRVivid) {
103 sampleInfo.hevcProfile = HEVC_PROFILE_MAIN_10;
104 }
105 return sampleInfo;
106 }
107
CreateAsyncInfo(napi_env env,napi_deferred deferred,SampleInfo sampleInfo)108 static AsyncCallbackInfo* CreateAsyncInfo(napi_env env, napi_deferred deferred, SampleInfo sampleInfo)
109 {
110 AsyncCallbackInfo* asyncInfo = new AsyncCallbackInfo();
111 asyncInfo->env = env;
112 asyncInfo->deferred = deferred;
113 asyncInfo->sampleInfo = sampleInfo;
114 asyncInfo->resultCode = -1;
115 return asyncInfo;
116 }
117
StartAsyncWork(napi_env env,AsyncCallbackInfo * asyncInfo)118 static void StartAsyncWork(napi_env env, AsyncCallbackInfo* asyncInfo)
119 {
120 napi_value resourceName;
121 napi_create_string_latin1(env, "recorder", NAPI_AUTO_LENGTH, &resourceName);
122 napi_create_async_work(env, nullptr, resourceName,
123 [](napi_env env, void* data) { NativeInit(data); },
124 [](napi_env env, napi_status status, void* data) { DealCallBack(env, data); },
125 asyncInfo, &asyncInfo->asyncWork);
126 napi_queue_async_work(env, asyncInfo->asyncWork);
127 }
128
Init(napi_env env,napi_callback_info info)129 napi_value RecorderNative::Init(napi_env env, napi_callback_info info)
130 {
131 size_t argc = 8;
132 napi_value args[8] = {nullptr};
133 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
134
135 SampleInfo sampleInfo = ParseSampleInfo(env, args);
136
137 //音频
138 sampleInfo.audioCodecMime = OH_AVCODEC_MIMETYPE_AUDIO_AAC;
139 sampleInfo.audioSampleForamt = OH_BitsPerSample::SAMPLE_S16LE;
140 sampleInfo.audioSampleRate = 48000; // sample rate 48000
141 sampleInfo.audioChannelCount = 2; // channel count 2
142 sampleInfo.audioBitRate = 32000; // bit rate 32000
143 sampleInfo.audioChannelLayout = OH_AudioChannelLayout::CH_LAYOUT_STEREO;
144 sampleInfo.audioMaxInputSize = sampleInfo.audioSampleRate * sampleInfo.audioChannelCount *
145 sizeof(short) * 0.02; // 0.02 is 20ms
146
147 napi_value promise;
148 napi_deferred deferred;
149 napi_create_promise(env, &deferred, &promise);
150
151 AsyncCallbackInfo* asyncInfo = CreateAsyncInfo(env, deferred, sampleInfo);
152 StartAsyncWork(env, asyncInfo);
153 return promise;
154 }
155
Start(napi_env env,napi_callback_info info)156 napi_value RecorderNative::Start(napi_env env, napi_callback_info info)
157 {
158 Recorder::GetInstance().Start();
159 return nullptr;
160 }
161
NativeStop(napi_env env,void * data)162 void NativeStop(napi_env env, void *data)
163 {
164 AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
165 int32_t ret = Recorder::GetInstance().Stop();
166 if (ret != AVCODEC_SAMPLE_ERR_OK) {
167 SetCallBackResult(asyncCallbackInfo, -1);
168 }
169 SetCallBackResult(asyncCallbackInfo, 0);
170 }
171
Stop(napi_env env,napi_callback_info info)172 napi_value RecorderNative::Stop(napi_env env, napi_callback_info info)
173 {
174 napi_value promise;
175 napi_deferred deferred;
176 napi_create_promise(env, &deferred, &promise);
177
178 AsyncCallbackInfo *asyncCallbackInfo = new AsyncCallbackInfo();
179
180 asyncCallbackInfo->env = env;
181 asyncCallbackInfo->asyncWork = nullptr;
182 asyncCallbackInfo->deferred = deferred;
183
184 napi_value resourceName;
185 napi_create_string_latin1(env, "recorder", NAPI_AUTO_LENGTH, &resourceName);
186 napi_create_async_work(
187 env, nullptr, resourceName, [](napi_env env, void *data) { NativeStop(env, data); },
188 [](napi_env env, napi_status status, void *data) { DealCallBack(env, data); }, (void *)asyncCallbackInfo,
189 &asyncCallbackInfo->asyncWork);
190 napi_queue_async_work(env, asyncCallbackInfo->asyncWork);
191 return promise;
192 }
193
194 EXTERN_C_START
Init(napi_env env,napi_value exports)195 static napi_value Init(napi_env env, napi_value exports)
196 {
197 napi_property_descriptor classProp[] = {
198 {"initNative", nullptr, RecorderNative::Init, nullptr, nullptr, nullptr, napi_default, nullptr},
199 {"startNative", nullptr, RecorderNative::Start, nullptr, nullptr, nullptr, napi_default, nullptr},
200 {"stopNative", nullptr, RecorderNative::Stop, nullptr, nullptr, nullptr, napi_default, nullptr},
201 };
202
203 napi_value RecorderNative = nullptr;
204 const char *classBindName = "recorderNative";
205 napi_define_class(env, classBindName, strlen(classBindName), nullptr, nullptr, 1, classProp, &RecorderNative);
206 napi_define_properties(env, exports, sizeof(classProp) / sizeof(classProp[0]), classProp);
207 return exports;
208 }
209 EXTERN_C_END
210
211 static napi_module RecorderModule = {
212 .nm_version = 1,
213 .nm_flags = 0,
214 .nm_filename = nullptr,
215 .nm_register_func = Init,
216 .nm_modname = "recorder",
217 .nm_priv = ((void *)0),
218 .reserved = {0},
219 };
220
221
RegisterRecorderModule(void)222 extern "C" __attribute__((constructor)) void RegisterRecorderModule(void) { napi_module_register(&RecorderModule); }
223