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

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端进行交互。
更多推荐

所有评论(0)