1.pulseaudio:是一个声音服务器,一个后台进程,它从一个或多个音源(进程或输入设备)接受声音输入,然后重定向声音到一个或多个槽(声卡、远程网络PulseAudio服务或其他进程)。PulseAudio的主要目的是重定向所有声音流。
pulseaudio结构图:

img

2.PaAdapterManager::CreateCapturer主要作用是创建PulseAudio的Capture模块的client端,调用**InitPaContext()创建上下文并连接server端,创建成功以后,再调用InitPaStream()CreateCapturerStream()**给该client初始化流信息。

int32_t PaAdapterManager::CreateCapturer(AudioProcessConfig processConfig, std::shared_ptr<ICapturerStream> &stream)
{
    AUDIO_DEBUG_LOG("Create capturer start");
    CHECK_AND_RETURN_RET_LOG(managerType_ == RECORDER, ERROR, "Invalid managerType:%{public}d", managerType_);

    int32_t ret = InitPaContext();
    CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Failed to init pa context");
    uint32_t sessionId = PolicyHandler::GetInstance().GenerateSessionId(processConfig.appInfo.appUid);

    pa_stream *paStream = InitPaStream(processConfig, sessionId, true);
    CHECK_AND_RETURN_RET_LOG(paStream != nullptr, ERR_OPERATION_FAILED, "Failed to init capture");

    std::shared_ptr<ICapturerStream> capturerStream = CreateCapturerStream(processConfig, paStream);
    CHECK_AND_RETURN_RET_LOG(capturerStream != nullptr, ERR_DEVICE_INIT, "Failed to init pa stream");
    capturerStream->SetStreamIndex(sessionId);
    std::lock_guard<std::mutex> lock(streamMapMutex_);
    capturerStreamMap_[sessionId] = capturerStream;
    stream = capturerStream;
    return SUCCESS;
}

3.PaAdapterManager::InitPaContext()主要作用为调用pulseaudio库的接口函数,调用pa_threaded_mainloop_new创建mainloop,调用pa_context_new创建context,并且调用pa_context_connect连接至server端,连接成功后调用**HandleMainLoopStart()**启动mainloop。

    int32_t PaAdapterManager::InitPaContext()
    {
        ...
        mainLoop_ = pa_threaded_mainloop_new();
        CHECK_AND_RETURN_RET_LOG(mainLoop_ != nullptr, ERR_DEVICE_INIT, "Failed to init pa mainLoop");
        api_ = pa_threaded_mainloop_get_api(mainLoop_);
        if (managerType_ == PLAYBACK) {
            pa_threaded_mainloop_set_name(mainLoop_, "OS_RendererML");
        } else if (managerType_ == DUP_PLAYBACK) {
            pa_threaded_mainloop_set_name(mainLoop_, "OS_DRendererML");
        } else if (managerType_ == DUAL_PLAYBACK) {
            pa_threaded_mainloop_set_name(mainLoop_, "OS_DualRendererML");
        } else if (managerType_ == RECORDER) {
            pa_threaded_mainloop_set_name(mainLoop_, "OS_CapturerML");
        } else {
            AUDIO_ERR_LOG("Not supported managerType:%{public}d", managerType_);
        }
        ...
        context_ = pa_context_new(api_, packageName.c_str());
        if (context_ == nullptr) {
            AUDIO_ERR_LOG("New context failed");
            pa_threaded_mainloop_free(mainLoop_);
            return ERR_DEVICE_INIT;
        }
    
        pa_context_set_state_callback(context_, PAContextStateCb, mainLoop_);
        if (pa_context_connect(context_, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) {
            int error = pa_context_errno(context_);
            AUDIO_ERR_LOG("Context connect error: %{public}s", pa_strerror(error));
            return ERR_DEVICE_INIT;
        }
        isContextConnected_ = true;
        CHECK_AND_RETURN_RET_LOG(HandleMainLoopStart() == SUCCESS, ERR_DEVICE_INIT, "Failed to start pa mainLoop");
    
        return SUCCESS;
    }

4.调用pa_threaded_mainloop_start启动mainloop,并通过循环检查pa_context_的状态,当上下文状态变为 PA_CONTEXT_READY 时,退出循环并返回 SUCCESS

int32_t PaAdapterManager::HandleMainLoopStart()
{
    PaLockGuard lock(mainLoop_);
    if (pa_threaded_mainloop_start(mainLoop_) < 0) {
        return ERR_DEVICE_INIT;
    }
    isMainLoopStarted_ = true;

    while (true) {
        pa_context_state_t state = pa_context_get_state(context_);
        if (state == PA_CONTEXT_READY) {
            AUDIO_INFO_LOG("pa context is ready");
            break;
        }

        if (!PA_CONTEXT_IS_GOOD(state)) {
            int error = pa_context_errno(context_);
            AUDIO_ERR_LOG("Context bad state error: %{public}s", pa_strerror(error));
            lock.Unlock();
            ResetPaContext();
            return ERR_DEVICE_INIT;
        }
        pa_threaded_mainloop_wait(mainLoop_);
    }
    return SUCCESS;
}

此时,PulseAudio的client端与PulseAudio的server端连接成功,并使用线程mainLoop_与server端进行交互。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐