赞
踩
在切换场景时,声音一直不变,和场景没有关联性,这在插播的场合很不好用,要点两次按钮,然后会有尾音,现在要看看代码,想办法将声音的配置和场景相结合;
我们要先看看界面上的混音器控件是咋添加上声音的:
我们看到声音条好像是在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优化工作已经完工了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。