您的位置:首页 > 其它

OBS源码阅读笔记--将声音设置和场景挂钩

2016-10-18 16:17 645 查看
在切换场景时,声音一直不变,和场景没有关联性,这在插播的场合很不好用,要点两次按钮,然后会有尾音,现在要看看代码,想办法将声音的配置和场景相结合;

我们要先看看界面上的混音器控件是咋添加上声音的:

我们看到声音条好像是在volumeWidgets中的,搜索代码,发现有:ui->volumeWidgets->layout()->addWidget(vol);

我们将他注释掉看看是否就没有声音条了,确实注释掉就没有声音条了;

发现这个是在ActivateAudioSource时候添加的声音条;

在SourceActivated中,会调用:

QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
"ActivateAudioSource",
Q_ARG(OBSSource, OBSSource(source)));

我们搜索下:

void OBSBasic::InitOBSCallbacks()

{
ProfileScope("OBSBasic::InitOBSCallbacks");

signalHandlers.reserve(signalHandlers.size() + 6);
signalHandlers.emplace_back(obs_get_signal_handler(), "source_remove",
OBSBasic::SourceRemoved, this);
signalHandlers.emplace_back(obs_get_signal_handler(), "source_activate",
OBSBasic::SourceActivated, this);
signalHandlers.emplace_back(obs_get_signal_handler(), "source_deactivate",
OBSBasic::SourceDeactivated, this);
signalHandlers.emplace_back(obs_get_signal_handler(), "source_rename",
OBSBasic::SourceRenamed, this);

}

而source_activate是在:

static void activate_source(obs_source_t *source)

{
if (source->context.data && source->info.activate)
source->info.activate(source->context.data);
obs_source_dosignal(source, "source_activate", "activate");

}

线索已经断了,这里之前貌似很难找到源;

我们看看:

void VolControl::SetMuted(bool checked)

{
obs_source_set_muted(source, checked);

}

这个函数是点击静音还是不静音的,说明每个VolControl里面就带上了对应的audio的source

在每个声音控件被创建时,都会放到volumes.push_back(vol);中;那么我们能不能在每调用一次静音操作的时候,记录一个副本到scence中呢?

然后在切换scence的处理中恢复?我想应该可行,来试试吧。

我们在window_basic_main.hpp中可以查到获取到当前使用的场景:OBSScene      GetCurrentScene();

另外,我们还要考虑一点,在切换场景时,有些声音条是会被删除掉的,这怎么办?是不是就不删除了?

我们再看看basic-main.cpp中有SceneItemRemoved及SourceRemoved函数,应该是处理场景源被删除的动作的;

通过打印发现,在删除场景的时候,会调用SourceRemoved,但是不会调用到SceneItemRemoved,而在删除场景源的时候,会调用到SceneItemRemoved;

调用SourceRemoved后,还会接着调用RemoveScene;

思考下,通常的操作流程:

1、添加场景;

2、添加来源(可以是现场直播或者是录像);

3、如果是现场直播,则将音频源设置为麦克风;

4、如果是录播直播,则将音频源设置为录播的音频;

5、将场景对应的音频源配置信息volumes保存到场景中去;

6、在source的Deactived中,不能将该volume控件删除掉;

7、在场景被删除时,要查找场景当前正在使用的source和其ref数量,如果ref数量是0;

8、场景切换时在TransitionToScene中处理的,该函数是在transitionButton按钮触发的;

9、通过

QListWidgetItem *item = ui->scenes->item(i);

OBSScene scene = GetOBSRef<OBSScene>(item);

可以获取到某个列表控件对应的scence

10、每次(包括加载)点击的时候,都会导致SelectSceneItem被调用,另外每次点击静音按钮的时候都会导致SetMute函数被调用;

通过第10条的分析,我们在SelectSceneItem和SetMute函数中都保存下当前静音的配置到Scene中即可。

接下来,数据结构怎么设计呢?最好是将volume_control加到备份表中;

好那么我们来设计一个结构,在OBSBasic中:

typedef struct T_volumeCfg{
VolControl *volume;
bool mute;

};

std::map<OBSScene, std::vector<T_volumeCfg>> m_mVolumeCfg;

我们用这个map结构来保存每个场景的声音配置;

再定义几个函数:

//jiang

void UpdateVolumeCfg(OBSScene scene);//这个是将声音面板的内容更新到map中

void RestoreVolumeCfg(OBSScene scene);//将保存的场景声音配置恢复到声音面板中,这个在选场景的时候触发;

bool ifVolumeExist(VolControl* vol);//为了排除有的音频源会被删除的错误,我们需要判断map中的volume是否真的还存在;

在SetMuted和SelectSceneItem的时候(这两个地方更新,就可以保证map是最新的了),更新map:

void VolControl::SetMuted(bool checked)

{
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
main->UpdateVolumeCfg(main->GetCurrentScene());

obs_source_set_muted(source, checked);

}

void OBSBasic::SelectSceneItem(OBSScene scene, OBSSceneItem item, bool select)

{
SignalBlocker sourcesSignalBlocker(ui->sources);

if (scene != GetCurrentScene() || ignoreSelectionUpdate)
return;

UpdateVolumeCfg(scene);

for (int i = 0; i < ui->sources->count(); i++) {
QListWidgetItem *witem = ui->sources->item(i);
QVariant data = witem->data(static_cast<int>(QtDataRole::OBSRef));
if (!data.canConvert<OBSSceneItem>())
continue;

if (item != data.value<OBSSceneItem>())
continue;

witem->setSelected(select);
break;
}

}

在场景选择的函数中还原面板:

void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current,
QListWidgetItem *prev)

{
_cprintf("on_scenes_currentItemChanged\n");
obs_source_t *source = NULL;

if (sceneChanging)
return;

if (current) {
obs_scene_t *scene;

scene = GetOBSRef<OBSScene>(current);
source = obs_scene_get_source(scene);
}

SetCurrentScene(source);
RestoreVolumeCfg(GetCurrentScene());

UNUSED_PARAMETER(prev);

}

还原方法:

void OBSBasic::RestoreVolumeCfg(OBSScene scene)

{
std::map<OBSScene, std::vector<T_volumeCfg>>::iterator it;
for (it = m_mVolumeCfg.begin(); it != m_mVolumeCfg.end(); it++)
{
if (it->first == scene) {
for (std::vector<T_volumeCfg>::iterator iter = it->second.begin(); iter != it->second.end();) {
if (!ifVolumeExist(iter->volume)) {
iter = it->second.erase(iter);
continue;
}

bool mute = iter->mute;
iter->volume->mute->setChecked(mute);
obs_source_only_set_muted(iter->volume->GetSource(), mute);
iter++;
}
break;
}
}

}

注意:上面的setChecked只是修改了静音按钮的状态,还需要调用obs_source_only_set_muted设置user_muted这个变量,才能真正实现静音切换。

好了,一切大功告成,按照上面的方法,已经实现了音频的联动了,再也不用担心插播的时候现场的声音还在播了,只要推流前先配置好场景和音频源的关联,就可以自动关联了。

还有DeactivateAudioSource,ActivateAudioSource,SourceActivated,SourceDeactivated需要注意修改。

貌似到这里,我的obs优化工作已经完工了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: