/* * Copyright (C) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "common_napi.h" #include #include "avcodec_list.h" #include "media_log.h" #include "media_errors.h" namespace { constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_PLAYER, "CommonNapi"}; } namespace OHOS { namespace Media { std::string CommonNapi::GetStringArgument(napi_env env, napi_value value, size_t maxLength) { std::string strValue = ""; size_t bufLength = 0; napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &bufLength); if (status == napi_ok && bufLength > 0 && bufLength < maxLength) { char *buffer = static_cast(malloc((bufLength + 1) * sizeof(char))); CHECK_AND_RETURN_RET_LOG(buffer != nullptr, strValue, "no memory"); status = napi_get_value_string_utf8(env, value, buffer, bufLength + 1, &bufLength); if (status == napi_ok) { MEDIA_LOGD("argument = %{public}s", buffer); strValue = buffer; } free(buffer); buffer = nullptr; } return strValue; } bool CommonNapi::GetIntArrayArgument(napi_env env, napi_value value, std::vector &vec, size_t maxLength) { napi_valuetype type; napi_status status = napi_typeof(env, value, &type); if (status != napi_ok || type != napi_object) { return false; } uint32_t arrayLength = 0; status = napi_get_array_length(env, value, &arrayLength); if (status != napi_ok || arrayLength == 0 || arrayLength > maxLength) { return false; } for (size_t i = 0; i < arrayLength; ++i) { napi_value element; status = napi_get_element(env, value, i, &element); if (status != napi_ok) { return false; } int32_t elementValue = 0; status = napi_get_value_int32(env, element, &elementValue); if (status != napi_ok) { return false; } vec.push_back(elementValue); } return true; } bool CommonNapi::CheckValueType(napi_env env, napi_value arg, napi_valuetype type) { napi_valuetype valueType = napi_undefined; if (arg != nullptr && napi_typeof(env, arg, &valueType) == napi_ok && valueType == type) { return true; } return false; } bool CommonNapi::CheckhasNamedProperty(napi_env env, napi_value arg, std::string type) { bool exist = false; napi_status napiStatus = napi_has_named_property(env, arg, type.c_str(), &exist); return exist && (napiStatus == napi_ok); } bool CommonNapi::GetPropertyInt32(napi_env env, napi_value configObj, const std::string &type, int32_t &result) { napi_value item = nullptr; bool exist = false; napi_status napiStatus = napi_has_named_property(env, configObj, type.c_str(), &exist); CHECK_AND_RETURN_RET_LOG(napiStatus == napi_ok && exist, false, "can not find %{public}s property", type.c_str()); CHECK_AND_RETURN_RET_LOG(napi_get_named_property(env, configObj, type.c_str(), &item) == napi_ok, false, "get %{public}s property fail", type.c_str()); CHECK_AND_RETURN_RET_LOG(napi_get_value_int32(env, item, &result) == napi_ok, false, "get %{public}s property value fail", type.c_str()); return true; } bool CommonNapi::GetPropertyUint32(napi_env env, napi_value configObj, const std::string &type, uint32_t &result) { napi_value item = nullptr; bool exist = false; napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist); CHECK_AND_RETURN_RET_LOG(status == napi_ok && exist, false, "can not find %{public}s property", type.c_str()); CHECK_AND_RETURN_RET_LOG(napi_get_named_property(env, configObj, type.c_str(), &item) == napi_ok, false, "get %{public}s property fail", type.c_str()); CHECK_AND_RETURN_RET_LOG(napi_get_value_uint32(env, item, &result) == napi_ok, false, "get %{public}s property value fail", type.c_str()); return true; } bool CommonNapi::GetPropertyInt64(napi_env env, napi_value configObj, const std::string &type, int64_t &result) { napi_value item = nullptr; bool exist = false; napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist); if (status != napi_ok || !exist) { MEDIA_LOGE("can not find %{public}s property", type.c_str()); return false; } if (napi_get_named_property(env, configObj, type.c_str(), &item) != napi_ok) { MEDIA_LOGE("get %{public}s property fail", type.c_str()); return false; } if (napi_get_value_int64(env, item, &result) != napi_ok) { MEDIA_LOGE("get %{public}s property value fail", type.c_str()); return false; } return true; } bool CommonNapi::GetPropertyDouble(napi_env env, napi_value configObj, const std::string &type, double &result) { napi_value item = nullptr; bool exist = false; napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist); if (status != napi_ok || !exist) { MEDIA_LOGE("can not find %{public}s property", type.c_str()); return false; } if (napi_get_named_property(env, configObj, type.c_str(), &item) != napi_ok) { MEDIA_LOGE("get %{public}s property fail", type.c_str()); return false; } if (napi_get_value_double(env, item, &result) != napi_ok) { MEDIA_LOGE("get %{public}s property value fail", type.c_str()); return false; } return true; } std::string CommonNapi::GetPropertyString(napi_env env, napi_value configObj, const std::string &type) { std::string invalid = ""; bool exist = false; napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist); if (status != napi_ok || !exist) { MEDIA_LOGE("can not find %{public}s property", type.c_str()); return invalid; } napi_value item = nullptr; if (napi_get_named_property(env, configObj, type.c_str(), &item) != napi_ok) { MEDIA_LOGE("get %{public}s property fail", type.c_str()); return invalid; } return GetStringArgument(env, item); } bool CommonNapi::GetPropertyArrayBuffer(napi_env env, napi_value configObj, void **data, size_t* length) { if (napi_get_arraybuffer_info(env, configObj, data, length) != napi_ok) { MEDIA_LOGE("get arraybuffer value fail"); return false; } return true; } napi_status CommonNapi::GetPropertyRecord(napi_env env, napi_value configObj, Meta &meta, std::string type) { bool exist = false; napi_value in = nullptr; napi_valuetype valueType = napi_undefined; napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist); if (status != napi_ok || !exist) { MEDIA_LOGE("can not find %{public}s property", type.c_str()); return napi_invalid_arg; } if (napi_get_named_property(env, configObj, type.c_str(), &in) != napi_ok) { MEDIA_LOGE("get %{public}s property fail", type.c_str()); return napi_invalid_arg; } status = napi_typeof(env, in, &valueType); CHECK_AND_RETURN_RET_LOG(status == napi_ok, status, "get valueType failed"); CHECK_AND_RETURN_RET_LOG(valueType != napi_undefined, napi_ok, "PropertyRecord undefined"); CHECK_AND_RETURN_RET_LOG(valueType == napi_object, napi_invalid_arg, "invalid arguments"); napi_value dataList = nullptr; uint32_t count = 0; status = napi_get_property_names(env, in, &dataList); CHECK_AND_RETURN_RET_LOG(status == napi_ok, status, "get property names failed"); status = napi_get_array_length(env, dataList, &count); CHECK_AND_RETURN_RET_LOG(status == napi_ok && count <= MAX_COUNT, napi_invalid_arg, "get length failed or more than 500"); napi_value jsKey = nullptr; napi_value jsValue = nullptr; for (uint32_t i = 0; i < count; i++) { status = napi_get_element(env, dataList, i, &jsKey); CHECK_AND_RETURN_RET_LOG(status == napi_ok, status, "get element Key failed"); status = napi_typeof(env, jsKey, &valueType); CHECK_AND_RETURN_RET_LOG(status == napi_ok, status, "get valueType failed"); CHECK_AND_RETURN_RET_LOG(valueType == napi_string, napi_invalid_arg, "key not supported type"); std::string strKey = GetStringArgument(env, jsKey, CUSTOM_MAX_LENGTH); CHECK_AND_RETURN_RET_LOG(strKey != "", napi_invalid_arg, "key not supported"); status = napi_get_named_property(env, in, strKey.c_str(), &jsValue); CHECK_AND_RETURN_RET_LOG(status == napi_ok, status, "get property value failed"); status = napi_typeof(env, jsValue, &valueType); CHECK_AND_RETURN_RET_LOG(status == napi_ok, status, "get valueType failed"); CHECK_AND_RETURN_RET_LOG(valueType == napi_string, napi_invalid_arg, "value not supported type"); std::string strValue = GetStringArgument(env, jsValue, CUSTOM_MAX_LENGTH); CHECK_AND_RETURN_RET_LOG(!strValue.empty(), napi_invalid_arg, "get value failed"); meta.SetData(strKey, strValue); } return napi_ok; } bool CommonNapi::GetFdArgument(napi_env env, napi_value value, AVFileDescriptor &rawFd) { CHECK_AND_RETURN_RET(GetPropertyInt32(env, value, "fd", rawFd.fd) == true, false); if (!GetPropertyInt64(env, value, "offset", rawFd.offset)) { rawFd.offset = 0; // use default value } if (!GetPropertyInt64(env, value, "length", rawFd.length)) { rawFd.length = -1; // -1 means use default value } MEDIA_LOGD("get fd argument, fd = %{public}d, offset = %{public}" PRIi64 ", size = %{public}" PRIi64 "", rawFd.fd, rawFd.offset, rawFd.length); return true; } bool CommonNapi::GetPropertyMap(napi_env env, napi_value value, std::map& map) { napi_value jsProNameList = nullptr; uint32_t jsProCount = 0; napi_status status = napi_get_property_names(env, value, &jsProNameList); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "get property name failed"); status = napi_get_array_length(env, jsProNameList, &jsProCount); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "get subKeys length failed"); napi_value jsProName = nullptr; napi_value jsProValue = nullptr; for (uint32_t i = 0; i < jsProCount; i++) { status = napi_get_element(env, jsProNameList, i, &jsProName); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "get sub key failed"); std::string strProName = GetStringArgument(env, jsProName); status = napi_get_named_property(env, value, strProName.c_str(), &jsProValue); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "get sub value failed"); std::string strProValue = GetStringArgument(env, jsProValue); map.emplace(strProName, strProValue); } return true; } bool CommonNapi::GetPlayStrategy(napi_env env, napi_value value, AVPlayStrategyTmp &playStrategy) { if (!GetPropertyUint32(env, value, "preferredWidth", playStrategy.preferredWidth)) { playStrategy.preferredWidth = 0; // use default value } if (!GetPropertyUint32(env, value, "preferredHeight", playStrategy.preferredHeight)) { playStrategy.preferredHeight = 0; // use default value } if (!GetPropertyUint32(env, value, "preferredBufferDuration", playStrategy.preferredBufferDuration)) { playStrategy.preferredBufferDuration = 0; // use default value } if (!GetPropertyBool(env, value, "preferredHdr", playStrategy.preferredHdr)) { playStrategy.preferredHdr = 0; // use default value } if (!GetPropertyBool(env, value, "showFirstFrameOnPrepare", playStrategy.showFirstFrameOnPrepare)) { playStrategy.showFirstFrameOnPrepare = false; // use default value } if (!GetPropertyBool(env, value, "enableSuperResolution", playStrategy.enableSuperResolution)) { playStrategy.enableSuperResolution = false; // use default value } if (!GetPropertyBool(env, value, "enableCameraPostprocessing", playStrategy.enableCameraPostprocessing)) { playStrategy.enableCameraPostprocessing = false; // use default value } if (!GetPropertyInt32(env, value, "mutedMediaType", playStrategy.mutedMediaType)) { playStrategy.mutedMediaType = MediaType::MEDIA_TYPE_MAX_COUNT; // use default value } playStrategy.preferredAudioLanguage = GetPropertyString(env, value, "preferredAudioLanguage"); playStrategy.preferredSubtitleLanguage = GetPropertyString(env, value, "preferredSubtitleLanguage"); if (!GetPropertyDouble(env, value, "preferredBufferDurationForPlaying", playStrategy.preferredBufferDurationForPlaying)) { playStrategy.preferredBufferDurationForPlaying = 0; // use default value playStrategy.isSetBufferDurationForPlaying = false; } else { playStrategy.isSetBufferDurationForPlaying = true; } if (!GetPropertyDouble(env, value, "thresholdForAutoQuickPlay", playStrategy.thresholdForAutoQuickPlay)) { playStrategy.thresholdForAutoQuickPlay = -1; playStrategy.isSetThresholdForAutoQuickPlay = false; } else { playStrategy.isSetThresholdForAutoQuickPlay = true; } if (!GetPropertyBool(env, value, "keepDecodingOnMute", playStrategy.keepDecodingOnMute)) { playStrategy.keepDecodingOnMute = false; // use default value } return true; } bool CommonNapi::GetPlayMediaStreamData(napi_env env, napi_value value, AVPlayMediaStreamTmp &mediaStream) { bool existProperty = CommonNapi::CheckhasNamedProperty(env, value, "url"); existProperty &= CommonNapi::CheckhasNamedProperty(env, value, "width"); existProperty &= CommonNapi::CheckhasNamedProperty(env, value, "height"); existProperty &= CommonNapi::CheckhasNamedProperty(env, value, "bitrate"); CHECK_AND_RETURN_RET_LOG(existProperty, false, "property is not complete for AVPlayMediaStream"); mediaStream.url = GetPropertyString(env, value, "url"); GetPropertyUint32(env, value, "width", mediaStream.width); GetPropertyUint32(env, value, "height", mediaStream.height); GetPropertyUint32(env, value, "bitrate", mediaStream.bitrate); return true; } napi_status CommonNapi::FillErrorArgs(napi_env env, int32_t errCode, const napi_value &args) { napi_value codeStr = nullptr; napi_status status = napi_create_string_utf8(env, "code", NAPI_AUTO_LENGTH, &codeStr); CHECK_AND_RETURN_RET_LOG(status == napi_ok && codeStr != nullptr, napi_invalid_arg, "create code str fail"); napi_value errCodeVal = nullptr; int32_t errCodeInt = errCode; status = napi_create_int32(env, errCodeInt, &errCodeVal); CHECK_AND_RETURN_RET_LOG(status == napi_ok && errCodeVal != nullptr, napi_invalid_arg, "create error code number val fail"); status = napi_set_property(env, args, codeStr, errCodeVal); CHECK_AND_RETURN_RET_LOG(status == napi_ok, napi_invalid_arg, "set error code property fail"); napi_value nameStr = nullptr; status = napi_create_string_utf8(env, "name", NAPI_AUTO_LENGTH, &nameStr); CHECK_AND_RETURN_RET_LOG(status == napi_ok && nameStr != nullptr, napi_invalid_arg, "create name str fail"); napi_value errNameVal = nullptr; status = napi_create_string_utf8(env, "BusinessError", NAPI_AUTO_LENGTH, &errNameVal); CHECK_AND_RETURN_RET_LOG(status == napi_ok && errNameVal != nullptr, napi_invalid_arg, "create BusinessError str fail"); status = napi_set_property(env, args, nameStr, errNameVal); CHECK_AND_RETURN_RET_LOG(status == napi_ok, napi_invalid_arg, "set error name property fail"); return napi_ok; } napi_status CommonNapi::CreateError(napi_env env, int32_t errCode, const std::string &errMsg, napi_value &errVal) { napi_get_undefined(env, &errVal); napi_value msgValStr = nullptr; napi_status nstatus = napi_create_string_utf8(env, errMsg.c_str(), NAPI_AUTO_LENGTH, &msgValStr); if (nstatus != napi_ok || msgValStr == nullptr) { MEDIA_LOGE("create error message str fail"); return napi_invalid_arg; } nstatus = napi_create_error(env, nullptr, msgValStr, &errVal); if (nstatus != napi_ok || errVal == nullptr) { MEDIA_LOGE("create error fail"); return napi_invalid_arg; } napi_value codeStr = nullptr; nstatus = napi_create_string_utf8(env, "code", NAPI_AUTO_LENGTH, &codeStr); if (nstatus != napi_ok || codeStr == nullptr) { MEDIA_LOGE("create code str fail"); return napi_invalid_arg; } napi_value errCodeVal = nullptr; nstatus = napi_create_int32(env, errCode, &errCodeVal); if (nstatus != napi_ok || errCodeVal == nullptr) { MEDIA_LOGE("create error code number val fail"); return napi_invalid_arg; } nstatus = napi_set_property(env, errVal, codeStr, errCodeVal); if (nstatus != napi_ok) { MEDIA_LOGE("set error code property fail"); return napi_invalid_arg; } napi_value nameStr = nullptr; nstatus = napi_create_string_utf8(env, "name", NAPI_AUTO_LENGTH, &nameStr); if (nstatus != napi_ok || nameStr == nullptr) { MEDIA_LOGE("create name str fail"); return napi_invalid_arg; } napi_value errNameVal = nullptr; nstatus = napi_create_string_utf8(env, "BusinessError", NAPI_AUTO_LENGTH, &errNameVal); if (nstatus != napi_ok || errNameVal == nullptr) { MEDIA_LOGE("create BusinessError str fail"); return napi_invalid_arg; } nstatus = napi_set_property(env, errVal, nameStr, errNameVal); if (nstatus != napi_ok) { MEDIA_LOGE("set error name property fail"); return napi_invalid_arg; } return napi_ok; } napi_ref CommonNapi::CreateReference(napi_env env, napi_value arg) { napi_ref ref = nullptr; napi_valuetype valueType = napi_undefined; if (arg != nullptr && napi_typeof(env, arg, &valueType) == napi_ok && valueType == napi_function) { MEDIA_LOGD("napi_create_reference"); napi_create_reference(env, arg, 1, &ref); } return ref; } napi_deferred CommonNapi::CreatePromise(napi_env env, napi_ref ref, napi_value &result) { napi_deferred deferred = nullptr; if (ref == nullptr) { MEDIA_LOGD("napi_create_promise"); napi_create_promise(env, &deferred, &result); } return deferred; } bool CommonNapi::SetPropertyByValueType(napi_env env, napi_value &obj, std::shared_ptr &meta, std::string key) { CHECK_AND_RETURN_RET(obj != nullptr && meta != nullptr, false); CHECK_AND_RETURN_RET(meta->Find(key) != meta->end(), false); bool ret = true; AnyValueType type = meta->GetValueType(key); if (type == AnyValueType::STRING) { std::string sValue; ret = meta->GetData(key, sValue); CHECK_AND_RETURN_RET_LOG(ret, ret, "GetData failed, key %{public}s", key.c_str()); ret = CommonNapi::SetPropertyString(env, obj, key, sValue); CHECK_AND_RETURN_RET_LOG(ret, ret, "SetPropertyString failed, key %{public}s", key.c_str()); } else if (type == AnyValueType::INT32_T) { int32_t value; ret = meta->GetData(key, value); CHECK_AND_RETURN_RET_LOG(ret, ret, "GetData failed, key %{public}s", key.c_str()); ret = CommonNapi::SetPropertyInt32(env, obj, key, value); CHECK_AND_RETURN_RET_LOG(ret, ret, "SetPropertyString failed, key %{public}s", key.c_str()); } else if (type == AnyValueType::FLOAT) { float dValue; ret = meta->GetData(key, dValue); CHECK_AND_RETURN_RET_LOG(ret, ret, "GetData failed, key %{public}s", key.c_str()); ret = CommonNapi::SetPropertyDouble(env, obj, key, dValue); CHECK_AND_RETURN_RET_LOG(ret, ret, "SetPropertyString failed, key %{public}s", key.c_str()); } else { MEDIA_LOGE("not supported value type"); } return true; } bool CommonNapi::AddRangeProperty(napi_env env, napi_value obj, const std::string &name, int32_t min, int32_t max) { CHECK_AND_RETURN_RET(obj != nullptr, false); napi_value range = nullptr; napi_status status = napi_create_object(env, &range); CHECK_AND_RETURN_RET(status == napi_ok, false); CHECK_AND_RETURN_RET(SetPropertyInt32(env, range, "min", min) == true, false); CHECK_AND_RETURN_RET(SetPropertyInt32(env, range, "max", max) == true, false); napi_value nameStr = nullptr; status = napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &nameStr); CHECK_AND_RETURN_RET(status == napi_ok, false); status = napi_set_property(env, obj, nameStr, range); CHECK_AND_RETURN_RET(status == napi_ok, false); return true; } bool CommonNapi::AddArrayProperty(napi_env env, napi_value obj, const std::string &name, const std::vector &vec) { CHECK_AND_RETURN_RET(obj != nullptr, false); napi_value array = nullptr; napi_status status = napi_create_array_with_length(env, vec.size(), &array); CHECK_AND_RETURN_RET(status == napi_ok, false); for (uint32_t i = 0; i < vec.size(); i++) { napi_value number = nullptr; (void)napi_create_int32(env, vec.at(i), &number); (void)napi_set_element(env, array, i, number); } napi_value nameStr = nullptr; status = napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &nameStr); CHECK_AND_RETURN_RET(status == napi_ok, false); status = napi_set_property(env, obj, nameStr, array); CHECK_AND_RETURN_RET(status == napi_ok, false); return true; } bool CommonNapi::SetPropertyArrayBuffer( const napi_env &env, napi_value &result, const std::string &fieldStr, size_t bufferLen, uint8_t *bufferData) { void *native = nullptr; napi_value arrayBuffer = nullptr; napi_status status = napi_create_arraybuffer(env, bufferLen, &native, &arrayBuffer); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "napi_create_arraybuffer failed"); CHECK_AND_RETURN_RET_LOG(memcpy_s(native, bufferLen, bufferData, bufferLen) == 0, false, "memcpy failed"); status = napi_set_named_property(env, result, fieldStr.c_str(), arrayBuffer); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "napi_set_named_property failed"); return true; } bool CommonNapi::AddArrayInt(napi_env env, napi_value &array, const std::vector &vec) { if (vec.size() == 0) { return false; } napi_status status = napi_create_array_with_length(env, vec.size(), &array); CHECK_AND_RETURN_RET(status == napi_ok, false); for (uint32_t i = 0; i < vec.size(); i++) { napi_value number = nullptr; (void)napi_create_int32(env, vec.at(i), &number); (void)napi_set_element(env, array, i, number); } return true; } bool CommonNapi::SetPropertyInt32(napi_env env, napi_value &obj, const std::string &key, int32_t value) { CHECK_AND_RETURN_RET(obj != nullptr, false); napi_value keyNapi = nullptr; napi_status status = napi_create_string_utf8(env, key.c_str(), NAPI_AUTO_LENGTH, &keyNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); napi_value valueNapi = nullptr; status = napi_create_int32(env, value, &valueNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); status = napi_set_property(env, obj, keyNapi, valueNapi); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "failed to set property"); return true; } bool CommonNapi::SetPropertyInt64(napi_env env, napi_value &obj, const std::string &key, int64_t value) { CHECK_AND_RETURN_RET(obj != nullptr, false); napi_value keyNapi = nullptr; napi_status status = napi_create_string_utf8(env, key.c_str(), NAPI_AUTO_LENGTH, &keyNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); napi_value valueNapi = nullptr; status = napi_create_int64(env, value, &valueNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); status = napi_set_property(env, obj, keyNapi, valueNapi); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "failed to set property"); return true; } bool CommonNapi::SetPropertyDouble(napi_env env, napi_value &obj, const std::string &key, double value) { CHECK_AND_RETURN_RET(obj != nullptr, false); napi_value keyNapi = nullptr; napi_status status = napi_create_string_utf8(env, key.c_str(), NAPI_AUTO_LENGTH, &keyNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); napi_value valueNapi = nullptr; status = napi_create_double(env, value, &valueNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); status = napi_set_property(env, obj, keyNapi, valueNapi); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "failed to set property"); return true; } bool CommonNapi::SetPropertyBool(napi_env env, napi_value &obj, const std::string &key, bool value) { CHECK_AND_RETURN_RET(obj != nullptr, false); napi_value keyNapi = nullptr; napi_status status = napi_create_string_utf8(env, key.c_str(), NAPI_AUTO_LENGTH, &keyNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); napi_value valueNapi = nullptr; status = napi_get_boolean(env, value, &valueNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); status = napi_set_property(env, obj, keyNapi, valueNapi); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "failed to set property"); return true; } bool CommonNapi::SetPropertyString(napi_env env, napi_value &obj, const std::string &key, const std::string &value) { CHECK_AND_RETURN_RET(obj != nullptr, false); napi_value keyNapi = nullptr; napi_status status = napi_create_string_utf8(env, key.c_str(), NAPI_AUTO_LENGTH, &keyNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); napi_value valueNapi = nullptr; status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &valueNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); status = napi_set_property(env, obj, keyNapi, valueNapi); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "failed to set property"); return true; } napi_value CommonNapi::CreateFormatBuffer(napi_env env, Format &format) { int32_t intValue = 0; size_t bufferLen = 0; std::string strValue; uint8_t *bufferData = nullptr; napi_value buffer = nullptr; napi_status status = napi_create_object(env, &buffer); CHECK_AND_RETURN_RET(status == napi_ok, nullptr); for (auto &iter : format.GetFormatMap()) { switch (format.GetValueType(std::string_view(iter.first))) { case FORMAT_TYPE_INT32: if (format.GetIntValue(iter.first, intValue)) { CHECK_AND_RETURN_RET(SetPropertyInt32(env, buffer, iter.first, intValue) == true, nullptr); } break; case FORMAT_TYPE_INT64: int64_t longValue; if (format.GetLongValue(iter.first, longValue) && longValue >= INT32_MIN && longValue <= INT32_MAX) { intValue = static_cast(longValue); CHECK_AND_RETURN_RET(SetPropertyInt32(env, buffer, iter.first, intValue) == true, nullptr); } break; case FORMAT_TYPE_DOUBLE: double doubleValue; if (format.GetDoubleValue(iter.first, doubleValue) && doubleValue >= INT32_MIN && doubleValue <= INT32_MAX) { intValue = static_cast(doubleValue); CHECK_AND_RETURN_RET(SetPropertyInt32(env, buffer, iter.first, intValue) == true, nullptr); } break; case FORMAT_TYPE_STRING: if (format.GetStringValue(iter.first, strValue)) { CHECK_AND_RETURN_RET(SetPropertyString(env, buffer, iter.first, strValue) == true, nullptr); } break; case FORMAT_TYPE_ADDR: if (format.GetBuffer(iter.first, &bufferData, bufferLen)) { CHECK_AND_RETURN_RET( SetPropertyArrayBuffer(env, buffer, iter.first, bufferLen, bufferData) == true, nullptr); } break; default: MEDIA_LOGE("format key: %{public}s", iter.first.c_str()); break; } } return buffer; } bool CommonNapi::CreateFormatBufferByRef(napi_env env, Format &format, napi_value &result) { int32_t intValue = 0; int64_t longValue = 0; std::string strValue = ""; napi_status status = napi_create_object(env, &result); CHECK_AND_RETURN_RET(status == napi_ok, false); for (auto &iter : format.GetFormatMap()) { switch (format.GetValueType(std::string_view(iter.first))) { case FORMAT_TYPE_INT32: if (format.GetIntValue(iter.first, intValue)) { (void)SetPropertyInt32(env, result, iter.first, intValue); } break; case FORMAT_TYPE_INT64: if (format.GetLongValue(iter.first, longValue)) { (void)SetPropertyInt64(env, result, iter.first, longValue); } break; case FORMAT_TYPE_STRING: if (format.GetStringValue(iter.first, strValue)) { (void)SetPropertyString(env, result, iter.first, strValue); } break; default: MEDIA_LOGE("format key: %{public}s", iter.first.c_str()); break; } } return true; } bool CommonNapi::AddNumberPropInt32(napi_env env, napi_value obj, const std::string &key, int32_t value) { CHECK_AND_RETURN_RET(obj != nullptr, false); napi_value keyNapi = nullptr; napi_status status = napi_create_string_utf8(env, key.c_str(), NAPI_AUTO_LENGTH, &keyNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); napi_value valueNapi = nullptr; status = napi_create_int32(env, value, &valueNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); status = napi_set_property(env, obj, keyNapi, valueNapi); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "Failed to set property"); return true; } bool CommonNapi::AddNumberPropInt64(napi_env env, napi_value obj, const std::string &key, int64_t value) { CHECK_AND_RETURN_RET(obj != nullptr, false); napi_value keyNapi = nullptr; napi_status status = napi_create_string_utf8(env, key.c_str(), NAPI_AUTO_LENGTH, &keyNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); napi_value valueNapi = nullptr; status = napi_create_int64(env, value, &valueNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); status = napi_set_property(env, obj, keyNapi, valueNapi); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "Failed to set property"); return true; } napi_status MediaJsResultStringVector::GetJsResult(napi_env env, napi_value &result) { napi_status status; size_t size = value_.size(); napi_create_array_with_length(env, size, &result); for (unsigned int i = 0; i < size; ++i) { std::string format = value_[i]; napi_value value = nullptr; status = napi_create_string_utf8(env, format.c_str(), NAPI_AUTO_LENGTH, &value); CHECK_AND_RETURN_RET_LOG(status == napi_ok, status, "Failed to call napi_create_string_utf8, with element %{public}u", i); status = napi_set_element(env, result, i, value); CHECK_AND_RETURN_RET_LOG(status == napi_ok, status, "Failed to call napi_set_element, with element %{public}u", i); } return napi_ok; } napi_status MediaJsResultIntArray::GetJsResult(napi_env env, napi_value &result) { napi_status status; size_t size = value_.size(); napi_create_array_with_length(env, size, &result); for (unsigned int i = 0; i < size; ++i) { int32_t index = value_[i]; napi_value value = nullptr; status = napi_create_int32(env, index, &value); CHECK_AND_RETURN_RET_LOG(status == napi_ok, status, "Failed to call napi_create_int32, with element %{public}u", i); status = napi_set_element(env, result, i, value); CHECK_AND_RETURN_RET_LOG(status == napi_ok, status, "Failed to call napi_set_element, with element %{public}u", i); } return napi_ok; } napi_status MediaJsResultArray::GetJsResult(napi_env env, napi_value &result) { // create Description napi_status status = napi_create_array(env, &result); if (status != napi_ok) { return napi_cancelled; } auto vecSize = value_.size(); for (size_t index = 0; index < vecSize; ++index) { napi_value description = nullptr; description = CommonNapi::CreateFormatBuffer(env, value_[index]); if (description == nullptr || napi_set_element(env, result, index, description) != napi_ok) { return napi_cancelled; } } return napi_ok; } MediaAsyncContext::MediaAsyncContext(napi_env env) : env_(env) { MEDIA_LOGD("MediaAsyncContext Create 0x%{public}06" PRIXPTR "", FAKE_POINTER(this)); } MediaAsyncContext::~MediaAsyncContext() { MEDIA_LOGD("MediaAsyncContext Destroy 0x%{public}06" PRIXPTR "", FAKE_POINTER(this)); } void MediaAsyncContext::SignError(int32_t code, const std::string &message, bool del) { errMessage = message; errCode = code; errFlag = true; delFlag = del; MEDIA_LOGE("SignError: %{public}s", message.c_str()); } napi_value CommonNapi::ThrowError(napi_env env, const int32_t errCode, const std::string errMsg) { napi_value result = nullptr; napi_status status = napi_throw_error(env, std::to_string(errCode).c_str(), errMsg.c_str()); if (status == napi_ok) { napi_get_undefined(env, &result); } return result; } void MediaAsyncContext::CompleteCallback(napi_env env, napi_status status, void *data) { MEDIA_LOGD("CompleteCallback In"); auto asyncContext = reinterpret_cast(data); CHECK_AND_RETURN_LOG(asyncContext != nullptr, "asyncContext is nullptr!"); std::string memoryTag = asyncContext->memoryTagHead + asyncContext->memoryTagTail; MEDIA_LOGD("MediaAsyncContext Create 0x%{public}06" PRIXPTR " memoryTag = %{public}s", FAKE_POINTER(data), memoryTag.c_str()); if (status != napi_ok) { asyncContext->SignError(MSERR_EXT_UNKNOWN, "napi_create_async_work status != napi_ok"); } napi_value result = nullptr; napi_get_undefined(env, &result); napi_value args[2] = { nullptr }; napi_get_undefined(env, &args[0]); napi_get_undefined(env, &args[1]); if (asyncContext->errFlag) { MEDIA_LOGD("async callback failed"); (void)CommonNapi::CreateError(env, asyncContext->errCode, asyncContext->errMessage, result); args[0] = result; } else { MEDIA_LOGD("async callback success"); if (asyncContext->JsResult != nullptr) { asyncContext->JsResult->GetJsResult(env, result); CheckCtorResult(env, result, asyncContext, args[0]); } if (!asyncContext->errFlag) { args[1] = result; } } Callback(env, asyncContext, args); napi_delete_async_work(env, asyncContext->work); if (asyncContext->delFlag) { delete asyncContext; asyncContext = nullptr; } } void MediaAsyncContext::Callback(napi_env env, const MediaAsyncContext *context, const napi_value *args) { if (context->deferred) { if (context->errFlag) { MEDIA_LOGE("promise napi_reject_deferred"); napi_reject_deferred(env, context->deferred, args[0]); } else { MEDIA_LOGD("promise napi_resolve_deferred"); napi_resolve_deferred(env, context->deferred, args[1]); } } else if (context->callbackRef != nullptr) { MEDIA_LOGD("callback napi_call_function"); napi_value callback = nullptr; napi_get_reference_value(env, context->callbackRef, &callback); CHECK_AND_RETURN_LOG(callback != nullptr, "callback is nullptr!"); constexpr size_t argCount = 2; napi_value retVal; napi_get_undefined(env, &retVal); napi_call_function(env, nullptr, callback, argCount, args, &retVal); napi_delete_reference(env, context->callbackRef); } else { MEDIA_LOGE("invalid promise and callback"); } } void MediaAsyncContext::CheckCtorResult(napi_env env, napi_value &result, MediaAsyncContext *ctx, napi_value &args) { CHECK_AND_RETURN(ctx != nullptr); if (ctx->ctorFlag) { void *instance = nullptr; if (napi_unwrap(env, result, reinterpret_cast(&instance)) != napi_ok || instance == nullptr) { MEDIA_LOGE("Failed to create instance"); ctx->errFlag = true; (void)CommonNapi::CreateError(env, MSERR_EXT_API9_NO_MEMORY, "The instance or memory has reached the upper limit, please recycle background playback", result); args = result; } } } napi_status MediaAsyncContext::SendCompleteEvent(napi_env env, MediaAsyncContext *asyncContext, napi_event_priority prio) { auto task = [env, asyncContext]() { MEDIA_LOGD("CompleteCallback In"); CHECK_AND_RETURN_LOG(asyncContext != nullptr, "asyncContext is nullptr!"); std::string memoryTag = asyncContext->memoryTagHead + asyncContext->memoryTagTail; MEDIA_LOGD("MediaAsyncContext 0x%{public}06" PRIXPTR " memoryTag = %{public}s", FAKE_POINTER(asyncContext), memoryTag.c_str()); napi_value result = nullptr; napi_get_undefined(env, &result); napi_value args[2] = { nullptr }; napi_get_undefined(env, &args[0]); napi_get_undefined(env, &args[1]); if (asyncContext->errFlag) { MEDIA_LOGD("async callback failed"); (void)CommonNapi::CreateError(env, asyncContext->errCode, asyncContext->errMessage, result); args[0] = result; } else { MEDIA_LOGD("async callback success"); if (asyncContext->JsResult != nullptr) { asyncContext->JsResult->GetJsResult(env, result); CheckCtorResult(env, result, asyncContext, args[0]); } if (!asyncContext->errFlag) { args[1] = result; } } Callback(env, asyncContext, args); if (asyncContext->delFlag) { delete asyncContext; } }; return napi_send_event(env, task, prio); } bool CommonNapi::AddStringProperty(napi_env env, napi_value obj, const std::string &key, const std::string &value) { CHECK_AND_RETURN_RET(obj != nullptr, false); napi_value keyNapi = nullptr; napi_status status = napi_create_string_utf8(env, key.c_str(), NAPI_AUTO_LENGTH, &keyNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); napi_value valueNapi = nullptr; status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &valueNapi); CHECK_AND_RETURN_RET(status == napi_ok, false); status = napi_set_property(env, obj, keyNapi, valueNapi); CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "Failed to set property"); return true; } bool CommonNapi::GetPropertyBool(napi_env env, napi_value configObj, const std::string &type, bool &result) { bool exist = false; napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist); if (status != napi_ok || !exist) { MEDIA_LOGE("can not find %{public}s property", type.c_str()); return false; } napi_value item = nullptr; if (napi_get_named_property(env, configObj, type.c_str(), &item) != napi_ok) { MEDIA_LOGE("get %{public}s property fail", type.c_str()); return false; } if (napi_get_value_bool(env, item, &result) != napi_ok) { MEDIA_LOGE("get %{public}s property value fail", type.c_str()); return false; } return true; } void CommonNapi::ConvertDeviceInfoToAudioDeviceDescriptor( std::shared_ptr audioDeviceDescriptor, const AudioStandard::AudioDeviceDescriptor &deviceInfo) { CHECK_AND_RETURN_LOG(audioDeviceDescriptor != nullptr, "audioDeviceDescriptor is nullptr"); audioDeviceDescriptor->deviceRole_ = deviceInfo.deviceRole_; audioDeviceDescriptor->deviceType_ = deviceInfo.deviceType_; audioDeviceDescriptor->deviceId_ = deviceInfo.deviceId_; audioDeviceDescriptor->channelMasks_ = deviceInfo.channelMasks_; audioDeviceDescriptor->channelIndexMasks_ = deviceInfo.channelIndexMasks_; audioDeviceDescriptor->deviceName_ = deviceInfo.deviceName_; audioDeviceDescriptor->macAddress_ = deviceInfo.macAddress_; audioDeviceDescriptor->interruptGroupId_ = deviceInfo.interruptGroupId_; audioDeviceDescriptor->volumeGroupId_ = deviceInfo.volumeGroupId_; audioDeviceDescriptor->networkId_ = deviceInfo.networkId_; audioDeviceDescriptor->displayName_ = deviceInfo.displayName_; audioDeviceDescriptor->audioStreamInfo_ = deviceInfo.audioStreamInfo_; } napi_status CommonNapi::SetDeviceDescriptor(const napi_env &env, const AudioStandard::AudioDeviceDescriptor &deviceInfo, napi_value &result) { (void)napi_create_object(env, &result); SetPropertyInt32(env, result, "deviceRole", static_cast(deviceInfo.deviceRole_)); SetPropertyInt32(env, result, "deviceType", static_cast(deviceInfo.deviceType_)); SetPropertyInt32(env, result, "id", static_cast(deviceInfo.deviceId_)); SetPropertyString(env, result, "name", deviceInfo.deviceName_); SetPropertyString(env, result, "address", deviceInfo.macAddress_); SetPropertyString(env, result, "networkId", deviceInfo.networkId_); SetPropertyString(env, result, "displayName", deviceInfo.displayName_); SetPropertyInt32(env, result, "interruptGroupId", static_cast(deviceInfo.interruptGroupId_)); SetPropertyInt32(env, result, "volumeGroupId", static_cast(deviceInfo.volumeGroupId_)); napi_value value = nullptr; napi_value sampleRates; AudioStandard::DeviceStreamInfo audioStreamInfo = deviceInfo.GetDeviceStreamInfo(); size_t size = audioStreamInfo.samplingRate.size(); napi_create_array_with_length(env, size, &sampleRates); size_t count = 0; for (const auto &samplingRate : audioStreamInfo.samplingRate) { napi_create_int32(env, samplingRate, &value); napi_set_element(env, sampleRates, count, value); count++; } napi_set_named_property(env, result, "sampleRates", sampleRates); napi_value channelCounts; std::set channelSet = audioStreamInfo.GetChannels(); size = channelSet.size(); napi_create_array_with_length(env, size, &channelCounts); count = 0; for (const auto &channels : channelSet) { napi_create_int32(env, channels, &value); napi_set_element(env, channelCounts, count, value); count++; } napi_set_named_property(env, result, "channelCounts", channelCounts); std::vector channelMasks_; channelMasks_.push_back(deviceInfo.channelMasks_); AddArrayProperty(env, result, "channelMasks", channelMasks_); std::vector channelIndexMasks_; channelIndexMasks_.push_back(deviceInfo.channelIndexMasks_); AddArrayProperty(env, result, "channelIndexMasks", channelIndexMasks_); std::vector encoding; encoding.push_back(audioStreamInfo.encoding); AddArrayProperty(env, result, "encodingTypes", encoding); return napi_ok; } napi_status CommonNapi::SetDeviceDescriptors(const napi_env &env, const std::vector> &deviceDescriptors, napi_value &result) { napi_status status = napi_create_array_with_length(env, deviceDescriptors.size(), &result); for (size_t i = 0; i < deviceDescriptors.size(); i++) { if (deviceDescriptors[i] != nullptr) { napi_value valueParam = nullptr; SetDeviceDescriptor(env, deviceDescriptors[i], valueParam); napi_set_element(env, result, i, valueParam); } } return status; } napi_status CommonNapi::SetValueDeviceInfo(const napi_env &env, const AudioStandard::AudioDeviceDescriptor &deviceInfo, napi_value &result) { std::vector> deviceDescriptors; std::shared_ptr audioDeviceDescriptor = std::make_shared(); CHECK_AND_RETURN_RET_LOG(audioDeviceDescriptor != nullptr, napi_generic_failure, "audioDeviceDescriptor malloc failed"); ConvertDeviceInfoToAudioDeviceDescriptor(audioDeviceDescriptor, deviceInfo); deviceDescriptors.push_back(std::move(audioDeviceDescriptor)); SetDeviceDescriptors(env, deviceDescriptors, result); return napi_ok; } } // namespace Media } // namespace OHOS