提交 52746c25 编写于 作者: J jp9000

Add (temporary terrible) volume controls

 - Add volume control

   These volume controls are basically nothing more than sliders.  They
   look terrible and hopefully will be as temporary as they are
   terrible.

 - Allow saving of specific non-user sources via obs_load_source and
   obs_save_source functions.

 - Save data of desktop/mic audio sources (sync data, volume data, etc),
   and load the data on startup.

 - Make it so that a scene is created by default if first time using the
   application.  On certain operating systems where supported, a default
   capture will be created.  Desktop capture on mac, particularly.  Not
   sure what to do about windows because monitor capture on windows 7 is
   completely terrible and is bad to start users off with.
上级 fc0afd5c
Language="English"
DesktopDevice1="Desktop Audio"
DesktopDevice2="Desktop Audio 2"
AuxDevice1="Mic/Aux"
AuxDevice2="Mic/Aux 2"
AuxDevice3="Mic/Aux 3"
AuxDevice4="Mic/Aux 4"
Studio.Basic.Scene="Scene"
Studio.Basic.DisplayCapture="Display Capture"
MainMenu.File="File"
MainMenu.File.New="New"
......@@ -64,9 +74,3 @@ Settings.Video.InvalidResolution="Invalid resolution value. Must be [width]x[he
Settings.Video.CurrentlyActive="Video output is currently active. Please turn off any outputs to change video settings."
Settings.Audio="Audio"
Settings.Audio.DesktopAudioDevice1="Desktop Audio Device 1:"
Settings.Audio.DesktopAudioDevice2="Desktop Audio Device 2:"
Settings.Audio.AuxAudioDevice1="Auxilary Audio Device 1:"
Settings.Audio.AuxAudioDevice2="Auxilary Audio Device 2:"
Settings.Audio.AuxAudioDevice3="Auxilary Audio Device 3:"
Settings.Audio.AuxAudioDevice4="Auxilary Audio Device 4:"
......@@ -100,7 +100,7 @@ bool obs_source_init(struct obs_source *source,
{
source->refs = 1;
source->user_volume = 1.0f;
source->present_volume = 1.0f;
source->present_volume = 0.0f;
source->sync_offset = 0;
pthread_mutex_init_value(&source->filter_mutex);
pthread_mutex_init_value(&source->video_mutex);
......
......@@ -1033,6 +1033,25 @@ float obs_get_present_volume(void)
return obs ? obs->audio.present_volume : 0.0f;
}
obs_source_t obs_load_source(obs_data_t source_data)
{
obs_source_t source;
const char *name = obs_data_getstring(source_data, "name");
const char *id = obs_data_getstring(source_data, "id");
obs_data_t settings = obs_data_getobj(source_data, "settings");
double volume;
source = obs_source_create(OBS_SOURCE_TYPE_INPUT, id, name, settings);
obs_data_set_default_double(source_data, "volume", 1.0);
volume = obs_data_getdouble(source_data, "volume");
obs_source_setvolume(source, (float)volume);
obs_data_release(settings);
return source;
}
void obs_load_sources(obs_data_array_t array)
{
size_t count;
......@@ -1045,19 +1064,12 @@ void obs_load_sources(obs_data_array_t array)
pthread_mutex_lock(&obs->data.user_sources_mutex);
for (i = 0; i < count; i++) {
obs_data_t source_data = obs_data_array_item(array, i);
obs_data_t source_data = obs_data_array_item(array, i);
obs_source_t source = obs_load_source(source_data);
const char *name = obs_data_getstring(source_data, "name");
const char *id = obs_data_getstring(source_data, "id");
obs_data_t settings = obs_data_getobj(source_data, "settings");
obs_source_t source;
source = obs_source_create(OBS_SOURCE_TYPE_INPUT, id, name,
settings);
obs_add_source(source);
obs_source_release(source);
obs_data_release(settings);
obs_source_release(source);
obs_data_release(source_data);
}
......@@ -1068,23 +1080,26 @@ void obs_load_sources(obs_data_array_t array)
pthread_mutex_unlock(&obs->data.user_sources_mutex);
}
static void save_source_data(obs_data_array_t array, obs_source_t source)
obs_data_t obs_save_source(obs_source_t source)
{
obs_data_t source_data = obs_data_create();
obs_data_t settings = obs_source_getsettings(source);
const char *name = obs_source_getname(source);
const char *id;
obs_data_t source_data = obs_data_create();
obs_data_t settings = obs_source_getsettings(source);
float volume = obs_source_getvolume(source);
const char *name = obs_source_getname(source);
const char *id;
obs_source_save(source);
obs_source_gettype(source, NULL, &id);
obs_data_setstring(source_data, "name", name);
obs_data_setstring(source_data, "id", id);
obs_data_setobj (source_data, "settings", settings);
obs_data_setdouble(source_data, "volume", volume);
obs_data_array_push_back(array, source_data);
obs_data_release(source_data);
obs_data_release(settings);
return source_data;
}
obs_data_array_t obs_save_sources(void)
......@@ -1099,9 +1114,11 @@ obs_data_array_t obs_save_sources(void)
pthread_mutex_lock(&obs->data.user_sources_mutex);
for (i = 0; i < obs->data.user_sources.num; i++) {
obs_source_t source = obs->data.user_sources.array[i];
obs_source_save(source);
save_source_data(array, source);
obs_source_t source = obs->data.user_sources.array[i];
obs_data_t source_data = obs_save_source(source);
obs_data_array_push_back(array, source_data);
obs_data_release(source_data);
}
pthread_mutex_unlock(&obs->data.user_sources_mutex);
......
......@@ -357,6 +357,12 @@ EXPORT float obs_get_master_volume(void);
/** Gets the master presentation volume */
EXPORT float obs_get_present_volume(void);
/** Saves a source to settings data */
EXPORT obs_data_t obs_save_source(obs_source_t source);
/** Loads a source from settings data */
EXPORT obs_source_t obs_load_source(obs_data_t data);
/** Loads sources from a data array */
EXPORT void obs_load_sources(obs_data_array_t array);
......
......@@ -16,6 +16,9 @@
#pragma once
/* Oh no I have my own com pointer class, the world is ending, how dare you
* write your own! */
template<typename T> class ComPtr {
T *ptr;
......@@ -77,6 +80,9 @@ public:
inline T *Get() const {return ptr;}
/* nabbed this one from virtualdub */
inline T **operator~() {return Assign();}
inline operator T*() const {return ptr;}
inline T *operator->() const {return ptr;}
......
......@@ -59,6 +59,7 @@ set(obs_SOURCES
window-basic-properties.cpp
window-namedialog.cpp
properties-view.cpp
volume-control.cpp
qt-wrappers.cpp)
set(obs_HEADERS
......@@ -71,6 +72,7 @@ set(obs_HEADERS
window-namedialog.hpp
properties-view.hpp
display-helpers.hpp
volume-control.hpp
qt-display.hpp
qt-wrappers.hpp)
......
......@@ -54,7 +54,7 @@
</property>
<property name="minimumSize">
<size>
<width>620</width>
<width>720</width>
<height>0</height>
</size>
</property>
......@@ -78,225 +78,294 @@
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Scenes</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
<widget class="QWidget" name="widget_5" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Scenes</string>
</property>
<property name="topMargin">
<number>0</number>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="rightMargin">
<number>0</number>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="bottomMargin">
<number>0</number>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<item>
<widget class="QListWidget" name="scenes">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolBar" name="toolBar">
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="floatable">
<bool>false</bool>
</property>
<addaction name="actionAddScene"/>
<addaction name="actionRemoveScene"/>
<addaction name="actionSceneProperties"/>
<addaction name="separator"/>
<addaction name="actionSceneUp"/>
<addaction name="actionSceneDown"/>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="scenes">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolBar" name="toolBar">
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="floatable">
<bool>false</bool>
</property>
<addaction name="actionAddScene"/>
<addaction name="actionRemoveScene"/>
<addaction name="actionSceneProperties"/>
<addaction name="separator"/>
<addaction name="actionSceneUp"/>
<addaction name="actionSceneDown"/>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Sources</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
<widget class="QWidget" name="widget_3" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Sources</string>
</property>
<property name="rightMargin">
<number>0</number>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="bottomMargin">
<number>0</number>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<item>
<widget class="QListWidget" name="sources">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolBar" name="toolBar_2">
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="floatable">
<bool>false</bool>
</property>
<addaction name="actionAddSource"/>
<addaction name="actionRemoveSource"/>
<addaction name="actionSourceProperties"/>
<addaction name="separator"/>
<addaction name="actionSourceUp"/>
<addaction name="actionSourceDown"/>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Volume</string>
</property>
</widget>
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="volumeWidgets">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>147</width>
<height>131</height>
</rect>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>6</number>
<number>0</number>
</property>
<property name="leftMargin">
<number>2</number>
<number>0</number>
</property>
<property name="topMargin">
<number>2</number>
<number>0</number>
</property>
<property name="rightMargin">
<number>2</number>
<number>0</number>
</property>
<property name="bottomMargin">
<number>2</number>
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="sources">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolBar" name="toolBar_2">
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="floatable">
<bool>false</bool>
</property>
<addaction name="actionAddSource"/>
<addaction name="actionRemoveSource"/>
<addaction name="actionSourceProperties"/>
<addaction name="separator"/>
<addaction name="actionSourceUp"/>
<addaction name="actionSourceDown"/>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_4" native="true">
<layout class="QVBoxLayout" name="verticalLayout_9">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Volume</string>
</property>
</widget>
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="volumeWidgets">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>233</width>
<height>16</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
<item alignment="Qt::AlignTop">
<widget class="QWidget" name="widget_2" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<width>150</width>
<height>0</height>
</size>
</property>
......@@ -446,6 +515,9 @@
</property>
</action>
<action name="actionSceneUp">
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon">
<iconset resource="obs.qrc">
<normaloff>:/res/images/up.ico</normaloff>:/res/images/up.ico</iconset>
......@@ -455,6 +527,9 @@
</property>
</action>
<action name="actionSourceUp">
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon">
<iconset resource="obs.qrc">
<normaloff>:/res/images/up.ico</normaloff>:/res/images/up.ico</iconset>
......@@ -464,6 +539,9 @@
</property>
</action>
<action name="actionSceneDown">
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon">
<iconset resource="obs.qrc">
<normaloff>:/res/images/down.ico</normaloff>:/res/images/down.ico</iconset>
......@@ -473,6 +551,9 @@
</property>
</action>
<action name="actionSourceDown">
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon">
<iconset resource="obs.qrc">
<normaloff>:/res/images/down.ico</normaloff>:/res/images/down.ico</iconset>
......
......@@ -10,6 +10,12 @@
<height>602</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
......
#include "volume-control.hpp"
#include "qt-wrappers.hpp"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSlider>
#include <QLabel>
#include <string>
using namespace std;
void VolControl::OBSVolumeChanged(void *data, calldata_t calldata)
{
VolControl *volControl = static_cast<VolControl*>(data);
int vol = (int)(calldata_float(calldata, "volume") * 100.0f + 0.5f);
QMetaObject::invokeMethod(volControl, "VolumeChanged",
Q_ARG(int, vol));
}
void VolControl::VolumeChanged(int vol)
{
signalChanged = false;
slider->setValue(vol);
signalChanged = true;
}
void VolControl::SliderChanged(int vol)
{
if (signalChanged) {
signal_handler_disconnect(obs_source_signalhandler(source),
"volume", OBSVolumeChanged, this);
obs_source_setvolume(source, float(vol)*0.01f);
signal_handler_connect(obs_source_signalhandler(source),
"volume", OBSVolumeChanged, this);
}
volLabel->setText(QString::number(vol));
}
VolControl::VolControl(OBSSource source_)
: source (source_),
signalChanged (true)
{
QVBoxLayout *mainLayout = new QVBoxLayout();
QHBoxLayout *textLayout = new QHBoxLayout();
int vol = int(obs_source_getvolume(source) * 100.0f);
nameLabel = new QLabel();
volLabel = new QLabel();
slider = new QSlider(Qt::Horizontal);
QFont font = nameLabel->font();
font.setPointSize(font.pointSize()-1);
nameLabel->setText(obs_source_getname(source));
nameLabel->setFont(font);
volLabel->setText(QString::number(vol));
volLabel->setFont(font);
slider->setMinimum(0);
slider->setMaximum(100);
slider->setValue(vol);
//slider->setMaximumHeight(16);
textLayout->setContentsMargins(0, 0, 0, 0);
textLayout->addWidget(nameLabel);
textLayout->addWidget(volLabel);
textLayout->setAlignment(nameLabel, Qt::AlignLeft);
textLayout->setAlignment(volLabel, Qt::AlignRight);
mainLayout->setContentsMargins(4, 4, 4, 4);
mainLayout->setSpacing(2);
mainLayout->addItem(textLayout);
mainLayout->addWidget(slider);
setLayout(mainLayout);
signal_handler_connect(obs_source_signalhandler(source),
"volume", OBSVolumeChanged, this);
QWidget::connect(slider, SIGNAL(valueChanged(int)),
this, SLOT(SliderChanged(int)));
}
VolControl::~VolControl()
{
signal_handler_disconnect(obs_source_signalhandler(source),
"volume", OBSVolumeChanged, this);
}
#pragma once
#include <obs.hpp>
#include <QWidget>
/* TODO: Make a real volume control that isn't terrible */
class QLabel;
class QSlider;
class VolControl : public QWidget {
Q_OBJECT
private:
OBSSource source;
QLabel *nameLabel;
QLabel *volLabel;
QSlider *slider;
bool signalChanged;
static void OBSVolumeChanged(void *param, calldata_t calldata);
private slots:
void VolumeChanged(int vol);
void SliderChanged(int vol);
public:
VolControl(OBSSource source);
~VolControl();
inline obs_source_t GetSource() const {return source;}
};
......@@ -32,6 +32,7 @@
#include "window-basic-properties.hpp"
#include "qt-wrappers.hpp"
#include "display-helpers.hpp"
#include "volume-control.hpp"
#include "ui_OBSBasic.h"
......@@ -47,13 +48,13 @@ Q_DECLARE_METATYPE(OBSSceneItem);
OBSBasic::OBSBasic(QWidget *parent)
: OBSMainWindow (parent),
properties (nullptr),
streamOutput (nullptr),
service (nullptr),
aac (nullptr),
x264 (nullptr),
sceneChanging (false),
resizeTimer (0),
properties (nullptr),
ui (new Ui::OBSBasic)
{
ui->setupUi(this);
......@@ -66,6 +67,20 @@ OBSBasic::OBSBasic(QWidget *parent)
});
}
static void SaveAudioDevice(const char *name, int channel, obs_data_t parent)
{
obs_source_t source = obs_get_output_source(channel);
if (!source)
return;
obs_data_t data = obs_save_source(source);
obs_data_setobj(parent, name, data);
obs_data_release(data);
obs_source_release(source);
}
static obs_data_t GenerateSaveData()
{
obs_data_t saveData = obs_data_create();
......@@ -73,6 +88,12 @@ static obs_data_t GenerateSaveData()
obs_source_t currentScene = obs_get_output_source(0);
const char *sceneName = obs_source_getname(currentScene);
SaveAudioDevice(DESKTOP_AUDIO_1, 1, saveData);
SaveAudioDevice(DESKTOP_AUDIO_2, 2, saveData);
SaveAudioDevice(AUX_AUDIO_1, 3, saveData);
SaveAudioDevice(AUX_AUDIO_2, 4, saveData);
SaveAudioDevice(AUX_AUDIO_3, 5, saveData);
obs_data_setstring(saveData, "current_scene", sceneName);
obs_data_setarray(saveData, "sources", sourcesArray);
obs_data_array_release(sourcesArray);
......@@ -81,6 +102,18 @@ static obs_data_t GenerateSaveData()
return saveData;
}
void OBSBasic::ClearVolumeControls()
{
VolControl *control;
for (size_t i = 0; i < volumes.size(); i++) {
control = volumes[i];
delete control;
}
volumes.clear();
}
void OBSBasic::Save(const char *file)
{
obs_data_t saveData = GenerateSaveData();
......@@ -93,6 +126,45 @@ void OBSBasic::Save(const char *file)
obs_data_release(saveData);
}
static void LoadAudioDevice(const char *name, int channel, obs_data_t parent)
{
obs_data_t data = obs_data_getobj(parent, name);
if (!data)
return;
obs_source_t source = obs_load_source(data);
if (source) {
obs_set_output_source(channel, source);
obs_source_release(source);
}
obs_data_release(data);
}
void OBSBasic::CreateDefaultScene()
{
obs_scene_t scene = obs_scene_create(Str("Studio.Basic.Scene"));
obs_source_t source = obs_scene_getsource(scene);
obs_add_source(source);
#ifdef __APPLE__
source = obs_source_create(OBS_SOURCE_TYPE_INPUT, "display_capture",
Str("Studio.Basic.DisplayCapture"), NULL);
if (source) {
sourceSceneRefs[source] = 0;
obs_scene_add(scene, source);
obs_add_source(source);
obs_source_release(source);
}
#endif
obs_set_output_source(0, obs_scene_getsource(scene));
obs_scene_release(scene);
}
void OBSBasic::Load(const char *file)
{
if (!file) {
......@@ -101,14 +173,22 @@ void OBSBasic::Load(const char *file)
}
BPtr<char> jsonData = os_quick_read_utf8_file(file);
if (!jsonData)
if (!jsonData) {
CreateDefaultScene();
return;
}
obs_data_t data = obs_data_create_from_json(jsonData);
obs_data_array_t sources = obs_data_getarray(data, "sources");
const char *sceneName = obs_data_getstring(data, "current_scene");
obs_source_t curScene;
LoadAudioDevice(DESKTOP_AUDIO_1, 1, data);
LoadAudioDevice(DESKTOP_AUDIO_2, 2, data);
LoadAudioDevice(AUX_AUDIO_1, 3, data);
LoadAudioDevice(AUX_AUDIO_2, 4, data);
LoadAudioDevice(AUX_AUDIO_3, 5, data);
obs_load_sources(sources);
curScene = obs_get_source_by_name(sceneName);
......@@ -317,8 +397,24 @@ bool OBSBasic::InitBasicConfig()
return InitBasicConfigDefaults();
}
void OBSBasic::InitOBSCallbacks()
{
signal_handler_connect(obs_signalhandler(), "source_add",
OBSBasic::SourceAdded, this);
signal_handler_connect(obs_signalhandler(), "source_remove",
OBSBasic::SourceRemoved, this);
signal_handler_connect(obs_signalhandler(), "channel_change",
OBSBasic::ChannelChanged, this);
signal_handler_connect(obs_signalhandler(), "source_activate",
OBSBasic::SourceActivated, this);
signal_handler_connect(obs_signalhandler(), "source_deactivate",
OBSBasic::SourceDeactivated, this);
}
void OBSBasic::OBSInit()
{
BPtr<char> savePath(os_get_config_path("obs-studio/basic/scenes.json"));
/* make sure it's fully displayed before doing any initialization */
show();
App()->processEvents();
......@@ -332,12 +428,7 @@ void OBSBasic::OBSInit()
if (!ResetAudio())
throw "Failed to initialize audio";
signal_handler_connect(obs_signalhandler(), "source_add",
OBSBasic::SourceAdded, this);
signal_handler_connect(obs_signalhandler(), "source_remove",
OBSBasic::SourceRemoved, this);
signal_handler_connect(obs_signalhandler(), "channel_change",
OBSBasic::ChannelChanged, this);
InitOBSCallbacks();
/* TODO: this is a test, all modules will be searched for and loaded
* automatically later */
......@@ -364,9 +455,7 @@ void OBSBasic::OBSInit()
if (!InitService())
throw "Failed to initialize service";
BPtr<char> savePath(os_get_config_path("obs-studio/basic/scenes.json"));
Load(savePath);
ResetAudioDevices();
}
......@@ -381,6 +470,7 @@ OBSBasic::~OBSBasic()
/* free the lists before shutting down to remove the scene/item
* references */
ClearVolumeControls();
ui->sources->clear();
ui->scenes->clear();
obs_shutdown();
......@@ -519,6 +609,25 @@ void OBSBasic::UpdateSceneSelection(OBSSource source)
}
}
void OBSBasic::ActivateAudioSource(OBSSource source)
{
VolControl *vol = new VolControl(source);
volumes.push_back(vol);
ui->volumeWidgets->layout()->addWidget(vol);
}
void OBSBasic::DeactivateAudioSource(OBSSource source)
{
for (size_t i = 0; i < volumes.size(); i++) {
if (volumes[i]->GetSource() == source) {
delete volumes[i];
volumes.erase(volumes.begin() + i);
break;
}
}
}
/* OBS Callbacks */
void OBSBasic::SceneItemAdded(void *data, calldata_t params)
......@@ -561,6 +670,28 @@ void OBSBasic::SourceRemoved(void *data, calldata_t params)
Q_ARG(OBSSource, OBSSource(source)));
}
void OBSBasic::SourceActivated(void *data, calldata_t params)
{
obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
uint32_t flags = obs_source_get_output_flags(source);
if (flags & OBS_SOURCE_AUDIO)
QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
"ActivateAudioSource",
Q_ARG(OBSSource, OBSSource(source)));
}
void OBSBasic::SourceDeactivated(void *data, calldata_t params)
{
obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
uint32_t flags = obs_source_get_output_flags(source);
if (flags & OBS_SOURCE_AUDIO)
QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
"DeactivateAudioSource",
Q_ARG(OBSSource, OBSSource(source)));
}
void OBSBasic::ChannelChanged(void *data, calldata_t params)
{
obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
......@@ -700,7 +831,7 @@ void OBSBasic::ResetAudioDevice(const char *sourceId, const char *deviceName,
obs_data_t settings = obs_data_create();
obs_data_setstring(settings, "device_id", deviceId);
source = obs_source_create(OBS_SOURCE_TYPE_INPUT,
sourceId, deviceName, settings);
sourceId, Str(deviceName), settings);
obs_data_release(settings);
obs_set_output_source(channel, source);
......
......@@ -19,6 +19,7 @@
#include <obs.hpp>
#include <unordered_map>
#include <vector>
#include <memory>
#include "window-main.hpp"
#include "window-basic-properties.hpp"
......@@ -28,15 +29,26 @@
#include <QPointer>
class QListWidgetItem;
class VolControl;
#include "ui_OBSBasic.h"
#define DESKTOP_AUDIO_1 Str("DesktopAudioDevice1")
#define DESKTOP_AUDIO_2 Str("DesktopAudioDevice2")
#define AUX_AUDIO_1 Str("AuxAudioDevice1")
#define AUX_AUDIO_2 Str("AuxAudioDevice2")
#define AUX_AUDIO_3 Str("AuxAudioDevice3")
class OBSBasic : public OBSMainWindow {
Q_OBJECT
private:
std::unordered_map<obs_source_t, int> sourceSceneRefs;
std::vector<VolControl*> volumes;
QPointer<OBSBasicProperties> properties;
obs_output_t streamOutput;
obs_service_t service;
obs_encoder_t aac;
......@@ -50,7 +62,9 @@ private:
ConfigFile basicConfig;
QPointer<OBSBasicProperties> properties;
void CreateDefaultScene();
void ClearVolumeControls();
void Save(const char *file);
void Load(const char *file);
......@@ -65,6 +79,8 @@ private:
bool InitBasicConfigDefaults();
bool InitBasicConfig();
void InitOBSCallbacks();
OBSScene GetCurrentScene();
OBSSceneItem GetCurrentSceneItem();
......@@ -92,12 +108,17 @@ private slots:
void RemoveScene(OBSSource source);
void UpdateSceneSelection(OBSSource source);
void ActivateAudioSource(OBSSource source);
void DeactivateAudioSource(OBSSource source);
private:
/* OBS Callbacks */
static void SceneItemAdded(void *data, calldata_t params);
static void SceneItemRemoved(void *data, calldata_t params);
static void SourceAdded(void *data, calldata_t params);
static void SourceRemoved(void *data, calldata_t params);
static void SourceActivated(void *data, calldata_t params);
static void SourceDeactivated(void *data, calldata_t params);
static void ChannelChanged(void *data, calldata_t params);
static void RenderMain(void *data, uint32_t cx, uint32_t cy);
......
......@@ -13,7 +13,7 @@ static const char *rtmp_common_getname(const char *locale)
UNUSED_PARAMETER(locale);
/* TODO: locale */
return "Other Streaming Services";
return "Streaming Services";
}
static void rtmp_common_update(void *data, obs_data_t settings)
......
......@@ -131,6 +131,24 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs"</Command>
</CustomBuild>
<CustomBuild Include="..\..\..\obs\volume-control.hpp">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing volume-control.hpp...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing volume-control.hpp...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing volume-control.hpp...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing volume-control.hpp...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs"</Command>
</CustomBuild>
<ClInclude Include="GeneratedFiles\ui_NameDialog.h" />
<ClInclude Include="GeneratedFiles\ui_OBSBasic.h" />
<ClInclude Include="GeneratedFiles\ui_OBSBasicProperties.h" />
......@@ -177,6 +195,7 @@
<ClCompile Include="..\..\..\obs\platform-windows.cpp" />
<ClCompile Include="..\..\..\obs\properties-view.cpp" />
<ClCompile Include="..\..\..\obs\qt-wrappers.cpp" />
<ClCompile Include="..\..\..\obs\volume-control.cpp" />
<ClCompile Include="..\..\..\obs\window-basic-main.cpp" />
<ClCompile Include="..\..\..\obs\window-basic-properties.cpp" />
<ClCompile Include="..\..\..\obs\window-basic-settings.cpp" />
......@@ -193,6 +212,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_volume-control.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_window-basic-main.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
......@@ -235,6 +258,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_volume-control.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_window-basic-main.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
......
......@@ -74,6 +74,9 @@
<CustomBuild Include="..\..\..\obs\properties-view.hpp">
<Filter>Header Files</Filter>
</CustomBuild>
<CustomBuild Include="..\..\..\obs\volume-control.hpp">
<Filter>Header Files</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\obs\platform.hpp">
......@@ -177,6 +180,15 @@
<ClCompile Include="..\..\..\obs\properties-view.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_volume-control.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_volume-control.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="..\..\..\obs\volume-control.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Image Include="..\..\..\obs\forms\images\add.ico">
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册