> 文档中心 > openharmony标准系统移植之音频工作流程分析

openharmony标准系统移植之音频工作流程分析

首先可以知道js上层应用是通过napi去调用底层函数,首先是通过类似如下的函数去注册一个模块提供给上层app使用。

extern "C" __attribute__((constructor)) void AppRegister(){    napi_module_register(&appModule);}

那么我们寻找多媒体相关的注册模块函数,源码在foundation/multimedia/media_standard/frameworks/kitsimpl/js/player/native_module_ohos_media.cpp文件中,

static napi_value Export(napi_env env, napi_value exports){    MEDIA_LOGD("Export() is called");    OHOS::Media::AudioDecoderNapi::Init(env, exports);    OHOS::Media::AudioEncoderNapi::Init(env, exports);    OHOS::Media::AudioPlayerNapi::Init(env, exports);    OHOS::Media::AudioRecorderNapi::Init(env, exports);    OHOS::Media::MediaCapsNapi::Init(env, exports);    OHOS::Media::MediaVideoCapsNapi::Init(env, exports);    OHOS::Media::MediaDataSourceNapi::Init(env, exports);    OHOS::Media::VideoDecoderNapi::Init(env, exports);    OHOS::Media::VideoEncoderNapi::Init(env, exports);    OHOS::Media::VideoPlayerNapi::Init(env, exports);    OHOS::Media::VideoRecorderNapi::Init(env, exports);    OHOS::Media::MediaEnumNapi::Init(env, exports);    return exports;}/* * module define */static napi_module g_module = {    .nm_version = 1,    .nm_flags = 0,    .nm_filename = nullptr,    .nm_register_func = Export, // 模块导出入口函数    .nm_modname = "multimedia.media",    .nm_priv = ((void*)0),    .reserved = {0}};/* * module register */extern "C" __attribute__((constructor)) void RegisterModule(void){    MEDIA_LOGD("RegisterModule() is called");    napi_module_register(&g_module);}

系统启动后,使用hilog查看,可以看到注册成功了。
openharmony标准系统移植之音频工作流程分析
我们是想确定音频播放的流程,所以我们只关心OHOS::Media::AudioPlayerNapi::Init(env, exports);这个初始化过程。那么我们查找这个类foundation/multimedia/media_standard/interfaces/kits/js/media/include/audio_player_napi.h定义在这个头文件中,

namespace OHOS { // 这里是c++的命名空间 OHOSnamespace Media { // 这里是c++的命名空间 Media class AudioPlayerNapi { // 这里是声明类 AudioPlayerNapipublic:    static napi_value Init(napi_env env, napi_value exports);private:    static napi_value Constructor(napi_env env, napi_callback_info info);    static void Destructor(napi_env env, void *nativeObject, void *finalize);    static napi_value CreateAudioPlayer(napi_env env, napi_callback_info info);    static napi_value CreateAudioPlayerAsync(napi_env env, napi_callback_info info);    static napi_value Play(napi_env env, napi_callback_info info);    static napi_value Pause(napi_env env, napi_callback_info info);    static napi_value Stop(napi_env env, napi_callback_info info);    static napi_value Reset(napi_env env, napi_callback_info info);    static napi_value Seek(napi_env env, napi_callback_info info);    static napi_value SetVolume(napi_env env, napi_callback_info info);    static napi_value Release(napi_env env, napi_callback_info info);    static napi_value On(napi_env env, napi_callback_info info);    static napi_value SetSrc(napi_env env, napi_callback_info info);    static napi_value GetSrc(napi_env env, napi_callback_info info);    static napi_value GetMediaDataSrc(napi_env env, napi_callback_info info);    static napi_value SetMediaDataSrc(napi_env env, napi_callback_info info);    static napi_value SetFdSrc(napi_env env, napi_callback_info info);    static napi_value GetFdSrc(napi_env env, napi_callback_info info);    static napi_value SetLoop(napi_env env, napi_callback_info info);    static napi_value GetLoop(napi_env env, napi_callback_info info);    static napi_value GetCurrentTime(napi_env env, napi_callback_info info);    static napi_value GetDuration(napi_env env, napi_callback_info info);    static napi_value GetState(napi_env env, napi_callback_info info);    static napi_value GetTrackDescription(napi_env env, napi_callback_info info);    static void AsyncGetTrackDescription(napi_env env, void *data);    void ErrorCallback(MediaServiceExtErrCode errCode);    AudioPlayerNapi();    ~AudioPlayerNapi();    static napi_ref constructor_;    std::shared_ptr<MediaDataSourceCallback> dataSrcCallBack_ = nullptr;    napi_env env_ = nullptr;    napi_ref wrapper_ = nullptr;    std::shared_ptr<Player> nativePlayer_ = nullptr;    std::shared_ptr<PlayerCallback> callbackNapi_ = nullptr;    std::string uri_ = "";    std::vector<Format> audioTrackInfoVec_;    AVFileDescriptor rawFd_;};} // namespace Media} // namespace OHOS

具体实现的方法定义在文件foundation/multimedia/media_standard/frameworks/kitsimpl/js/player/audio_player_napi.cpp中,init方法内容如下

napi_value AudioPlayerNapi::Init(napi_env env, napi_value exports){    napi_property_descriptor properties[] = { DECLARE_NAPI_FUNCTION("play", Play),  //定义提供上层使用的方法play,对应本地的Play方法 DECLARE_NAPI_FUNCTION("pause", Pause), DECLARE_NAPI_FUNCTION("stop", Stop), DECLARE_NAPI_FUNCTION("reset", Reset), DECLARE_NAPI_FUNCTION("release", Release), DECLARE_NAPI_FUNCTION("seek", Seek), DECLARE_NAPI_FUNCTION("on", On), DECLARE_NAPI_FUNCTION("setVolume", SetVolume), DECLARE_NAPI_FUNCTION("getTrackDescription", GetTrackDescription), DECLARE_NAPI_GETTER_SETTER("src", GetSrc, SetSrc), DECLARE_NAPI_GETTER_SETTER("dataSrc", GetMediaDataSrc, SetMediaDataSrc), DECLARE_NAPI_GETTER_SETTER("loop", GetLoop, SetLoop), DECLARE_NAPI_GETTER("currentTime", GetCurrentTime), DECLARE_NAPI_GETTER("duration", GetDuration), DECLARE_NAPI_GETTER("state", GetState)    };    napi_property_descriptor staticProperty[] = { DECLARE_NAPI_STATIC_FUNCTION("createAudioPlayer", CreateAudioPlayer),    };    napi_value constructor = nullptr;    napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr, sizeof(properties) / sizeof(properties[0]), properties, &constructor); // 定义C++类对应的JavaScript类,包括JS类名、JS构造函数    CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define AudioPlayer class");    status = napi_create_reference(env, constructor, 1, &constructor_);    CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to create reference of constructor");    status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);    CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to set constructor");    status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);    CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define static function");    MEDIA_LOGD("Init success");    return exports;}

为了更好的理解音频播放的工作原理这边写了个上层测试用例,如下图所示界面,示例代码在音频单步测试app
在这里插入图片描述
其中源码主要为如下功能说明
初始化函数如下

async init() {    console.info('zxy musicPlayer init');    this.audioPlayer =  media.createAudioPlayer();    //创建一个音频播放实例  }

以上功能片段主要为创建一个音频管理对象,这将会通过调用文件foundation/multimedia/media_standard/interfaces/kits/js/media/@ohos.multimedia.media.d.ts中对应的接口,如下图方法。
openharmony标准系统移植之音频工作流程分析
此为异步回调接口,异步方法调用整个过程不会阻碍调用者的工作。异步回调方法定义如下格式

命名:动词或动词+名词格式: - 无参:方法名([回调函数]) - 有参:方法名(必填参数[, 可选参数][, 回调函数])返回值 - 若回调函数非空,则返回void - 若回调函数为空,则返回Promise实例对象

所以我们这里的function createAudioPlayer(): AudioPlayer;为无参数,无回调,返回值为AudioPlayer实例对象。这样再接着调用上文使用napi_module_register注册的NAPI接口函数,改函数定义在foundation/multimedia/media_standard/frameworks/kitsimpl/js/player/audio_player_napi.cpp

napi_value AudioPlayerNapi::CreateAudioPlayer(napi_env env, napi_callback_info info){    MEDIA_LOGD("zxy start AudioPlayerNapi::CreateAudioPlayer");    napi_value result = nullptr;    napi_value constructor = nullptr;    napi_status status = napi_get_reference_value(env, constructor_, &constructor); // 获取计数值,存放在constructor中    if (status != napi_ok) { MEDIA_LOGE("Failed to get the representation of constructor object"); napi_get_undefined(env, &result); return result;    }    status = napi_new_instance(env, constructor, 0, nullptr, &result);//该函数用于使用给定的napi_value来实例化一个新的JavaScript值,该值代表该对象的构造函数    if (status != napi_ok) { MEDIA_LOGE("Failed to instantiate JavaScript audio player instance"); napi_get_undefined(env, &result); return result;    }    MEDIA_LOGD("zxy CreateAudioPlayer success");    return result;}

当我们点击上层app调用media.createAudioPlayer();后执行了如下操作

01-01 05:10:52.943  1202  1212 D 02b00/AudioPlayerNapi: {CreateAudioPlayer():152} zxy start AudioPlayerNapi::CreateAudioPlayer01-01 05:10:52.944  1202  1212 D 02b00/AudioPlayerNapi: {Constructor():105} zxy start AudioPlayerNapi::Constructor01-01 05:10:52.944  1202  1212 D 02b00/PlayerImpl: {Init():59} zxy start PlayerImpl::Init01-01 05:10:52.959  1202  1212 D 02b00/AudioPlayerNapi: {Constructor():136} zxy AudioPlayerNapi::Constructor success01-01 05:10:52.959  1202  1212 D 02b00/AudioPlayerNapi: {CreateAudioPlayer():169} zxy CreateAudioPlayer success