当前位置:   article > 正文

OBS源码阅读笔记--将声音设置和场景挂钩_obs切换场景画面让声音跟随

obs切换场景画面让声音跟随

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

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

我们看到声音条好像是在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优化工作已经完工了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/194956
推荐阅读
相关标签
  

闽ICP备14008679号