* Copyright (C) 2023 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.
*/
#define MLOG_TAG "MediaAssetManagerNapi"
#include "media_asset_manager_napi.h"
#include <string>
#include <sys/sendfile.h>
#include <uuid/uuid.h>
#include "accesstoken_kit.h"
#include "adapted_vo.h"
#include "camera_character_types.h"
#include "directory_ex.h"
#include "file_uri.h"
#include "image_source_napi.h"
#include "log_cinematic_access_vo.h"
#include "medialibrary_business_code.h"
#include "medialibrary_client_errno.h"
#include "medialibrary_napi_utils_ext.h"
#include "medialibrary_notify_utils.h"
#include "medialibrary_tracer.h"
#include "moving_photo_napi.h"
#include "moving_photo_call_transcoder.h"
#include "multistages_capture_on_process_observer.h"
#include "permission_utils.h"
#include "picture_handle_client.h"
#include "query_photo_vo.h"
#include "ui_extension_context.h"
#include "user_define_ipc_client.h"
#include "userfile_client.h"
#include "media_call_transcode.h"
#include "cancel_request_vo.h"
#include "get_progress_callback_vo.h"
#include "process_video_vo.h"
using namespace OHOS::Security::AccessToken;
namespace OHOS {
namespace Media {
static const std::string MEDIA_ASSET_MANAGER_CLASS = "MediaAssetManager";
static std::mutex multiStagesCaptureLock;
static std::map<std::string, std::map<std::string, AssetHandler*>> inProcessUriMap;
static std::mutex registerTaskLock;
static std::map<std::string,
std::map<ObserverType, std::shared_ptr<MediaOnNotifyUserDefineObserver>>> multiStagesObserverNewMap;
const int32_t UUID_STR_LENGTH = 37;
const int32_t MAX_URI_SIZE = 384;
const int32_t REQUEST_ID_MAX_LEN = 64;
const int32_t PROGRESS_MAX = 100;
const std::string HIGH_TEMPERATURE = "high_temperature";
const std::string HIGH_TEMPERATURE_VIDEO = "high_temperature_video";
static const std::string URI_TYPE = "uriType";
static const std::string TYPE_PHOTOS = "1";
static const int32_t AVERAGE_FACTOR = 2;
static const int32_t SLEEP_100_MS = 100;
thread_local unique_ptr<ChangeListenerNapi> g_multiStagesRequestListObj = nullptr;
thread_local napi_ref constructor_ = nullptr;
static SafeMap<std::string, AssetHandler*> inProcessFastRequests;
static SafeMap<std::string, AssetHandler*> onPreparedResult_;
static SafeMap<std::string, napi_value> onPreparedResultValue_;
static SafeMap<std::string, bool> isTranscoderMap_;
std::unique_ptr<std::thread> MediaAssetManagerNapi::progressThread_ = nullptr;
std::mutex MediaAssetManagerNapi::runningMutex_;
std::mutex MediaAssetManagerNapi::sleepMutex_;
std::condition_variable MediaAssetManagerNapi::condition_;
std::atomic_bool MediaAssetManagerNapi::pauseFlag_ = true;
std::atomic_bool MediaAssetManagerNapi::stopFlag_ = true;
static const std::map<MultistagesCaptureNotifyType, std::vector<ObserverType>> MATCH_NOTIFY_TO_OBSERVER = {
{ MultistagesCaptureNotifyType::ON_PROCESS_IMAGE_DONE, {ObserverType::REQUEST_IMAGE} },
{ MultistagesCaptureNotifyType::ON_ERROR_IMAGE, {ObserverType::REQUEST_IMAGE, ObserverType::REQUEST_QUICK_IMAGE} },
{ MultistagesCaptureNotifyType::ON_PROCESS_VIDEO_DONE, {ObserverType::REQUEST_VIDEO} },
{ MultistagesCaptureNotifyType::ON_ERROR_VIDEO, {ObserverType::REQUEST_VIDEO} },
{ MultistagesCaptureNotifyType::YUV_READY, {ObserverType::REQUEST_QUICK_IMAGE} },
};
napi_value MediaAssetManagerNapi::Init(napi_env env, napi_value exports)
{
NapiClassInfo info = {.name = MEDIA_ASSET_MANAGER_CLASS,
.ref = &constructor_,
.constructor = Constructor,
.props = {
DECLARE_NAPI_STATIC_FUNCTION("requestImage", JSRequestImage),
DECLARE_NAPI_STATIC_FUNCTION("requestImageData", JSRequestImageData),
DECLARE_NAPI_STATIC_FUNCTION("requestMovingPhoto", JSRequestMovingPhoto),
DECLARE_NAPI_STATIC_FUNCTION("cancelRequest", JSCancelRequest),
DECLARE_NAPI_STATIC_FUNCTION("requestVideoFile", JSRequestVideoFile),
DECLARE_NAPI_STATIC_FUNCTION("requestVideo", JSRequestVideo),
DECLARE_NAPI_STATIC_FUNCTION("loadMovingPhoto", JSLoadMovingPhoto),
DECLARE_NAPI_STATIC_FUNCTION("quickRequestImage", JSRequestEfficientIImage)
}};
MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
return exports;
}
napi_value MediaAssetManagerNapi::Constructor(napi_env env, napi_callback_info info)
{
napi_value newTarget = nullptr;
CHECK_ARGS(env, napi_get_new_target(env, info, &newTarget), JS_INNER_FAIL);
bool isConstructor = newTarget != nullptr;
if (isConstructor) {
napi_value thisVar = nullptr;
unique_ptr<MediaAssetManagerNapi> obj = make_unique<MediaAssetManagerNapi>();
CHECK_COND_WITH_MESSAGE(env, obj != nullptr, "Create MediaAssetManagerNapi failed");
CHECK_ARGS(env,
napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()), MediaAssetManagerNapi::Destructor,
nullptr, nullptr),
JS_INNER_FAIL);
obj.release();
return thisVar;
}
napi_value constructor = nullptr;
napi_value result = nullptr;
NAPI_CALL(env, napi_get_reference_value(env, constructor_, &constructor));
NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result));
return result;
}
void MediaAssetManagerNapi::Destructor(napi_env env, void *nativeObject, void *finalizeHint)
{
auto* mediaAssetManager = reinterpret_cast<MediaAssetManagerNapi*>(nativeObject);
if (mediaAssetManager != nullptr) {
delete mediaAssetManager;
mediaAssetManager = nullptr;
}
}
static bool HasReadPermission()
{
AccessTokenID tokenCaller = IPCSkeleton::GetSelfTokenID();
int result = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_READ_IMAGEVIDEO);
return result == PermissionState::PERMISSION_GRANTED;
}
static AssetHandler* CreateAssetHandler(const std::string &photoId, const std::string &requestId,
const std::string &uri, const MediaAssetDataHandlerPtr &handler, napi_threadsafe_function func)
{
AssetHandler *assetHandler = new AssetHandler(photoId, requestId, uri, handler, func);
NAPI_DEBUG_LOG("[AssetHandler create] photoId: %{public}s, requestId: %{public}s, uri: %{public}s",
photoId.c_str(), requestId.c_str(), uri.c_str());
return assetHandler;
}
static void DeleteAssetHandlerSafe(AssetHandler *handler, napi_env env)
{
if (handler != nullptr) {
if (handler->dataHandler != nullptr) {
handler->dataHandler->DeleteNapiReference(env);
}
if (handler->threadSafeFunc != nullptr) {
napi_release_threadsafe_function(handler->threadSafeFunc, napi_tsfn_release);
handler->threadSafeFunc = nullptr;
}
delete handler;
handler = nullptr;
}
}
static void DeleteProcessHandlerSafe(ProgressHandler *handler, napi_env env)
{
if (handler == nullptr) {
NAPI_WARN_LOG("handler is invalid");
return;
}
if (handler->progressRef != nullptr && env != nullptr) {
napi_delete_reference(env, handler->progressRef);
handler->progressRef = nullptr;
}
if (handler->progressFunc != nullptr) {
napi_release_threadsafe_function(handler->progressFunc, napi_tsfn_release);
handler->progressFunc = nullptr;
}
delete handler;
handler = nullptr;
}
static void InsertInProcessMapRecord(const std::string &requestUri, const std::string &requestId,
AssetHandler *handler)
{
std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
std::map<std::string, AssetHandler*> assetHandler;
auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(requestUri);
if (inProcessUriMap.find(uriLocal) != inProcessUriMap.end()) {
assetHandler = inProcessUriMap[uriLocal];
assetHandler[requestId] = handler;
inProcessUriMap[uriLocal] = assetHandler;
} else {
assetHandler[requestId] = handler;
inProcessUriMap[uriLocal] = assetHandler;
}
}
static void DeleteRecordNoLock(const std::string &requestUri, const std::string &requestId)
{
NAPI_INFO_LOG("DeleteRecordNoLock, requestUri: %{public}s, requestId: %{public}s.",
requestUri.c_str(), requestId.c_str());
auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(requestUri);
if (inProcessUriMap.find(uriLocal) == inProcessUriMap.end()) {
return;
}
std::map<std::string, AssetHandler*> &assetHandlers = inProcessUriMap[uriLocal];
if (assetHandlers.find(requestId) == assetHandlers.end()) {
return;
}
AssetHandler* handler = assetHandlers[requestId];
if (handler == nullptr) {
return;
}
ObserverType observerType = handler->observerType;
assetHandlers.erase(requestId);
if (assetHandlers.empty()) {
inProcessUriMap.erase(uriLocal);
}
std::unique_lock<std::mutex> registerLock(registerTaskLock);
if (multiStagesObserverNewMap.find(uriLocal) == multiStagesObserverNewMap.end()) {
return;
}
auto &observerMap = multiStagesObserverNewMap[uriLocal];
if (observerMap.find(observerType) != observerMap.end()) {
UserFileClient::UnregisterObserverExtProvider(Uri(uriLocal),
static_cast<std::shared_ptr<DataShare::DataShareObserver>>(observerMap[observerType]));
}
observerMap.erase(observerType);
if (observerMap.empty()) {
multiStagesObserverNewMap.erase(uriLocal);
}
}
static void DeleteInProcessMapRecord(const std::string &requestUri, const std::string &requestId)
{
DeleteRecordNoLock(requestUri, requestId);
}
static int32_t IsInProcessInMapRecord(const std::string &requestId, AssetHandler* &handler)
{
for (auto record : inProcessUriMap) {
if (record.second.find(requestId) != record.second.end()) {
handler = record.second[requestId];
return true;
}
}
return false;
}
static AssetHandler* InsertDataHandler(NotifyMode notifyMode, napi_env env,
MediaAssetManagerAsyncContext *asyncContext)
{
napi_ref dataHandlerRef;
napi_threadsafe_function threadSafeFunc;
if (notifyMode == NotifyMode::FAST_NOTIFY) {
dataHandlerRef = asyncContext->dataHandlerRef;
asyncContext->dataHandlerRef = nullptr;
threadSafeFunc = asyncContext->onDataPreparedPtr;
} else {
dataHandlerRef = asyncContext->dataHandlerRef2;
asyncContext->dataHandlerRef2 = nullptr;
threadSafeFunc = asyncContext->onDataPreparedPtr2;
}
std::shared_ptr<NapiMediaAssetDataHandler> mediaAssetDataHandler = make_shared<NapiMediaAssetDataHandler>(
env, dataHandlerRef, asyncContext->returnDataType, asyncContext->photoUri, asyncContext->destUri,
asyncContext->sourceMode);
mediaAssetDataHandler->SetCompatibleMode(asyncContext->compatibleMode);
mediaAssetDataHandler->SetNotifyMode(notifyMode);
mediaAssetDataHandler->SetRequestId(asyncContext->requestId);
mediaAssetDataHandler->SetProgressHandlerRef(asyncContext->progressHandlerRef);
mediaAssetDataHandler->SetThreadsafeFunction(asyncContext->onProgressPtr);
AssetHandler *assetHandler = CreateAssetHandler(asyncContext->photoId, asyncContext->requestId,
asyncContext->photoUri, mediaAssetDataHandler, threadSafeFunc);
assetHandler->photoQuality = asyncContext->photoQuality;
assetHandler->needsExtraInfo = asyncContext->needsExtraInfo;
assetHandler->observerType = asyncContext->observerType;
HILOG_COMM_INFO("%{public}s:{%{public}s:%{public}d} Add %{public}d, %{public}s, %{public}s",
MLOG_TAG, __FUNCTION__, __LINE__,
notifyMode, MediaFileUtils::DesensitizeUri(asyncContext->photoUri).c_str(), asyncContext->requestId.c_str());
switch (notifyMode) {
case NotifyMode::FAST_NOTIFY: {
inProcessFastRequests.EnsureInsert(asyncContext->requestId, assetHandler);
break;
}
case NotifyMode::WAIT_FOR_HIGH_QUALITY: {
InsertInProcessMapRecord(asyncContext->photoUri, asyncContext->requestId, assetHandler);
break;
}
default:
break;
}
return assetHandler;
}
static ProgressHandler* InsertProgressHandler(napi_env env, MediaAssetManagerAsyncContext *asyncContext,
ProgressMode progressMode, CameraProgressMode cameraProgressMode)
{
napi_ref dataHandlerRef;
napi_threadsafe_function threadSafeFunc;
dataHandlerRef = asyncContext->progressHandlerRef;
asyncContext->progressHandlerRef = nullptr;
threadSafeFunc = asyncContext->onProgressPtr;
ProgressHandler *progressHandler = new ProgressHandler(env, threadSafeFunc, asyncContext->requestId,
dataHandlerRef);
progressHandler->progressMode = progressMode;
progressHandler->cameraProgressMode = cameraProgressMode;
MediaAssetManagerNapi::progressHandlerMap_.EnsureInsert(asyncContext->requestId, progressHandler);
NAPI_DEBUG_LOG("InsertProgressHandler");
return progressHandler;
}
static void DeleteDataHandler(NotifyMode notifyMode, const std::string &requestUri, const std::string &requestId)
{
std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(requestUri);
NAPI_INFO_LOG("Rmv %{public}d, %{public}s, %{public}s", notifyMode,
MediaFileUtils::DesensitizeUri(requestUri).c_str(), requestId.c_str());
if (notifyMode == NotifyMode::WAIT_FOR_HIGH_QUALITY) {
DeleteInProcessMapRecord(uriLocal, requestId);
}
inProcessFastRequests.Erase(requestId);
}
void MediaAssetManagerNapi::ProcessImage(const int fileId, const int deliveryMode)
{
std::string uriStr = CONST_PAH_PROCESS_IMAGE;
MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
Uri uri(uriStr);
DataShare::DataSharePredicates predicates;
int errCode = 0;
std::vector<std::string> columns { std::to_string(fileId), std::to_string(deliveryMode) };
UserFileClient::Query(uri, predicates, columns, errCode);
}
void MediaAssetManagerNapi::AddImage(const int fileId, DeliveryMode deliveryMode)
{
Uri updateAssetUri(CONST_PAH_ADD_IMAGE);
DataShare::DataSharePredicates predicates;
DataShare::DataShareValuesBucket valuesBucket;
valuesBucket.Put(MediaColumn::MEDIA_ID, fileId);
valuesBucket.Put("deliveryMode", static_cast<int>(deliveryMode));
UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
}
void MediaAssetManagerNapi::ProcessVideo(MediaAssetManagerAsyncContext *asyncContext)
{
uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::CAMERA_DEFINE_PROCESS_VIDEO);
ProcessVideoReqBody reqBody;
reqBody.fileId = asyncContext->fileId;
reqBody.deliveryMode = static_cast<int32_t>(asyncContext->deliveryMode);
reqBody.photoId = asyncContext->photoId;
reqBody.requestId = asyncContext->requestId;
IPC::UserDefineIPCClient().Call(businessCode, reqBody);
}
napi_status GetDeliveryMode(napi_env env, const napi_value arg, const string &propName,
DeliveryMode& deliveryMode)
{
bool present = false;
napi_value property = nullptr;
int mode = -1;
CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present),
"Failed to check property name");
if (!present) {
NAPI_ERR_LOG("No delivery mode specified");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "No delivery mode specified");
return napi_invalid_arg;
}
CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property), "Failed to get property");
CHECK_STATUS_RET(napi_get_value_int32(env, property, &mode), "Failed to parse deliveryMode argument value");
if (mode < 0 || mode > 2) {
NAPI_ERR_LOG("delivery mode invalid argument ");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "invalid delivery mode value");
return napi_invalid_arg;
}
deliveryMode = static_cast<DeliveryMode>(mode);
return napi_ok;
}
napi_status GetSourceMode(napi_env env, const napi_value arg, const string &propName,
SourceMode& sourceMode)
{
bool present = false;
napi_value property = nullptr;
int mode = -1;
CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present), "Failed to check property name");
if (!present) {
sourceMode = SourceMode::EDITED_MODE;
return napi_ok;
} else if (!MediaLibraryNapiUtils::IsSystemApp()) {
NAPI_ERR_LOG("Source mode is only available to system apps");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Source mode is only available to system apps");
return napi_invalid_arg;
}
CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property), "Failed to get property");
CHECK_STATUS_RET(napi_get_value_int32(env, property, &mode), "Failed to parse sourceMode argument value");
if (mode < 0 || mode > 1) {
NAPI_ERR_LOG("source mode invalid");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "invalid source mode value");
return napi_invalid_arg;
}
sourceMode = static_cast<SourceMode>(mode);
return napi_ok;
}
napi_status ParseArgGetRequestOption(napi_env env, napi_value arg, DeliveryMode &deliveryMode, SourceMode &sourceMode)
{
CHECK_STATUS_RET(GetDeliveryMode(env, arg, "deliveryMode", deliveryMode), "Failed to parse deliveryMode");
CHECK_STATUS_RET(GetSourceMode(env, arg, "sourceMode", sourceMode), "Failed to parse sourceMode");
return napi_ok;
}
napi_status GetCompatibleMode(napi_env env, const napi_value arg, const string &propName,
CompatibleMode& compatibleMode)
{
bool present = false;
napi_value property = nullptr;
int mode = static_cast<int>(CompatibleMode::ORIGINAL_FORMAT_MODE);
CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present), "Failed to check property name");
if (!present) {
NAPI_DEBUG_LOG("compatible mode is null");
compatibleMode = CompatibleMode::ORIGINAL_FORMAT_MODE;
return napi_ok;
}
CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property), "Failed to get property");
CHECK_STATUS_RET(napi_get_value_int32(env, property, &mode), "Failed to parse compatiblemode argument value");
if (static_cast<CompatibleMode>(mode) < CompatibleMode::ORIGINAL_FORMAT_MODE ||
static_cast<CompatibleMode>(mode) > CompatibleMode::COMPATIBLE_FORMAT_MODE) {
NAPI_ERR_LOG("delivery mode invalid argument ");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "invalid compatible mode value");
return napi_invalid_arg;
}
#if !defined(USE_VIDEO_PROCESSING_ENGINE) || !defined(USE_VIDEO_PROCESSING_ENGINE_EXT)
if (static_cast<CompatibleMode>(mode) == CompatibleMode::COMPATIBLE_FORMAT_MODE) {
NAPI_ERR_LOG("current environment not support transcoder");
NapiError::ThrowError(env, OHOS_NOT_SUPPORT_TRANSCODER_CODE, "not support transcoder");
return napi_invalid_arg;
}
#endif
compatibleMode = static_cast<CompatibleMode>(mode);
return napi_ok;
}
napi_status GetMediaAssetProgressHandler(napi_env env, const napi_value arg, napi_value& mediaAssetProgressHandler,
const string &propName)
{
CHECK_COND_LOG_THROW_RETURN_RET(env, arg != nullptr, OHOS_INVALID_PARAM_CODE,
"MediaAssetProgressHandler invalid argument", napi_invalid_arg, "MediaAssetProgressHandler is nullptr");
bool present = false;
CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present), "Failed to check property name");
if (!present) {
NAPI_DEBUG_LOG("MediaAssetProgressHandler is null");
mediaAssetProgressHandler = nullptr;
return napi_ok;
}
napi_value progressHandler;
napi_status status = napi_get_named_property(env, arg, "mediaAssetProgressHandler", &progressHandler);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
"failed to get mediaAssetProgressHandler ", napi_invalid_arg,
"failed to get mediaAssetProgressHandler, napi status: %{public}d", static_cast<int>(status));
napi_valuetype valueType;
status = napi_typeof(env, progressHandler, &valueType);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid progress handler",
napi_invalid_arg, "failed to get type of progress handler, napi status: %{public}d", static_cast<int>(status));
CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_object, OHOS_INVALID_PARAM_CODE,
"progress handler not an object", napi_invalid_arg, "progress handler not an object");
napi_value onProgress;
status = napi_get_named_property(env, progressHandler, ON_PROGRESS_FUNC, &onProgress);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
"unable to get onProgress function", napi_invalid_arg,
"failed to get onProgress function, napi status: %{public}d", static_cast<int>(status));
status = napi_typeof(env, onProgress, &valueType);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onProgress",
napi_invalid_arg, "failed to get type of onProgress, napi status: %{public}d", static_cast<int>(status));
CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_function, OHOS_INVALID_PARAM_CODE,
"onProgress not a function", napi_invalid_arg, "onProgress not a function");
mediaAssetProgressHandler = progressHandler;
return napi_ok;
}
napi_status ParseArgGetRequestOptionMore(napi_env env, napi_value arg, CompatibleMode &compatibleMode,
napi_value &mediaAssetProgressHandler)
{
NAPI_DEBUG_LOG("ParseArgGetRequestOptionMore start");
CHECK_STATUS_RET(GetCompatibleMode(env, arg, "compatibleMode", compatibleMode), "Failed to parse compatibleMode");
if (GetMediaAssetProgressHandler(env, arg, mediaAssetProgressHandler, "mediaAssetProgressHandler") != napi_ok) {
NAPI_ERR_LOG("requestMedia GetMediaAssetProgressHandler error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia GetMediaAssetProgressHandler error");
return napi_invalid_arg;
}
return napi_ok;
}
napi_status ParseArgGetPhotoAsset(napi_env env, napi_value arg, int &fileId, std::string &uri,
std::string &displayName)
{
if (arg == nullptr) {
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "ParseArgGetPhotoAsset failed to get photoAsset");
return napi_invalid_arg;
}
FileAssetNapi *obj = nullptr;
napi_unwrap(env, arg, reinterpret_cast<void**>(&obj));
if (obj == nullptr) {
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to get asset napi object");
return napi_invalid_arg;
}
fileId = obj->GetFileId();
uri = obj->GetFileUri();
displayName = obj->GetFileDisplayName();
return napi_ok;
}
napi_status ParseArgGetPhotoAsset(napi_env env, napi_value arg, unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
{
if (arg == nullptr) {
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "ParseArgGetPhotoAsset failed to get photoAsset");
return napi_invalid_arg;
}
FileAssetNapi *obj = nullptr;
napi_unwrap(env, arg, reinterpret_cast<void**>(&obj));
if (obj == nullptr) {
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to get asset napi object");
return napi_invalid_arg;
}
asyncContext->fileId = obj->GetFileId();
asyncContext->photoUri = obj->GetFileUri();
asyncContext->displayName = obj->GetFileDisplayName();
asyncContext->userId = obj->GetFileAssetInstance()->GetUserId();
return napi_ok;
}
napi_status ParseArgGetDestPath(napi_env env, napi_value arg, std::string &destPath)
{
if (arg == nullptr) {
NAPI_ERR_LOG("destPath arg is invalid");
return napi_invalid_arg;
}
napi_get_print_string(env, arg, destPath);
if (destPath.empty()) {
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to get destPath napi object");
return napi_invalid_arg;
}
return napi_ok;
}
napi_status ParseArgGetEfficientImageDataHandler(napi_env env, napi_value arg, napi_value& dataHandler,
bool& needsExtraInfo)
{
CHECK_COND_LOG_THROW_RETURN_RET(env, arg != nullptr, OHOS_INVALID_PARAM_CODE, "efficient handler invalid argument",
napi_invalid_arg, "efficient data handler is nullptr");
napi_valuetype valueType;
napi_status status = napi_typeof(env, arg, &valueType);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid efficient data handler",
napi_invalid_arg, "failed to get type of efficient data handler, napi status: %{public}d",
static_cast<int>(status));
CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_object, OHOS_INVALID_PARAM_CODE,
"efficient data handler not a object", napi_invalid_arg, "efficient data handler not a object");
dataHandler = arg;
napi_value onDataPrepared;
status = napi_get_named_property(env, arg, ON_DATA_PREPARED_FUNC, &onDataPrepared);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
"unable to get onDataPrepared function", napi_invalid_arg,
"failed to get type of efficient data handler, napi status: %{public}d", static_cast<int>(status));
status = napi_typeof(env, onDataPrepared, &valueType);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
napi_invalid_arg, "failed to get type of onDataPrepared, napi status: %{public}d", static_cast<int>(status));
CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_function, OHOS_INVALID_PARAM_CODE,
"onDataPrepared not a function", napi_invalid_arg, "onDataPrepared not a function");
napi_value paramCountNapi;
status = napi_get_named_property(env, onDataPrepared, "length", ¶mCountNapi);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
napi_invalid_arg, "get onDataPrepared arg count fail, napi status: %{public}d", static_cast<int>(status));
int32_t paramCount = -1;
constexpr int paramCountMin = 2;
constexpr int paramCountMax = 3;
status = napi_get_value_int32(env, paramCountNapi, ¶mCount);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
napi_invalid_arg, "get onDataPrepared arg count value fail, napi status: %{public}d", static_cast<int>(status));
CHECK_COND_LOG_THROW_RETURN_RET(env, (paramCount >= paramCountMin && paramCount <= paramCountMax),
OHOS_INVALID_PARAM_CODE, "onDataPrepared has wrong number of parameters",
napi_invalid_arg, "onDataPrepared has wrong number of parameters");
if (paramCount == ARGS_THREE) {
needsExtraInfo = true;
}
return napi_ok;
}
napi_status ParseArgGetDataHandler(napi_env env, napi_value arg, napi_value& dataHandler, bool& needsExtraInfo)
{
CHECK_COND_LOG_THROW_RETURN_RET(env, arg != nullptr, OHOS_INVALID_PARAM_CODE, "data handler invalid argument",
napi_invalid_arg, "data handler is nullptr");
napi_valuetype valueType;
napi_status status = napi_typeof(env, arg, &valueType);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid data handler",
napi_invalid_arg, "failed to get type of data handler, napi status: %{public}d", static_cast<int>(status));
CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_object, OHOS_INVALID_PARAM_CODE,
"data handler not a object", napi_invalid_arg, "data handler not a object");
dataHandler = arg;
napi_value onDataPrepared;
status = napi_get_named_property(env, arg, ON_DATA_PREPARED_FUNC, &onDataPrepared);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
"unable to get onDataPrepared function", napi_invalid_arg,
"failed to get type of data handler, napi status: %{public}d", static_cast<int>(status));
status = napi_typeof(env, onDataPrepared, &valueType);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
napi_invalid_arg, "failed to get type of onDataPrepared, napi status: %{public}d", static_cast<int>(status));
CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_function, OHOS_INVALID_PARAM_CODE,
"onDataPrepared not a function", napi_invalid_arg, "onDataPrepared not a function");
napi_value paramCountNapi;
status = napi_get_named_property(env, onDataPrepared, "length", ¶mCountNapi);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
napi_invalid_arg, "get onDataPrepared arg count fail, napi status: %{public}d", static_cast<int>(status));
int32_t paramCount = -1;
constexpr int paramCountMin = 1;
constexpr int paramCountMax = 2;
status = napi_get_value_int32(env, paramCountNapi, ¶mCount);
CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
napi_invalid_arg, "get onDataPrepared arg count value fail, napi status: %{public}d", static_cast<int>(status));
CHECK_COND_LOG_THROW_RETURN_RET(env, (paramCount >= paramCountMin && paramCount <= paramCountMax),
OHOS_INVALID_PARAM_CODE, "onDataPrepared has wrong number of parameters",
napi_invalid_arg, "onDataPrepared has wrong number of parameters");
if (paramCount == ARGS_TWO) {
needsExtraInfo = true;
}
return napi_ok;
}
static std::string GenerateRequestId()
{
uuid_t uuid;
uuid_generate(uuid);
char str[UUID_STR_LENGTH] = {};
uuid_unparse(uuid, str);
return str;
}
void MediaAssetManagerNapi::RegisterTaskNewObserver(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
{
CHECK_NULL_PTR_RETURN_VOID(asyncContext, "asyncContext is nullptr");
CHECK_IF_EQUAL(asyncContext->observerType != ObserverType::UNDEFINED,
"In asyncContext, observerType is undefined, RegisterTaskNewObserver failed.");
std::string uriLocal = MediaFileUtils::GetUriWithoutDisplayname(asyncContext->photoUri);
auto observerBodyBase = std::make_shared<MultistagesCaptureOnProcessObserver>(uriLocal, asyncContext->observerType);
auto dataObserver = std::make_shared<MediaOnNotifyUserDefineObserver>(
NotifyUriType::USER_DEFINE_NOTIFY_URI, observerBodyBase);
Notification::NotifyUriType registerUriType = Notification::NotifyUriType::INVALID;
std::string registerUri = "";
if (MediaLibraryNotifyUtils::GetUserDefineNotifyTypeAndUri(
Notification::NotifyUriType::USER_DEFINE_NOTIFY_URI, registerUriType, registerUri) != E_OK) {
NAPI_ERR_LOG("GetUserDefineNotifyTypeAndUri failed.");
return;
}
std::unique_lock<std::mutex> registerLock(registerTaskLock);
if (multiStagesObserverNewMap.find(uriLocal) == multiStagesObserverNewMap.end()) {
multiStagesObserverNewMap.insert(std::make_pair(
uriLocal, std::map<ObserverType, std::shared_ptr<MediaOnNotifyUserDefineObserver>>{}));
}
auto &observerMap = multiStagesObserverNewMap.at(uriLocal);
if (observerMap.find(asyncContext->observerType) == observerMap.end()) {
UserFileClient::RegisterObserverExtProvider(Uri(registerUri),
static_cast<std::shared_ptr<DataShare::DataShareObserver>>(dataObserver), false);
observerMap.insert(std::make_pair(asyncContext->observerType, dataObserver));
}
registerLock.unlock();
InsertDataHandler(NotifyMode::WAIT_FOR_HIGH_QUALITY, env, asyncContext);
if (asyncContext->observerType == ObserverType::REQUEST_IMAGE
|| asyncContext->observerType == ObserverType::REQUEST_QUICK_IMAGE) {
MediaAssetManagerNapi::ProcessImage(asyncContext->fileId, static_cast<int32_t>(asyncContext->deliveryMode));
} else if (asyncContext->observerType == ObserverType::REQUEST_VIDEO) {
MediaAssetManagerNapi::ProcessVideo(asyncContext);
}
NAPI_INFO_LOG("RegisterTaskNewObserver success.");
}
napi_status MediaAssetManagerNapi::ParseRequestMediaArgs(napi_env env, napi_callback_info info,
unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
{
napi_value thisVar = nullptr;
GET_JS_ARGS(env, info, asyncContext->argc, asyncContext->argv, thisVar);
if (asyncContext->argc != ARGS_FOUR && asyncContext->argc != ARGS_FIVE) {
NAPI_ERR_LOG("requestMedia argc error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia argc invalid");
return napi_invalid_arg;
}
if (ParseArgGetPhotoAsset(env, asyncContext->argv[PARAM1], asyncContext) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetPhotoAsset error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetPhotoAsset error");
return napi_invalid_arg;
}
if (ParseArgGetRequestOption(env, asyncContext->argv[PARAM2], asyncContext->deliveryMode,
asyncContext->sourceMode) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetRequestOption error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOption error");
return napi_invalid_arg;
}
if (ParseArgGetRequestOptionMore(env, asyncContext->argv[PARAM2], asyncContext->compatibleMode,
asyncContext->mediaAssetProgressHandler) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetRequestOptionMore error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOptionMore error");
return napi_invalid_arg;
}
if (asyncContext->argc == ARGS_FOUR) {
if (ParseArgGetDataHandler(env, asyncContext->argv[PARAM3], asyncContext->dataHandler,
asyncContext->needsExtraInfo) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetDataHandler error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDataHandler error");
return napi_invalid_arg;
}
} else if (asyncContext->argc == ARGS_FIVE) {
if (ParseArgGetDestPath(env, asyncContext->argv[PARAM3], asyncContext->destUri) != napi_ok) {
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDestPath error");
return napi_invalid_arg;
}
if (ParseArgGetDataHandler(env, asyncContext->argv[PARAM4], asyncContext->dataHandler,
asyncContext->needsExtraInfo) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetDataHandler error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDataHandler error");
return napi_invalid_arg;
}
}
asyncContext->hasReadPermission = HasReadPermission();
return napi_ok;
}
napi_status MediaAssetManagerNapi::ParseEfficentRequestMediaArgs(napi_env env, napi_callback_info info,
unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
{
napi_value thisVar = nullptr;
GET_JS_ARGS(env, info, asyncContext->argc, asyncContext->argv, thisVar);
if (asyncContext->argc != ARGS_FOUR && asyncContext->argc != ARGS_FIVE) {
NAPI_ERR_LOG("requestMedia argc error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia argc invalid");
return napi_invalid_arg;
}
if (ParseArgGetPhotoAsset(env, asyncContext->argv[PARAM1], asyncContext) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetPhotoAsset error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetPhotoAsset error");
return napi_invalid_arg;
}
if (ParseArgGetRequestOption(env, asyncContext->argv[PARAM2], asyncContext->deliveryMode,
asyncContext->sourceMode) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetRequestOption error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOption error");
return napi_invalid_arg;
}
if (asyncContext->argc == ARGS_FOUR) {
if (ParseArgGetEfficientImageDataHandler(env, asyncContext->argv[PARAM3], asyncContext->dataHandler,
asyncContext->needsExtraInfo) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetEfficientImageDataHandler error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE,
"requestMedia ParseArgGetEfficientImageDataHandler error");
return napi_invalid_arg;
}
} else if (asyncContext->argc == ARGS_FIVE) {
if (ParseArgGetDestPath(env, asyncContext->argv[PARAM3], asyncContext->destUri) != napi_ok) {
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDestPath error");
return napi_invalid_arg;
}
if (ParseArgGetEfficientImageDataHandler(env, asyncContext->argv[PARAM4], asyncContext->dataHandler,
asyncContext->needsExtraInfo) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetEfficientImageDataHandler error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE,
"requestMedia ParseArgGetEfficientImageDataHandler error");
return napi_invalid_arg;
}
}
asyncContext->hasReadPermission = HasReadPermission();
return napi_ok;
}
bool MediaAssetManagerNapi::InitUserFileClient(napi_env env, napi_callback_info info, const int32_t userId)
{
if (UserFileClient::IsValid(userId)) {
return true;
}
std::unique_lock<std::mutex> helperLock(MediaLibraryNapi::sUserFileClientMutex_);
if (!UserFileClient::IsValid(userId)) {
UserFileClient::Init(env, info, userId);
}
helperLock.unlock();
return UserFileClient::IsValid(userId);
}
static int32_t GetPhotoSubtype(napi_env env, napi_value photoAssetArg)
{
if (photoAssetArg == nullptr) {
NAPI_ERR_LOG(
"Dfx adaptation to moving photo collector error: failed to get photo subtype, photo asset is null");
return -1;
}
FileAssetNapi *obj = nullptr;
napi_unwrap(env, photoAssetArg, reinterpret_cast<void**>(&obj));
if (obj == nullptr) {
NAPI_ERR_LOG("Dfx adaptation to moving photo collector error: failed to unwrap file asset");
return -1;
}
return obj->GetFileAssetInstance()->GetPhotoSubType();
}
napi_value MediaAssetManagerNapi::JSRequestImageData(napi_env env, napi_callback_info info)
{
HILOG_COMM_INFO("%{public}s:{%{public}s:%{public}d} Begin JSRequestImageData",
MLOG_TAG, __FUNCTION__, __LINE__);
if (env == nullptr || info == nullptr) {
NAPI_ERR_LOG("JSRequestImageData js arg invalid");
NapiError::ThrowError(env, JS_INNER_FAIL, "JSRequestImageData js arg invalid");
return nullptr;
}
MediaLibraryTracer tracer;
tracer.Start("JSRequestImageData");
unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
asyncContext->returnDataType = ReturnDataType::TYPE_ARRAY_BUFFER;
if (ParseRequestMediaArgs(env, info, asyncContext) != napi_ok) {
NAPI_ERR_LOG("failed to parse requestImagedata args");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse requestImagedata args");
return nullptr;
}
if (!InitUserFileClient(env, info, asyncContext->userId)) {
NAPI_ERR_LOG("JSRequestEfficientIImage init user file client failed");
NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
return nullptr;
}
if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
|| CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
return nullptr;
}
if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
|| CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
return nullptr;
}
asyncContext->requestId = GenerateRequestId();
asyncContext->subType = static_cast<PhotoSubType>(GetPhotoSubtype(env, asyncContext->argv[PARAM1]));
asyncContext->observerType = ObserverType::REQUEST_IMAGE;
return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestImageData", JSRequestExecute,
JSRequestComplete);
}
napi_value MediaAssetManagerNapi::JSRequestImage(napi_env env, napi_callback_info info)
{
HILOG_COMM_INFO("%{public}s:{%{public}s:%{public}d} Begin JSRequestImage",
MLOG_TAG, __FUNCTION__, __LINE__);
if (env == nullptr || info == nullptr) {
NAPI_ERR_LOG("JSRequestImage js arg invalid");
NapiError::ThrowError(env, JS_INNER_FAIL, "JSRequestImage js arg invalid");
return nullptr;
}
MediaLibraryTracer tracer;
tracer.Start("JSRequestImage");
unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
asyncContext->returnDataType = ReturnDataType::TYPE_IMAGE_SOURCE;
if (ParseRequestMediaArgs(env, info, asyncContext) != napi_ok) {
NAPI_ERR_LOG("failed to parse requestImage args");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse requestImage args");
return nullptr;
}
if (!InitUserFileClient(env, info, asyncContext->userId)) {
NAPI_ERR_LOG("JSRequestImage init user file client failed");
NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
return nullptr;
}
if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
|| CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
return nullptr;
}
if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
|| CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
return nullptr;
}
asyncContext->requestId = GenerateRequestId();
asyncContext->subType = static_cast<PhotoSubType>(GetPhotoSubtype(env, asyncContext->argv[PARAM1]));
asyncContext->observerType = ObserverType::REQUEST_IMAGE;
return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestImage", JSRequestExecute,
JSRequestComplete);
}
napi_value MediaAssetManagerNapi::JSRequestEfficientIImage(napi_env env, napi_callback_info info)
{
NAPI_DEBUG_LOG("JSRequestEfficientIImage");
if (env == nullptr || info == nullptr) {
NAPI_ERR_LOG("JSRequestEfficientIImage js arg invalid");
NapiError::ThrowError(env, JS_INNER_FAIL, "JSRequestEfficientIImage js arg invalid");
return nullptr;
}
MediaLibraryTracer tracer;
tracer.Start("JSRequestEfficientIImage");
unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
asyncContext->returnDataType = ReturnDataType::TYPE_PICTURE;
if (ParseEfficentRequestMediaArgs(env, info, asyncContext) != napi_ok) {
NAPI_ERR_LOG("failed to parse JSRequestEfficientIImage args");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse JSRequestEfficientIImage args");
return nullptr;
}
if (!InitUserFileClient(env, info, asyncContext->userId)) {
NAPI_ERR_LOG("JSRequestEfficientIImage init user file client failed");
NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
return nullptr;
}
if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
|| CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
return nullptr;
}
if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
|| CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
return nullptr;
}
asyncContext->requestId = GenerateRequestId();
asyncContext->subType = static_cast<PhotoSubType>(GetPhotoSubtype(env, asyncContext->argv[PARAM1]));
asyncContext->observerType = ObserverType::REQUEST_QUICK_IMAGE;
return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestEfficientIImage", JSRequestExecute,
JSRequestComplete);
}
void MediaAssetManagerNapi::ReleaseSafeFunc(napi_threadsafe_function &threadSafeFunc)
{
if (threadSafeFunc == nullptr) {
return;
}
napi_release_threadsafe_function(threadSafeFunc, napi_tsfn_release);
threadSafeFunc = nullptr;
}
bool MediaAssetManagerNapi::CreateOnProgressHandlerInfo(napi_env env,
unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
{
if (asyncContext->compatibleMode != CompatibleMode::COMPATIBLE_FORMAT_MODE) {
return true;
}
if (asyncContext->mediaAssetProgressHandler == nullptr) {
if (CreateOnProgressThreadSafeFunc(env, asyncContext, asyncContext->onProgressPtr) != napi_ok) {
NAPI_ERR_LOG("CreateOnProgressThreadSafeFunc failed");
return false;
}
return true;
}
if (CreateProgressHandlerRef(env, asyncContext, asyncContext->progressHandlerRef) != napi_ok ||
CreateOnProgressThreadSafeFunc(env, asyncContext, asyncContext->onProgressPtr) != napi_ok) {
NAPI_ERR_LOG("CreateProgressHandlerRef or CreateOnProgressThreadSafeFunc failed");
return false;
}
MEDIA_INFO_LOG("CreateOnProgressHandlerInfo create progress callback success.");
return true;
}
static bool CheckBaseParams(napi_env env, napi_callback_info info, const std::string &funcName)
{
if (env == nullptr || info == nullptr) {
NAPI_ERR_LOG("%{public}s js arg invalid", funcName.c_str());
NapiError::ThrowError(env, JS_INNER_FAIL, "js arg invalid");
return false;
}
return true;
}
bool MediaAssetManagerNapi::ParseAndCheckArgs(napi_env env, napi_callback_info info,
unique_ptr<MediaAssetManagerAsyncContext>& asyncContext)
{
if (ParseRequestMediaArgs(env, info, asyncContext) != napi_ok) {
NAPI_ERR_LOG("failed to parse requestVideo args");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse requestVideo args");
return false;
}
if (!InitUserFileClient(env, info, asyncContext->userId)) {
NAPI_ERR_LOG("JSRequestVideoFile init user file client failed, userId is %{public}d", asyncContext->userId);
NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
return false;
}
if (asyncContext->photoUri.length() > MAX_URI_SIZE || asyncContext->destUri.length() > MAX_URI_SIZE) {
NAPI_ERR_LOG("request video file uri lens out of limit photoUri lens: %{public}zu, destUri lens: %{public}zu",
asyncContext->photoUri.length(), asyncContext->destUri.length());
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "request video file uri lens out of limit");
return false;
}
if (MediaFileUtils::GetMediaType(asyncContext->displayName) != MEDIA_TYPE_VIDEO ||
MediaFileUtils::GetMediaType(MediaFileUtils::GetFileName(asyncContext->destUri)) != MEDIA_TYPE_VIDEO) {
NAPI_ERR_LOG("request video file type invalid");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "request video file type invalid");
return false;
}
return true;
}
bool MediaAssetManagerNapi::CheckDataHandler(napi_env env, unique_ptr<MediaAssetManagerAsyncContext>& asyncContext)
{
if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
|| CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
return false;
}
if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
|| CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
return false;
}
return true;
}
napi_value MediaAssetManagerNapi::JSRequestVideoFile(napi_env env, napi_callback_info info)
{
if (!CheckBaseParams(env, info, "JSRequestVideoFile")) {
return nullptr;
}
MediaLibraryTracer tracer;
tracer.Start("JSRequestVideoFile");
unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
asyncContext->returnDataType = ReturnDataType::TYPE_TARGET_PATH;
if (!ParseAndCheckArgs(env, info, asyncContext)) {
return nullptr;
}
if (!CheckDataHandler(env, asyncContext)) {
return nullptr;
}
if (!CreateOnProgressHandlerInfo(env, asyncContext)) {
NAPI_ERR_LOG("CreateOnProgressHandlerInfo failed");
return nullptr;
}
asyncContext->requestId = GenerateRequestId();
asyncContext->subType = static_cast<PhotoSubType>(GetPhotoSubtype(env, asyncContext->argv[PARAM1]));
asyncContext->observerType = ObserverType::REQUEST_VIDEO;
NAPI_INFO_LOG("JSRequestVideoFile requestId: %{public}s, subtype: %{public}d.",
asyncContext->requestId.c_str(), static_cast<int32_t>(asyncContext->subType));
return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestVideoFile",
JSRequestVideoFileExecute, JSRequestComplete);
}
napi_value MediaAssetManagerNapi::JSRequestVideo(napi_env env, napi_callback_info info)
{
NAPI_INFO_LOG("Beigin JSRequestVideo");
if (!CheckBaseParams(env, info, "JSRequestVideo")) {
return nullptr;
}
MediaLibraryTracer tracer;
tracer.Start("JSRequestVideo");
unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
asyncContext->returnDataType = ReturnDataType::TYPE_READY;
if (ParseRequestVideoArgs(env, info, asyncContext) != napi_ok) {
NAPI_ERR_LOG("failed to parse requestVideo args");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse requestVideo args");
return nullptr;
}
if (!InitUserFileClient(env, info, asyncContext->userId)) {
NAPI_ERR_LOG("JSRequestVideo init user file client failed, userId is %{public}d", asyncContext->userId);
NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
return nullptr;
}
if (asyncContext->photoUri.length() > MAX_URI_SIZE) {
NAPI_ERR_LOG("request video file uri lens out of limit photoUri lens: %{public}zu",
asyncContext->photoUri.length());
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "request video file uri lens out of limit");
return nullptr;
}
if (MediaFileUtils::GetMediaType(asyncContext->displayName) != MEDIA_TYPE_VIDEO) {
NAPI_ERR_LOG("request video file type invalid");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "request video file type invalid");
return nullptr;
}
if (!CheckDataHandler(env, asyncContext)) {
return nullptr;
}
if (!CreateOnProgressHandlerInfoForRequestVideo(env, asyncContext)) {
NAPI_ERR_LOG("CreateOnProgressHandlerInfoForRequestVideo failed");
return nullptr;
}
asyncContext->requestId = GenerateRequestId();
asyncContext->subType = static_cast<PhotoSubType>(GetPhotoSubtype(env, asyncContext->argv[PARAM1]));
asyncContext->observerType = ObserverType::REQUEST_VIDEO;
NAPI_INFO_LOG("JSRequestVideo requestId: %{public}s, subtype: %{public}d.",
asyncContext->requestId.c_str(), static_cast<int32_t>(asyncContext->subType));
return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestVideo",
JSRequestVideoFileExecute, JSRequestComplete);
}
napi_status MediaAssetManagerNapi::ParseRequestVideoArgs(napi_env env, napi_callback_info info,
unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
{
napi_value thisVar = nullptr;
GET_JS_ARGS(env, info, asyncContext->argc, asyncContext->argv, thisVar);
if (asyncContext->argc != ARGS_FOUR) {
NAPI_ERR_LOG("requestMedia argc error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia argc invalid");
return napi_invalid_arg;
}
if (ParseArgGetPhotoAsset(env, asyncContext->argv[PARAM1], asyncContext) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetPhotoAsset error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetPhotoAsset error");
return napi_invalid_arg;
}
if (ParseArgGetRequestOption(env, asyncContext->argv[PARAM2], asyncContext->deliveryMode,
asyncContext->sourceMode) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetRequestOption error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOption error");
return napi_invalid_arg;
}
if (ParseArgGetRequestOptionMore(env, asyncContext->argv[PARAM2], asyncContext->compatibleMode,
asyncContext->mediaAssetProgressHandler) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetRequestOptionMore error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOptionMore error");
return napi_invalid_arg;
}
if (asyncContext->compatibleMode == CompatibleMode::COMPATIBLE_FORMAT_MODE) {
NAPI_ERR_LOG("This compatibleMode is not supported.");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOptionMore error");
return napi_invalid_arg;
}
if (ParseArgGetDataHandler(env, asyncContext->argv[PARAM3], asyncContext->dataHandler,
asyncContext->needsExtraInfo) != napi_ok) {
NAPI_ERR_LOG("requestMedia ParseArgGetDataHandler error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDataHandler error");
return napi_invalid_arg;
}
asyncContext->hasReadPermission = HasReadPermission();
return napi_ok;
}
bool MediaAssetManagerNapi::CreateOnProgressHandlerInfoForRequestVideo(napi_env env,
unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
{
if (asyncContext->mediaAssetProgressHandler == nullptr) {
MEDIA_INFO_LOG("mediaAssetProgressHandler is nullptr, there is no progress callback.");
return true;
}
if (CreateProgressHandlerRef(env, asyncContext, asyncContext->progressHandlerRef) != napi_ok ||
CreateOnProgressThreadSafeFunc(env, asyncContext, asyncContext->onProgressPtr) != napi_ok) {
NAPI_ERR_LOG("CreateProgressHandlerRef or CreateOnProgressThreadSafeFunc failed");
return false;
}
MEDIA_INFO_LOG("ForRequestVideo create progress callback success.");
return true;
}
void MediaAssetManagerNapi::OnHandleRequestImage(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
{
CHECK_NULL_PTR_RETURN_VOID(asyncContext, "asyncContext is nullptr");
HILOG_COMM_INFO("%{public}s:{%{public}s:%{public}d} OnHandleRequestImage mode: %{public}d.",
MLOG_TAG, __FUNCTION__, __LINE__, static_cast<int32_t>(asyncContext->deliveryMode));
QueryPhotoStatusInput param = {
.fileId = asyncContext->fileId,
.mode = asyncContext->deliveryMode,
.photoUri = asyncContext->photoUri,
.hasReadPermission = asyncContext->hasReadPermission,
.needsExtraInfo = (asyncContext->deliveryMode != DeliveryMode::FAST) ? true : asyncContext->needsExtraInfo,
.userId = asyncContext->userId,
};
auto status = MediaAssetManagerAdapter::QueryPhotoStatusWithDfx(param, asyncContext->photoId);
switch (asyncContext->deliveryMode) {
case DeliveryMode::FAST:
if (asyncContext->needsExtraInfo) {
asyncContext->photoQuality = status;
}
MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
ReleaseSafeFunc(asyncContext->onDataPreparedPtr2);
break;
case DeliveryMode::HIGH_QUALITY:
asyncContext->photoQuality = status;
if (status == MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) {
MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
ReleaseSafeFunc(asyncContext->onDataPreparedPtr2);
} else {
RegisterTaskNewObserver(env, asyncContext);
ReleaseSafeFunc(asyncContext->onDataPreparedPtr);
}
break;
case DeliveryMode::BALANCED_MODE:
asyncContext->photoQuality = status;
MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
if (status == MultiStagesCapturePhotoStatus::LOW_QUALITY_STATUS) {
RegisterTaskNewObserver(env, asyncContext);
} else {
ReleaseSafeFunc(asyncContext->onDataPreparedPtr2);
}
break;
default: {
NAPI_ERR_LOG("invalid delivery mode");
return;
}
}
}
static void DfxLogCinematicVideo(bool isHighQaulity, const int32_t &userId)
{
CinematicVideoAccessReqBody reqBody;
reqBody.isHighQaulity = isHighQaulity;
int32_t ret = IPC::UserDefineIPCClient().SetUserId(userId).Call(
static_cast<uint32_t>(MediaLibraryBusinessCode::LOG_CINEMATIC_VIDEO), reqBody);
if (ret != E_OK) {
NAPI_ERR_LOG("cinematic video access log failed, ret: %{public}d", ret);
}
}
void MediaAssetManagerNapi::RequestVidoForFastMode(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
{
CHECK_NULL_PTR_RETURN_VOID(asyncContext, "asyncContext is nullptr");
QueryPhotoStatusInput param = {
.fileId = asyncContext->fileId,
.mode = asyncContext->deliveryMode,
.photoUri = asyncContext->photoUri,
.hasReadPermission = asyncContext->hasReadPermission,
.needsExtraInfo = asyncContext->needsExtraInfo,
.userId = asyncContext->userId,
};
if (asyncContext->needsExtraInfo) {
asyncContext->photoQuality = MediaAssetManagerAdapter::QueryPhotoStatusWithDfx(param, asyncContext->photoId);
}
if (asyncContext->subType == PhotoSubType::CINEMATIC_VIDEO) {
DfxLogCinematicVideo(asyncContext->photoQuality == MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS,
asyncContext->userId);
}
MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
ReleaseSafeFunc(asyncContext->onDataPreparedPtr2);
}
void MediaAssetManagerNapi::RequestVideoForHighQualityMode(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
{
CHECK_NULL_PTR_RETURN_VOID(asyncContext, "asyncContext is nullptr");
QueryPhotoStatusInput param = {
.fileId = asyncContext->fileId,
.mode = asyncContext->deliveryMode,
.photoUri = asyncContext->photoUri,
.hasReadPermission = asyncContext->hasReadPermission,
.needsExtraInfo = true,
.userId = asyncContext->userId,
};
auto status = MediaAssetManagerAdapter::QueryPhotoStatusWithDfx(param, asyncContext->photoId);
asyncContext->photoQuality = status;
if (asyncContext->subType == PhotoSubType::CINEMATIC_VIDEO) {
if (status == MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) {
MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
ReleaseSafeFunc(asyncContext->onDataPreparedPtr2);
} else {
RegisterTaskNewObserver(env, asyncContext);
ReleaseSafeFunc(asyncContext->onDataPreparedPtr);
}
DfxLogCinematicVideo(true, asyncContext->userId);
} else {
MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
ReleaseSafeFunc(asyncContext->onDataPreparedPtr2);
}
}
void MediaAssetManagerNapi::OnHandleRequestVideo(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
{
CHECK_NULL_PTR_RETURN_VOID(asyncContext, "asyncContext is nullptr");
NAPI_INFO_LOG("OnHandleRequestVideo mode: %{public}d.", asyncContext->deliveryMode);
switch (asyncContext->deliveryMode) {
case DeliveryMode::FAST:
case DeliveryMode::BALANCED_MODE:
MediaAssetManagerNapi::RequestVidoForFastMode(env, asyncContext);
break;
case DeliveryMode::HIGH_QUALITY:
MediaAssetManagerNapi::RequestVideoForHighQualityMode(env, asyncContext);
break;
default: {
NAPI_ERR_LOG("invalid delivery mode");
return;
}
}
}
void MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(napi_env env,
MediaAssetManagerAsyncContext *asyncContext)
{
AssetHandler *assetHandler = InsertDataHandler(NotifyMode::FAST_NOTIFY, env, asyncContext);
if (assetHandler == nullptr) {
NAPI_ERR_LOG("assetHandler is nullptr");
return;
}
asyncContext->assetHandler = assetHandler;
}
void MediaAssetManagerNapi::OnHandleProgress(napi_env env, MediaAssetManagerAsyncContext *asyncContext,
ProgressMode progressMode, CameraProgressMode cameraProgressMode)
{
CHECK_NULL_PTR_RETURN_VOID(asyncContext, "asyncContext is nullptr");
MEDIA_INFO_LOG("OnHandleProgress, progressMode: %{public}d, cameraProgressMode: %{public}d.",
static_cast<int32_t>(progressMode), static_cast<int32_t>(cameraProgressMode));
ProgressHandler *progressHandler = InsertProgressHandler(env, asyncContext, progressMode, cameraProgressMode);
if (progressHandler == nullptr) {
NAPI_ERR_LOG("progressHandler is nullptr");
return;
}
asyncContext->progressHandler = progressHandler;
}
static string PhotoQualityToString(MultiStagesCapturePhotoStatus photoQuality)
{
static const string HIGH_QUALITY_STRING = "high";
static const string LOW_QUALITY_STRING = "low";
if (photoQuality != MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS &&
photoQuality != MultiStagesCapturePhotoStatus::LOW_QUALITY_STATUS) {
NAPI_ERR_LOG("Invalid photo quality: %{public}d", static_cast<int>(photoQuality));
return HIGH_QUALITY_STRING;
}
return (photoQuality == MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) ? HIGH_QUALITY_STRING :
LOW_QUALITY_STRING;
}
static napi_value GetInfoMapNapiValue(napi_env env, AssetHandler* assetHandler)
{
napi_status status;
napi_value mapNapiValue {nullptr};
status = napi_create_map(env, &mapNapiValue);
CHECK_COND_RET(status == napi_ok && mapNapiValue != nullptr, nullptr,
"Failed to create map napi value, napi status: %{public}d", static_cast<int>(status));
napi_value qualityInfo {nullptr};
status = napi_create_string_utf8(env, PhotoQualityToString(assetHandler->photoQuality).c_str(),
NAPI_AUTO_LENGTH, &qualityInfo);
CHECK_COND_RET(status == napi_ok && qualityInfo != nullptr, nullptr,
"Failed to create quality string, napi status: %{public}d", static_cast<int>(status));
status = napi_set_named_property(env, mapNapiValue, "quality", qualityInfo);
CHECK_COND_RET(status == napi_ok, nullptr, "Failed to set quality property, napi status: %{public}d",
static_cast<int>(status));
status = napi_map_set_named_property(env, mapNapiValue, "quality", qualityInfo);
CHECK_COND_RET(status == napi_ok, nullptr, "Failed to set quality map key-value, napi status: %{public}d",
static_cast<int>(status));
return mapNapiValue;
}
static napi_value GetNapiValueOfMedia(napi_env env, AssetHandler *assetHandler)
{
NAPI_DEBUG_LOG("GetNapiValueOfMedia");
if (assetHandler == nullptr) {
NAPI_ERR_LOG("assetHandler is nullptr");
return nullptr;
}
auto dataHandler = assetHandler->dataHandler;
if (dataHandler == nullptr) {
NAPI_ERR_LOG("dataHandler is nullptr");
DeleteAssetHandlerSafe(assetHandler, env);
return nullptr;
}
napi_value napiValueOfMedia = nullptr;
if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_ARRAY_BUFFER) {
MediaAssetManagerNapi::GetByteArrayNapiObject(dataHandler->GetRequestUri(), napiValueOfMedia,
dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE, env);
} else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_IMAGE_SOURCE) {
MediaAssetManagerNapi::GetImageSourceNapiObject(dataHandler->GetRequestUri(), napiValueOfMedia,
dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE, env);
} else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_TARGET_PATH) {
WriteData param;
param.compatibleMode = dataHandler->GetCompatibleMode();
param.destUri = dataHandler->GetDestUri();
param.requestUri = dataHandler->GetRequestUri();
param.env = env;
param.isSource = dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE;
MediaAssetManagerNapi::WriteDataToDestPath(param, napiValueOfMedia, dataHandler->GetRequestId());
} else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_MOVING_PHOTO) {
MovingPhotoParam movingPhotoParam;
movingPhotoParam.compatibleMode = dataHandler->GetCompatibleMode();
movingPhotoParam.requestId = dataHandler->GetRequestId();
movingPhotoParam.progressHandlerRef = dataHandler->GetProgressHandlerRef();
movingPhotoParam.threadsafeFunction = dataHandler->GetThreadsafeFunction();
napiValueOfMedia = MovingPhotoNapi::NewMovingPhotoNapi(env, dataHandler->GetRequestUri(),
dataHandler->GetSourceMode(), movingPhotoParam);
} else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_PICTURE) {
MediaAssetManagerNapi::GetPictureNapiObject(dataHandler->GetRequestUri(), napiValueOfMedia,
dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE, env, assetHandler->isPicture,
assetHandler->photoQuality);
} else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_READY) {
napi_get_boolean(env, dataHandler->GetCinematicResult(), &napiValueOfMedia);
} else {
NAPI_ERR_LOG("source mode type invalid");
}
return napiValueOfMedia;
}
void MediaAssetManagerNapi::SetCinematicResult(const std::shared_ptr<NapiMediaAssetDataHandler>& dataHandler,
AssetHandler *assetHandler)
{
if (dataHandler->GetReturnDataType() != ReturnDataType::TYPE_READY) {
return;
}
dataHandler->SetCinematicResult(!assetHandler->isCinematicVideoError);
NAPI_INFO_LOG("isCinematicVideoError: %{public}d, CinematicResult: %{public}d",
assetHandler->isCinematicVideoError, dataHandler->GetCinematicResult());
}
bool IsSaveCallbackInfoByTranscoder(napi_value napiValueOfMedia, napi_env env, AssetHandler *assetHandler,
napi_value napiValueOfInfoMap)
{
auto dataHandler = assetHandler->dataHandler;
if (dataHandler == nullptr) {
NAPI_ERR_LOG("data handler is nullptr");
return false;
}
if (napiValueOfMedia == nullptr) {
napi_get_undefined(env, &napiValueOfMedia);
}
bool isTranscoder;
if (!isTranscoderMap_.Find(assetHandler->requestId, isTranscoder)) {
NAPI_DEBUG_LOG("not find key from map");
isTranscoder = false;
}
NAPI_INFO_LOG("IsSaveCallbackInfoByTranscoder isTranscoder_ %{public}d", isTranscoder);
if (isTranscoder) {
onPreparedResult_.EnsureInsert(assetHandler->requestId, assetHandler);
onPreparedResultValue_.EnsureInsert(assetHandler->requestId, napiValueOfMedia);
return true;
}
dataHandler->JsOnDataPrepared(env, napiValueOfMedia, napiValueOfInfoMap);
return false;
}
void MediaAssetManagerNapi::OnDataPrepared(napi_env env, napi_value cb, void *context, void *data)
{
NAPI_INFO_LOG("Begin OnDataPrepared.");
AssetHandler *assetHandler = reinterpret_cast<AssetHandler *>(data);
CHECK_NULL_PTR_RETURN_VOID(assetHandler, "assetHandler is nullptr");
auto dataHandler = assetHandler->dataHandler;
if (dataHandler == nullptr) {
NAPI_ERR_LOG("data handler is nullptr");
DeleteAssetHandlerSafe(assetHandler, env);
return;
}
NotifyMode notifyMode = dataHandler->GetNotifyMode();
if (notifyMode == NotifyMode::FAST_NOTIFY) {
AssetHandler *tmp;
if (!inProcessFastRequests.Find(assetHandler->requestId, tmp)) {
NAPI_ERR_LOG("The request has been canceled");
DeleteAssetHandlerSafe(assetHandler, env);
return;
}
}
SetCinematicResult(dataHandler, assetHandler);
napi_value napiValueOfMedia = assetHandler->isError ? nullptr : GetNapiValueOfMedia(env, assetHandler);
napi_value napiValueOfInfoMap = nullptr;
if (assetHandler->needsExtraInfo) {
napiValueOfInfoMap = GetInfoMapNapiValue(env, assetHandler);
if (napiValueOfInfoMap == nullptr) {
NAPI_ERR_LOG("Failed to get info map");
napi_get_undefined(env, &napiValueOfInfoMap);
}
}
if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_PICTURE) {
if (assetHandler->isPicture) {
dataHandler->JsOnDataPrepared(env, napiValueOfMedia, nullptr, napiValueOfInfoMap);
} else {
if (napiValueOfMedia == nullptr) {
napi_get_undefined(env, &napiValueOfMedia);
}
dataHandler->JsOnDataPrepared(env, nullptr, napiValueOfMedia, napiValueOfInfoMap);
}
} else {
if (IsSaveCallbackInfoByTranscoder(napiValueOfMedia, env, assetHandler, napiValueOfInfoMap)) {
return;
}
}
DeleteDataHandler(notifyMode, assetHandler->requestUri, assetHandler->requestId);
NAPI_DEBUG_LOG("delete assetHandler");
DeleteAssetHandlerSafe(assetHandler, env);
}
void CallPreparedCallbackAfterProgress(napi_env env, ProgressHandler *progressHandler, napi_value napiValueOfMedia)
{
MediaCallTranscode::CallTranscodeRelease(progressHandler->requestId);
MediaAssetManagerNapi::progressHandlerMap_.Erase(progressHandler->requestId);
AssetHandler *assetHandler = nullptr;
if (!onPreparedResult_.Find(progressHandler->requestId, assetHandler)) {
NAPI_ERR_LOG("not find key from map");
return;
}
onPreparedResult_.Erase(progressHandler->requestId);
auto dataHandler = assetHandler->dataHandler;
if (dataHandler == nullptr) {
NAPI_ERR_LOG("data handler is nullptr");
DeleteAssetHandlerSafe(assetHandler, env);
return;
}
NotifyMode notifyMode = dataHandler->GetNotifyMode();
napi_value napiValueOfInfoMap = nullptr;
if (assetHandler->needsExtraInfo) {
napiValueOfInfoMap = GetInfoMapNapiValue(env, assetHandler);
if (napiValueOfInfoMap == nullptr) {
NAPI_ERR_LOG("Failed to get info map");
napi_get_undefined(env, &napiValueOfInfoMap);
}
}
dataHandler->JsOnDataPrepared(env, napiValueOfMedia, napiValueOfInfoMap);
NAPI_INFO_LOG("delete assetHandler");
DeleteProcessHandlerSafe(progressHandler, env);
DeleteDataHandler(notifyMode, assetHandler->requestUri, assetHandler->requestId);
DeleteAssetHandlerSafe(assetHandler, env);
}
void CallProgressCallback(napi_env env, ProgressHandler* progressHandler, int32_t process)
{
if (progressHandler == nullptr) {
NAPI_ERR_LOG("progressHandler is nullptr");
return;
}
napi_value result;
napi_status status = napi_create_int32(env, process, &result);
if (status != napi_ok) {
NAPI_ERR_LOG("OnProgress napi_create_int32 fail");
}
napi_value callback;
if (process < 0 || process > PROGRESS_MAX || progressHandler->progressRef == nullptr) {
NAPI_ERR_LOG("progressHandler->progressRef is nullptr or process out of range");
return;
}
status = napi_get_reference_value(env, progressHandler->progressRef, &callback);
if (status != napi_ok) {
NAPI_ERR_LOG("OnProgress napi_get_reference_value fail, napi status: %{public}d",
static_cast<int>(status));
DeleteProcessHandlerSafe(progressHandler, env);
return;
}
napi_value jsOnProgress;
status = napi_get_named_property(env, callback, ON_PROGRESS_FUNC, &jsOnProgress);
if (status != napi_ok) {
NAPI_ERR_LOG("jsOnProgress napi_get_named_property fail, napi status: %{public}d",
static_cast<int>(status));
DeleteProcessHandlerSafe(progressHandler, env);
return;
}
constexpr size_t maxArgs = 1;
napi_value argv[maxArgs];
size_t argc = ARGS_ONE;
argv[PARAM0] = result;
argc = ARGS_ONE;
napi_value promise;
status = napi_call_function(env, nullptr, jsOnProgress, argc, argv, &promise);
if (status != napi_ok) {
NAPI_ERR_LOG("call js function failed %{public}d", static_cast<int32_t>(status));
NapiError::ThrowError(env, JS_INNER_FAIL, "calling onDataPrepared failed");
}
NAPI_INFO_LOG("CallProgressCallback process %{public}d", process);
}
void MediaAssetManagerNapi::OnProgress(napi_env env, napi_value cb, void *context, void *data)
{
ProgressHandler *progressHandler = reinterpret_cast<ProgressHandler *>(data);
if (progressHandler == nullptr) {
NAPI_ERR_LOG("progressHandler handler is nullptr");
DeleteProcessHandlerSafe(progressHandler, env);
return;
}
double process = progressHandler->outputResult;
int32_t type = progressHandler->retProgressValue.type;
MEDIA_INFO_LOG("OnProgress begin, type: %{public}d, requestId: %{public}s.",
type, progressHandler->requestId.c_str());
if (type == INFO_TYPE_TRANSCODER_COMPLETED || type == INFO_TYPE_ERROR) {
bool isTranscoder;
if (isTranscoderMap_.Find(progressHandler->requestId, isTranscoder)) {
isTranscoderMap_.Erase(progressHandler->requestId);
}
napi_value napiValueOfMedia;
if (onPreparedResultValue_.Find(progressHandler->requestId, napiValueOfMedia)) {
onPreparedResultValue_.Erase(progressHandler->requestId);
}
if (type == INFO_TYPE_ERROR) {
napi_get_boolean(env, false, &napiValueOfMedia);
}
NAPI_INFO_LOG("CallPreparedCallbackAfterProgress type %{public}d, requestId: %{public}s.",
type, progressHandler->requestId.c_str());
CallPreparedCallbackAfterProgress(env, progressHandler, napiValueOfMedia);
return;
}
if (progressHandler->progressRef == nullptr) {
NAPI_INFO_LOG("progressHandler->progressRef == nullptr");
return;
}
CallProgressCallback(env, progressHandler, process);
}
void MediaAssetManagerNapi::NotifyMediaDataPrepared(AssetHandler *assetHandler)
{
napi_status status = napi_call_threadsafe_function(assetHandler->threadSafeFunc, (void *)assetHandler,
napi_tsfn_blocking);
if (status != napi_ok) {
NAPI_ERR_LOG("napi_call_threadsafe_function fail, %{public}d", static_cast<int32_t>(status));
napi_release_threadsafe_function(assetHandler->threadSafeFunc, napi_tsfn_release);
DeleteAssetHandlerSafe(assetHandler, nullptr);
}
}
std::shared_ptr<MultistagesCaptureNotifyServerInfo> MultistagesCaptureOnProcessObserver::ConvertWrapperToNotifyInfo(
const UserDefineCallbackWrapper &wrapper)
{
if (wrapper.userDefineInfo_ == nullptr ||
wrapper.userDefineInfo_->notifyUserDefineType_ != NotifyForUserDefineType::MULTISTAGES_CAPTURE) {
NAPI_WARN_LOG("Wrapper is invalid.");
return nullptr;
}
auto notifyBody = wrapper.userDefineInfo_->GetUserDefineNotifyBody();
if (notifyBody == nullptr) {
NAPI_ERR_LOG("NotifyBody is nullptr.");
return nullptr;
}
auto notifyInfo = static_pointer_cast<MultistagesCaptureNotifyServerInfo>(notifyBody);
if (notifyInfo == nullptr) {
NAPI_ERR_LOG("NotifyInfo is nullptr.");
return nullptr;
}
int32_t notifyType = static_cast<int32_t>(notifyInfo->notifyType_);
if (notifyType <= static_cast<int32_t>(MultistagesCaptureNotifyType::UNDEFINED) ||
notifyType >= static_cast<int32_t>(MultistagesCaptureNotifyType::NOTIFY_END)) {
NAPI_ERR_LOG("NotifyType is invalid.");
return nullptr;
}
return notifyInfo;
}
bool MultistagesCaptureOnProcessObserver::MatchNotifyToObserver(
const MultistagesCaptureNotifyType ¬ifyType, const ObserverType &observerType)
{
if (MATCH_NOTIFY_TO_OBSERVER.find(notifyType) == MATCH_NOTIFY_TO_OBSERVER.end()) {
NAPI_ERR_LOG("NotifyType is invalid.");
return false;
}
std::vector<ObserverType> observers = MATCH_NOTIFY_TO_OBSERVER.at(notifyType);
for (const auto observer : observers) {
if (observer == observerType) {
NAPI_INFO_LOG("Need notify.");
return true;
}
}
return false;
}
void MultistagesCaptureOnProcessObserver::OnChange(const UserDefineCallbackWrapper &wrapper)
{
NAPI_INFO_LOG("MultistagesCapture, OnChange called, %{public}s.", ToString().c_str());
std::shared_ptr<MultistagesCaptureNotifyServerInfo> notifyInfo = ConvertWrapperToNotifyInfo(wrapper);
if (notifyInfo == nullptr) {
return;
}
std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
if (inProcessUriMap.find(notifyInfo->uri_) == inProcessUriMap.end()) {
NAPI_ERR_LOG("Current uri does not in process, uri: %{public}s", uri_.c_str());
return;
}
std::map<std::string, AssetHandler *> assetHandlers = inProcessUriMap[notifyInfo->uri_];
for (auto handler : assetHandlers) {
auto assetHandler = handler.second;
auto requestUri = assetHandler->requestUri;
auto requestId = assetHandler->requestId;
if (!MatchNotifyToObserver(notifyInfo->notifyType_, assetHandler->observerType)) {
continue;
}
assetHandler->photoQuality = MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
if (notifyInfo->notifyType_ == MultistagesCaptureNotifyType::ON_ERROR_IMAGE ||
notifyInfo->notifyType_ == MultistagesCaptureNotifyType::ON_ERROR_VIDEO) {
NAPI_WARN_LOG("OnChange receive high_temperature");
assetHandler->isError = true;
}
MediaAssetManagerNapi::NotifyMediaDataPrepared(assetHandler);
DeleteRecordNoLock(requestUri, requestId);
}
}
bool OnHandleProgressOutputResult(int32_t type, int32_t progress, ProgressHandler *progressHandler)
{
if (progressHandler == nullptr) {
MEDIA_ERR_LOG("ProgressHandler is nullptr.");
return false;
}
MEDIA_INFO_LOG("OnHandleProgressOutputResult type: %{public}d, progress: %{public}d.", type, progress);
progressHandler->retProgressValue.type = type;
if (type == static_cast<int32_t>(ProgressReturnInfoType::CAMERA_PROGRESS)) {
if (progressHandler->progressMode == ProgressMode::ONLY_FOR_CAMERA) {
progressHandler->cameraProgress = progress;
progressHandler->outputResult = progress;
} else if (progressHandler->progressMode == ProgressMode::CAMERA_AND_TRANSCODING) {
progressHandler->cameraProgress = progress;
progressHandler->outputResult =
(progressHandler->retProgressValue.progress + progressHandler->cameraProgress) / AVERAGE_FACTOR;
} else {
MEDIA_ERR_LOG("Failed to OnHandleProgressOutputResult, type: %{public}d.", type);
return false;
}
} else {
if (progressHandler->progressMode == ProgressMode::ONLY_FOR_TRANSCODING) {
progressHandler->retProgressValue.progress = progress;
progressHandler->outputResult = progress;
} else if (progressHandler->progressMode == ProgressMode::CAMERA_AND_TRANSCODING) {
progressHandler->retProgressValue.progress = progress;
progressHandler->outputResult =
(progressHandler->retProgressValue.progress + progressHandler->cameraProgress) / AVERAGE_FACTOR;
} else {
MEDIA_ERR_LOG("Failed to OnHandleProgressOutputResult, type: %{public}d.", type);
return false;
}
}
return true;
}
void MediaAssetManagerNapi::NotifyOnProgress(int32_t type, int32_t progress, std::string requestId)
{
NAPI_DEBUG_LOG("NotifyOnProgress start %{public}d, type:%{public}d, requestId:%{public}s", progress, type,
requestId.c_str());
ProgressHandler *progressHandler = nullptr;
if (!MediaAssetManagerNapi::progressHandlerMap_.Find(requestId, progressHandler)) {
NAPI_ERR_LOG("not find key from map");
return;
}
if (progressHandler == nullptr) {
NAPI_ERR_LOG("ProgressHandler is nullptr.");
return;
}
if (!OnHandleProgressOutputResult(type, progress, progressHandler)) {
return;
}
napi_status status = napi_acquire_threadsafe_function(progressHandler->progressFunc);
if (status != napi_ok) {
NAPI_ERR_LOG("napi_acquire_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
return;
}
status = napi_call_threadsafe_function(progressHandler->progressFunc, (void *)progressHandler, napi_tsfn_blocking);
if (status != napi_ok) {
NAPI_ERR_LOG("napi_call_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
DeleteProcessHandlerSafe(progressHandler, progressHandler->env);
return;
}
}
void MediaAssetManagerNapi::GetImageSourceNapiObject(const std::string &fileUri, napi_value &imageSourceNapiObj,
bool isSource, napi_env env)
{
if (env == nullptr) {
NAPI_ERR_LOG(" create image source object failed, need to initialize js env");
return;
}
napi_value tempImageSourceNapi;
ImageSourceNapi::CreateImageSourceNapi(env, &tempImageSourceNapi);
ImageSourceNapi* imageSourceNapi = nullptr;
napi_unwrap(env, tempImageSourceNapi, reinterpret_cast<void**>(&imageSourceNapi));
if (imageSourceNapi == nullptr) {
NAPI_ERR_LOG("unwrap image napi object failed");
return;
}
std::string tmpUri = fileUri;
if (isSource) {
MediaFileUtils::UriAppendKeyValue(tmpUri, CONST_MEDIA_OPERN_KEYWORD, CONST_SOURCE_REQUEST);
NAPI_INFO_LOG("request source image's imageSource");
}
MediaFileUtils::UriAppendKeyValue(tmpUri, CONST_PHOTO_TRANSCODE_OPERATION, CONST_OPRN_TRANSCODE_HEIF);
Uri uri(tmpUri);
int fd = UserFileClient::OpenFile(uri, "r");
if (fd < 0) {
NAPI_ERR_LOG("get image fd failed, errno: %{public}d", errno);
return;
}
SourceOptions opts;
uint32_t errCode = 0;
auto nativeImageSourcePtr = ImageSource::CreateImageSource(fd, opts, errCode);
close(fd);
if (nativeImageSourcePtr == nullptr) {
NAPI_ERR_LOG("get ImageSource::CreateImageSource failed nullptr, errCode:%{public}d", errCode);
return;
}
imageSourceNapi->SetNativeImageSource(std::move(nativeImageSourcePtr));
imageSourceNapiObj = tempImageSourceNapi;
}
void MediaAssetManagerNapi::GetPictureNapiObject(const std::string &fileUri, napi_value &pictureNapiObj,
bool isSource, napi_env env, bool& isPicture, MultiStagesCapturePhotoStatus &photoQuality)
{
if (env == nullptr) {
NAPI_ERR_LOG(" create image source object failed, need to initialize js env");
return;
}
NAPI_DEBUG_LOG("GetPictureNapiObject");
std::string tempStr = fileUri.substr(PhotoColumn::PHOTO_URI_PREFIX.length());
std::size_t index = tempStr.find("/");
std::string fileId = tempStr.substr(0, index);
bool isHighQuality = false;
auto pic = PictureHandlerClient::RequestPicture(std::atoi(fileId.c_str()), isHighQuality);
if (pic == nullptr) {
NAPI_ERR_LOG("picture is null");
isPicture = false;
GetImageSourceNapiObject(fileUri, pictureNapiObj, isSource, env);
return;
}
isPicture = true;
NAPI_ERR_LOG("picture is not null");
photoQuality = isHighQuality ? MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS
: MultiStagesCapturePhotoStatus::LOW_QUALITY_STATUS;
napi_value tempPictureNapi;
PictureNapi::CreatePictureNapi(env, &tempPictureNapi);
PictureNapi* pictureNapi = nullptr;
napi_unwrap(env, tempPictureNapi, reinterpret_cast<void**>(&pictureNapi));
if (pictureNapi == nullptr) {
NAPI_ERR_LOG("GetPictureNapiObject unwrap image napi object failed");
return;
}
pictureNapi->SetNativePicture(pic);
pictureNapiObj = tempPictureNapi;
}
void MediaAssetManagerNapi::GetByteArrayNapiObject(const std::string &requestUri, napi_value &arrayBuffer,
bool isSource, napi_env env)
{
if (env == nullptr) {
NAPI_ERR_LOG("create byte array object failed, need to initialize js env");
return;
}
std::string tmpUri = requestUri;
if (isSource) {
MediaFileUtils::UriAppendKeyValue(tmpUri, CONST_MEDIA_OPERN_KEYWORD, CONST_SOURCE_REQUEST);
}
Uri uri(tmpUri);
int imageFd = UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
if (imageFd < 0) {
NAPI_ERR_LOG("get image fd failed, %{public}d", errno);
return;
}
ssize_t imgLen = lseek(imageFd, 0, SEEK_END);
void* buffer = nullptr;
if (napi_create_arraybuffer(env, imgLen, &buffer, &arrayBuffer) != napi_ok) {
NAPI_ERR_LOG("create napi arraybuffer failed");
close(imageFd);
return;
}
lseek(imageFd, 0, SEEK_SET);
ssize_t readRet = read(imageFd, buffer, imgLen);
close(imageFd);
if (readRet != imgLen) {
NAPI_ERR_LOG("read image failed");
return;
}
}
bool IsMovingPhoto(int32_t photoSubType, int32_t effectMode, int32_t sourceMode)
{
return photoSubType == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO) ||
(MediaLibraryNapiUtils::IsSystemApp() && sourceMode == static_cast<int32_t>(SourceMode::ORIGINAL_MODE) &&
effectMode == static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY));
}
static napi_value ParseArgsForRequestMovingPhoto(napi_env env, size_t argc, const napi_value argv[],
unique_ptr<MediaAssetManagerAsyncContext> &context)
{
CHECK_COND_WITH_MESSAGE(env, (argc == ARGS_FOUR), "Invalid number of arguments");
FileAssetNapi *fileAssetNapi = nullptr;
CHECK_COND_WITH_MESSAGE(env,
(napi_unwrap(env, argv[PARAM1], reinterpret_cast<void**>(&fileAssetNapi)) == napi_ok),
"Failed to parse photo asset");
CHECK_COND_WITH_MESSAGE(env, fileAssetNapi != nullptr, "Failed to parse photo asset");
auto fileAssetPtr = fileAssetNapi->GetFileAssetInstance();
CHECK_COND_WITH_MESSAGE(env, fileAssetPtr != nullptr, "fileAsset is null");
context->photoUri = fileAssetPtr->GetUri();
context->fileId = fileAssetPtr->GetId();
context->returnDataType = ReturnDataType::TYPE_MOVING_PHOTO;
context->hasReadPermission = HasReadPermission();
context->subType = PhotoSubType::MOVING_PHOTO;
context->userId = fileAssetPtr->GetUserId();
CHECK_COND_WITH_MESSAGE(env,
ParseArgGetRequestOption(env, argv[PARAM2], context->deliveryMode, context->sourceMode) == napi_ok,
"Failed to parse request option");
CHECK_COND_WITH_MESSAGE(env,
ParseArgGetRequestOptionMore(env, argv[PARAM2], context->compatibleMode,
context->mediaAssetProgressHandler) == napi_ok, "Failed to parse request option more");
CHECK_COND_WITH_MESSAGE(env, IsMovingPhoto(fileAssetPtr->GetPhotoSubType(),
fileAssetPtr->GetMovingPhotoEffectMode(), static_cast<int32_t>(context->sourceMode)),
"Asset is not a moving photo");
if (fileAssetPtr->GetUserId() != -1) {
MediaFileUtils::UriAppendKeyValue(context->photoUri, "user", to_string(fileAssetPtr->GetUserId()));
}
if (ParseArgGetDataHandler(env, argv[PARAM3], context->dataHandler, context->needsExtraInfo) != napi_ok) {
NAPI_ERR_LOG("requestMovingPhoto ParseArgGetDataHandler error");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMovingPhoto ParseArgGetDataHandler error");
return nullptr;
}
RETURN_NAPI_TRUE(env);
}
napi_status MediaAssetManagerNapi::CreateMovingPhotoThreadSafeFunc(napi_env env,
unique_ptr<MediaAssetManagerAsyncContext> &context, napi_threadsafe_function &progressFunc)
{
if (env == nullptr || context == nullptr) {
NAPI_ERR_LOG("env or context is nullptr");
return napi_invalid_arg;
}
napi_value workName = nullptr;
napi_create_string_utf8(env, "ProgressThread", NAPI_AUTO_LENGTH, &workName);
napi_status status = napi_ok;
status = napi_create_threadsafe_function(env, context->mediaAssetProgressHandler, NULL, workName, 0, 1,
NULL, NULL, NULL, MovingPhotoCallTranscoder::OnProgress, &progressFunc);
if (status != napi_ok) {
NAPI_ERR_LOG("napi_create_threadsafe_function fail");
progressFunc = nullptr;
NapiError::ThrowError(env, JS_INNER_FAIL, "napi_create_threadsafe_function fail");
}
return status;
}
bool MediaAssetManagerNapi::CreateMovingPhotoHandlerInfo(napi_env env,
unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
{
if (env == nullptr || asyncContext == nullptr) {
NAPI_ERR_LOG("env or asyncContext is nullptr");
return false;
}
if (asyncContext->compatibleMode != CompatibleMode::COMPATIBLE_FORMAT_MODE) {
return true;
}
if (asyncContext->mediaAssetProgressHandler == nullptr) {
if (CreateMovingPhotoThreadSafeFunc(env, asyncContext, asyncContext->onProgressPtr) != napi_ok) {
NAPI_ERR_LOG("CreateMovingPhotoThreadSafeFunc failed");
return false;
}
return true;
}
if (CreateProgressHandlerRef(env, asyncContext, asyncContext->progressHandlerRef) != napi_ok ||
CreateMovingPhotoThreadSafeFunc(env, asyncContext, asyncContext->onProgressPtr) != napi_ok) {
NAPI_ERR_LOG("CreateProgressHandlerRef or CreateMovingPhotoThreadSafeFunc failed");
return false;
}
return true;
}
napi_value MediaAssetManagerNapi::JSRequestMovingPhoto(napi_env env, napi_callback_info info)
{
MediaLibraryTracer tracer;
tracer.Start("JSRequestMovingPhoto");
unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
CHECK_ARGS(env, napi_get_cb_info(env, info, &(asyncContext->argc), asyncContext->argv, nullptr, nullptr),
JS_INNER_FAIL);
CHECK_NULLPTR_RET(ParseArgsForRequestMovingPhoto(env, asyncContext->argc, asyncContext->argv, asyncContext));
CHECK_COND(env, InitUserFileClient(env, info, asyncContext->userId), JS_INNER_FAIL);
if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
|| CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
return nullptr;
}
if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
|| CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
return nullptr;
}
if (!CreateMovingPhotoHandlerInfo(env, asyncContext)) {
NAPI_ERR_LOG("CreateMovingPhotoHandlerInfo failed");
return nullptr;
}
asyncContext->requestId = GenerateRequestId();
asyncContext->observerType = ObserverType::REQUEST_IMAGE;
return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestMovingPhoto", JSRequestExecute,
JSRequestComplete);
}
void MediaAssetManagerNapi::WriteDataToDestPath(WriteData &writeData, napi_value &resultNapiValue,
std::string requestId)
{
if (writeData.env == nullptr) {
NAPI_ERR_LOG("create byte array object failed, need to initialize js env");
return;
}
if (writeData.requestUri.empty() || writeData.destUri.empty()) {
napi_get_boolean(writeData.env, false, &resultNapiValue);
NAPI_ERR_LOG("requestUri or responseUri is nullptr");
return;
}
std::string tmpUri = writeData.requestUri;
if (writeData.isSource) {
MediaFileUtils::UriAppendKeyValue(tmpUri, CONST_MEDIA_OPERN_KEYWORD, CONST_SOURCE_REQUEST);
}
Uri srcUri(tmpUri);
int srcFd = UserFileClient::OpenFile(srcUri, MEDIA_FILEMODE_READONLY);
if (srcFd < 0) {
napi_get_boolean(writeData.env, false, &resultNapiValue);
NAPI_ERR_LOG("get source file fd failed %{public}d", srcFd);
return;
}
UniqueFd uniqueSrcFd(srcFd);
struct stat statSrc;
if (fstat(uniqueSrcFd.Get(), &statSrc) == -1) {
napi_get_boolean(writeData.env, false, &resultNapiValue);
NAPI_DEBUG_LOG("File get stat failed, %{public}d", errno);
return;
}
int destFd = GetFdFromSandBoxUri(writeData.destUri);
if (destFd < 0) {
napi_get_boolean(writeData.env, false, &resultNapiValue);
NAPI_ERR_LOG("get dest fd failed %{public}d", destFd);
return;
}
UniqueFd uniqueDestFd(destFd);
NAPI_INFO_LOG("WriteDataToDestPath compatibleMode %{public}d", writeData.compatibleMode);
if (writeData.compatibleMode == CompatibleMode::COMPATIBLE_FORMAT_MODE) {
isTranscoderMap_.Insert(requestId, true);
MediaCallTranscode::RegisterCallback(NotifyOnProgress);
MediaCallTranscode::CallTranscodeHandle(writeData.env, uniqueSrcFd, uniqueDestFd, resultNapiValue,
statSrc.st_size, requestId);
} else {
SendFile(writeData.env, uniqueSrcFd.Get(), uniqueDestFd.Get(), resultNapiValue, statSrc.st_size);
}
return;
}
void MediaAssetManagerNapi::SendFile(napi_env env, int srcFd, int destFd, napi_value &result, off_t fileSize)
{
if (srcFd < 0 || destFd < 0) {
NAPI_ERR_LOG("srcFd or destFd is invalid");
napi_get_boolean(env, false, &result);
return;
}
if (sendfile(destFd, srcFd, nullptr, fileSize) == -1) {
close(srcFd);
close(destFd);
napi_get_boolean(env, false, &result);
NAPI_ERR_LOG("send file failed, %{public}d", errno);
return;
}
napi_get_boolean(env, true, &result);
}
static bool IsFastRequestCanceled(const std::string &requestId, std::string &photoId)
{
AssetHandler *assetHandler = nullptr;
if (!inProcessFastRequests.Find(requestId, assetHandler)) {
NAPI_ERR_LOG("requestId(%{public}s) not in progress.", requestId.c_str());
return false;
}
if (assetHandler == nullptr) {
NAPI_ERR_LOG("assetHandler is nullptr.");
return false;
}
photoId = assetHandler->photoId;
inProcessFastRequests.Erase(requestId);
return true;
}
static bool IsMapRecordCanceled(const std::string &requestId, std::string &photoId,
std::string &requestUri, napi_env env)
{
AssetHandler *assetHandler = nullptr;
std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
if (!IsInProcessInMapRecord(requestId, assetHandler)) {
NAPI_ERR_LOG("requestId(%{public}s) not in progress.", requestId.c_str());
return false;
}
if (assetHandler == nullptr) {
NAPI_ERR_LOG("assetHandler is nullptr.");
return false;
}
photoId = assetHandler->photoId;
requestUri = assetHandler->requestUri;
DeleteInProcessMapRecord(assetHandler->requestUri, assetHandler->requestId);
DeleteAssetHandlerSafe(assetHandler, env);
return true;
}
void MediaAssetManagerNapi::DeleteProgressHandler(const std::string &requestId)
{
ProgressHandler *progressHandler = nullptr;
if (MediaAssetManagerNapi::progressHandlerMap_.Find(requestId, progressHandler)) {
MediaAssetManagerNapi::progressHandlerMap_.Erase(requestId);
}
}
napi_value MediaAssetManagerNapi::JSCancelRequest(napi_env env, napi_callback_info info)
{
size_t argc = ARGS_TWO;
napi_value argv[ARGS_TWO];
napi_value thisVar = nullptr;
GET_JS_ARGS(env, info, argc, argv, thisVar);
NAPI_ASSERT(env, (argc == ARGS_TWO), "requires 2 paramters");
string requestId;
CHECK_ARGS_THROW_INVALID_PARAM(env,
MediaLibraryNapiUtils::GetParamStringWithLength(env, argv[ARGS_ONE], REQUEST_ID_MAX_LEN, requestId));
std::string photoId = "";
std::string requestUri = "";
bool hasFastRequestInProcess = IsFastRequestCanceled(requestId, photoId);
bool hasMapRecordInProcess = IsMapRecordCanceled(requestId, photoId, requestUri, env);
if (hasMapRecordInProcess) {
DeleteProgressHandler(requestId);
}
if (hasFastRequestInProcess || hasMapRecordInProcess) {
unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
asyncContext->photoId = photoId;
asyncContext->photoUri = requestUri;
asyncContext->requestId = requestId;
return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCancelRequest", JSCancelRequestExecute,
JSCancelRequestComplete);
}
RETURN_NAPI_UNDEFINED(env);
}
static napi_value ParseArgsForLoadMovingPhoto(napi_env env, size_t argc, const napi_value argv[],
unique_ptr<MediaAssetManagerAsyncContext> &context)
{
CHECK_COND_WITH_MESSAGE(env, (argc == ARGS_THREE), "Invalid number of arguments");
std::string imageFileUri;
CHECK_COND_WITH_MESSAGE(env,
MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[PARAM1], imageFileUri) == napi_ok,
"Failed to parse image file uri");
std::string videoFileUri;
CHECK_COND_WITH_MESSAGE(env,
MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[PARAM2], videoFileUri) == napi_ok,
"Failed to parse video file uri");
std::string uri(imageFileUri + MOVING_PHOTO_URI_SPLIT + videoFileUri);
context->photoUri = uri;
RETURN_NAPI_TRUE(env);
}
static void JSLoadMovingPhotoComplete(napi_env env, napi_status status, void *data)
{
MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
MediaLibraryTracer tracer;
tracer.Start("JSLoadMovingPhotoComplete");
unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
jsContext->status = false;
if (context->error == ERR_DEFAULT) {
MovingPhotoParam movingPhotoParam;
movingPhotoParam.compatibleMode = CompatibleMode::ORIGINAL_FORMAT_MODE;
movingPhotoParam.requestId = context->requestId;
napi_value movingPhoto = MovingPhotoNapi::NewMovingPhotoNapi(env, context->photoUri,
SourceMode::EDITED_MODE, movingPhotoParam);
jsContext->data = movingPhoto;
napi_get_undefined(env, &jsContext->error);
jsContext->status = true;
} else {
context->HandleError(env, jsContext->error);
napi_get_undefined(env, &jsContext->data);
}
tracer.Finish();
if (context->work != nullptr) {
MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
context->work, *jsContext);
}
delete context;
}
static void JSLoadMovingPhotoExecute(napi_env env, void *data)
{
}
napi_value MediaAssetManagerNapi::JSLoadMovingPhoto(napi_env env, napi_callback_info info)
{
unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
CHECK_ARGS(env, napi_get_cb_info(env, info, &(asyncContext->argc), asyncContext->argv, nullptr, nullptr),
JS_INNER_FAIL);
CHECK_NULLPTR_RET(ParseArgsForLoadMovingPhoto(env, asyncContext->argc, asyncContext->argv, asyncContext));
return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSLoadMovingPhoto", JSLoadMovingPhotoExecute,
JSLoadMovingPhotoComplete);
}
int32_t MediaAssetManagerNapi::GetFdFromSandBoxUri(const std::string &sandBoxUri)
{
AppFileService::ModuleFileUri::FileUri destUri(sandBoxUri);
string destPath = destUri.GetRealPath();
if (!MediaFileUtils::IsFileExists(destPath) && !MediaFileUtils::CreateFile(destPath)) {
NAPI_DEBUG_LOG("Create empty dest file in sandbox failed, path:%{private}s", destPath.c_str());
return E_ERR;
}
string absDestPath;
if (!PathToRealPath(destPath, absDestPath)) {
NAPI_DEBUG_LOG("PathToRealPath failed, path:%{private}s", destPath.c_str());
return E_ERR;
}
return MediaFileUtils::OpenFile(absDestPath, MEDIA_FILEMODE_WRITETRUNCATE);
}
napi_status MediaAssetManagerNapi::CreateDataHandlerRef(napi_env env,
const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_ref &dataHandlerRef)
{
napi_status status = napi_create_reference(env, context->dataHandler, PARAM1, &dataHandlerRef);
if (status != napi_ok) {
dataHandlerRef = nullptr;
NAPI_ERR_LOG("napi_create_reference failed");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "napi_create_reference fail");
}
return status;
}
napi_status MediaAssetManagerNapi::CreateProgressHandlerRef(napi_env env,
const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_ref &dataHandlerRef)
{
napi_status status = napi_create_reference(env, context->mediaAssetProgressHandler, PARAM1, &dataHandlerRef);
if (status != napi_ok) {
dataHandlerRef = nullptr;
NAPI_ERR_LOG("napi_create_reference failed");
NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "napi_create_reference fail");
}
return status;
}
napi_status MediaAssetManagerNapi::CreateOnDataPreparedThreadSafeFunc(napi_env env,
const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_threadsafe_function &threadSafeFunc)
{
NAPI_DEBUG_LOG("CreateOnDataPreparedThreadSafeFunc");
napi_value workName = nullptr;
napi_create_string_utf8(env, "Data Prepared", NAPI_AUTO_LENGTH, &workName);
napi_status status = napi_create_threadsafe_function(env, context->dataHandler, NULL, workName, 0, 1,
NULL, NULL, NULL, MediaAssetManagerNapi::OnDataPrepared, &threadSafeFunc);
if (status != napi_ok) {
NAPI_ERR_LOG("napi_create_threadsafe_function fail");
threadSafeFunc = nullptr;
NapiError::ThrowError(env, JS_INNER_FAIL, "napi_create_threadsafe_function fail");
}
return status;
}
napi_status MediaAssetManagerNapi::CreateOnProgressThreadSafeFunc(napi_env env,
unique_ptr<MediaAssetManagerAsyncContext> &context, napi_threadsafe_function &progressFunc)
{
napi_value workName = nullptr;
napi_create_string_utf8(env, "ProgressThread", NAPI_AUTO_LENGTH, &workName);
napi_status status = napi_ok;
status = napi_create_threadsafe_function(env, context->mediaAssetProgressHandler, NULL, workName, 0, 1,
NULL, NULL, NULL, MediaAssetManagerNapi::OnProgress, &progressFunc);
if (status != napi_ok) {
NAPI_ERR_LOG("napi_create_threadsafe_function fail");
progressFunc = nullptr;
NapiError::ThrowError(env, JS_INNER_FAIL, "napi_create_threadsafe_function fail");
}
return status;
}
void MediaAssetManagerNapi::JSRequestExecute(napi_env env, void *data)
{
MediaLibraryTracer tracer;
tracer.Start("JSRequestExecute");
MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
OnHandleRequestImage(env, context);
if (context->subType == PhotoSubType::MOVING_PHOTO) {
string uri = CONST_LOG_MOVING_PHOTO;
Uri logMovingPhotoUri(uri);
DataShare::DataShareValuesBucket valuesBucket;
string result;
valuesBucket.Put("adapted", context->returnDataType == ReturnDataType::TYPE_MOVING_PHOTO);
AdaptedReqBody reqBody;
reqBody.adapted = context->returnDataType == ReturnDataType::TYPE_MOVING_PHOTO;
IPC::UserDefineIPCClient().SetUserId(context->userId).Call(
static_cast<uint32_t>(MediaLibraryBusinessCode::LOG_MOVING_PHOTO), reqBody);
}
}
ProgressMode GetProgressMode(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
{
if (asyncContext->compatibleMode == CompatibleMode::COMPATIBLE_FORMAT_MODE) {
if (asyncContext->subType == PhotoSubType::CINEMATIC_VIDEO) {
if (asyncContext->sourceMode == SourceMode::EDITED_MODE) {
return ProgressMode::CAMERA_AND_TRANSCODING;
}
return ProgressMode::ONLY_FOR_CAMERA;
} else {
return ProgressMode::ONLY_FOR_TRANSCODING;
}
} else {
if (asyncContext->subType == PhotoSubType::CINEMATIC_VIDEO) {
return ProgressMode::ONLY_FOR_CAMERA;
}
if (asyncContext->subType == PhotoSubType::SLOW_MOTION_VIDEO) {
return ProgressMode::ONLY_FOR_TRANSCODING;
}
}
return ProgressMode::UNDEFINED;
}
static void CheckProgressMode(napi_env env, MediaAssetManagerAsyncContext *asyncContext,
ProgressMode &progressMode)
{
if (asyncContext->photoQuality == MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS &&
progressMode == ProgressMode::CAMERA_AND_TRANSCODING) {
progressMode = ProgressMode::ONLY_FOR_TRANSCODING;
}
}
CameraProgressMode GetCameraProgressMode(napi_env env, MediaAssetManagerAsyncContext *asyncContext,
ProgressMode progressMode)
{
if (progressMode == ProgressMode::ONLY_FOR_TRANSCODING || progressMode == ProgressMode::UNDEFINED) {
return CameraProgressMode::UNDEFINED;
} else if (progressMode == ProgressMode::ONLY_FOR_CAMERA || progressMode == ProgressMode::CAMERA_AND_TRANSCODING) {
switch (asyncContext->deliveryMode) {
case DeliveryMode::FAST:
case DeliveryMode::BALANCED_MODE:
return CameraProgressMode::IMMEDIATELY_MODE;
case DeliveryMode::HIGH_QUALITY:
if (asyncContext->photoQuality == MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) {
return CameraProgressMode::IMMEDIATELY_MODE;
}
return CameraProgressMode::WAIT_FOR_POLLOT;
}
}
return CameraProgressMode::UNDEFINED;
}
void MediaAssetManagerNapi::OnHandleProgressForRequest(
napi_env env, MediaAssetManagerAsyncContext *asyncContext, CameraProgressMode &cameraProgressMode)
{
CHECK_NULL_PTR_RETURN_VOID(asyncContext, "asyncContext is nullptr");
NAPI_INFO_LOG("OnHandleProgressForRequest mode: %{public}d.", asyncContext->deliveryMode);
ProgressMode progressMode = GetProgressMode(env, asyncContext);
CheckProgressMode(env, asyncContext, progressMode);
cameraProgressMode = GetCameraProgressMode(env, asyncContext, progressMode);
MediaAssetManagerNapi::OnHandleProgress(env, asyncContext, progressMode, cameraProgressMode);
}
void MediaAssetManagerNapi::JSRequestVideoFileExecute(napi_env env, void *data)
{
MediaLibraryTracer tracer;
tracer.Start("JSRequestVideoFileExecute");
MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
OnHandleRequestVideo(env, context);
CameraProgressMode cameraProgressMode = CameraProgressMode::UNDEFINED;
OnHandleProgressForRequest(env, context, cameraProgressMode);
if (cameraProgressMode == CameraProgressMode::WAIT_FOR_POLLOT && context->onProgressPtr != nullptr) {
StartThreadForProgress();
}
}
void MediaAssetManagerNapi::Run()
{
MEDIA_INFO_LOG("enter thread run:");
string name("VideoProgressThread");
pthread_setname_np(pthread_self(), name.c_str());
while (!stopFlag_) {
{
std::unique_lock<mutex> locker(sleepMutex_);
condition_.wait_for(locker, std::chrono::milliseconds(SLEEP_100_MS));
}
uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::CAMERA_DEFINE_GET_PROGRESS_CALLBACK);
GetProgressCallbackReqBody reqBody;
GetProgressCallbackRespBody respBody;
IPC::UserDefineIPCClient().Call(businessCode, reqBody, respBody);
if (respBody.progressMap.empty()) {
pauseFlag_ = true;
MEDIA_INFO_LOG("VideoProgressThread end.");
return;
}
for (auto [requestId, progress] : respBody.progressMap) {
MEDIA_INFO_LOG("VideoProgressThread requestId: %{public}s, progress: %{public}f",
requestId.c_str(), progress);
NotifyOnProgress(static_cast<int32_t>(ProgressReturnInfoType::CAMERA_PROGRESS),
static_cast<int32_t>(progress * PROGRESS_MAX), requestId);
}
}
}
void MediaAssetManagerNapi::StopThreadForProgress()
{
MEDIA_INFO_LOG("enter StopThreadForProgress");
if (progressThread_ != nullptr) {
pauseFlag_ = false;
stopFlag_ = true;
condition_.notify_all();
if (progressThread_->joinable()) {
progressThread_->join();
}
progressThread_ = nullptr;
}
}
void MediaAssetManagerNapi::StartThreadForProgress()
{
std::unique_lock<mutex> locker(runningMutex_);
if (pauseFlag_) {
StopThreadForProgress();
}
if (progressThread_ == nullptr) {
pauseFlag_ = false;
stopFlag_ = false;
progressThread_ = std::make_unique<std::thread>(&MediaAssetManagerNapi::Run);
}
}
void MediaAssetManagerNapi::JSRequestComplete(napi_env env, napi_status, void *data)
{
MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
if (context->dataHandlerRef != nullptr) {
napi_delete_reference(env, context->dataHandlerRef);
context->dataHandlerRef = nullptr;
}
if (context->dataHandlerRef2 != nullptr) {
napi_delete_reference(env, context->dataHandlerRef2);
context->dataHandlerRef2 = nullptr;
}
MediaLibraryTracer tracer;
tracer.Start("JSRequestComplete");
unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
jsContext->status = false;
if (context->progressHandler &&
context->progressHandler->cameraProgressMode == CameraProgressMode::IMMEDIATELY_MODE) {
NotifyOnProgress(static_cast<int32_t>(
ProgressReturnInfoType::CAMERA_PROGRESS), PROGRESS_MAX, context->requestId);
context->progressHandler = nullptr;
}
if (context->assetHandler) {
NotifyMediaDataPrepared(context->assetHandler);
context->assetHandler = nullptr;
}
if (context->error == ERR_DEFAULT) {
napi_value requestId;
napi_create_string_utf8(env, context->requestId.c_str(), NAPI_AUTO_LENGTH, &requestId);
jsContext->data = requestId;
napi_get_undefined(env, &jsContext->error);
jsContext->status = true;
} else {
context->HandleError(env, jsContext->error);
napi_get_undefined(env, &jsContext->data);
}
if (context->work != nullptr) {
MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
context->work, *jsContext);
}
delete context;
}
void MediaAssetManagerNapi::JSCancelRequestExecute(napi_env env, void *data)
{
MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
int32_t mediaType = static_cast<int32_t>(MediaFileUtils::GetMediaType(
MediaFileUtils::GetFileName(context->photoUri)));
NAPI_INFO_LOG("JSCancelRequestExecute requestId: %{public}s", (context->requestId).c_str());
CancelRequestReqBody reqBody;
reqBody.photoId = context->photoId;
reqBody.mediaType = mediaType;
uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::CAMERA_MAM_CANCEL_PROCESS);
IPC::UserDefineIPCClient().Call(businessCode, reqBody);
}
void MediaAssetManagerNapi::JSCancelRequestComplete(napi_env env, napi_status, void *data)
{
MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
MediaLibraryTracer tracer;
tracer.Start("JSCancelRequestComplete");
unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
if (jsContext == nullptr) {
MEDIA_ERR_LOG("Async jsContext is null");
delete context;
return;
}
jsContext->status = false;
if (context->error == ERR_DEFAULT) {
napi_get_undefined(env, &jsContext->error);
jsContext->status = true;
} else {
context->HandleError(env, jsContext->error);
}
napi_get_undefined(env, &jsContext->data);
if (context->work != nullptr) {
MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
context->work, *jsContext);
}
delete context;
}
}
}