Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/data/locale/en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,8 @@ Basic.Settings.Advanced.Video.HdrNominalPeakLevel="HDR Nominal Peak Level"
Basic.Settings.Advanced.Audio.MonitoringDevice="Monitoring Device"
Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Default"
Basic.Settings.Advanced.Audio.DisableAudioDucking="Disable Windows audio ducking"
Basic.Settings.Advanced.Audio.AsioMonitoringDevice="ASIO Monitoring Device"
Basic.Settings.Audio.AsioMonitoring="Setup Panel"
Basic.Settings.Advanced.StreamDelay="Stream Delay"
Basic.Settings.Advanced.StreamDelay.Duration="Duration"
Basic.Settings.Advanced.StreamDelay.Preserve="Preserve cutoff point (increase delay) when reconnecting"
Expand Down
6 changes: 6 additions & 0 deletions frontend/data/themes/Yami.obt
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,12 @@ QPushButton::menu-indicator {
right: -2px;
}

QWidget QFormLayout > QToolButton#asioMonitoring {
min-width: 0px;
max-width: 16777215px;
text-align: center;
}

QToolButton {
border: 1px solid var(--button_border);
}
Expand Down
24 changes: 24 additions & 0 deletions frontend/forms/OBSBasicSettings.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6327,6 +6327,29 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="asioDeviceLabel">
<property name="text">
<string>Basic.Settings.Advanced.Audio.AsioMonitoringDevice</string>
</property>
<property name="buddy">
<cstring>asioMonitoring</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QToolButton" name="asioMonitoring">
<property name="text">
<string>Basic.Settings.Audio.AsioMonitoring</string>
</property>
<property name="objectName">
<string>asioMonitoring</string>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed"/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down Expand Up @@ -8955,6 +8978,7 @@
<tabstop>meterDecayRate</tabstop>
<tabstop>peakMeterType</tabstop>
<tabstop>monitoringDevice</tabstop>
<tabstop>asioMonitoring</tabstop>
<tabstop>disableAudioDucking</tabstop>
<tabstop>lowLatencyBuffering</tabstop>
<tabstop>baseResolution</tabstop>
Expand Down
25 changes: 25 additions & 0 deletions frontend/settings/OBSBasicSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,14 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
FillAudioMonitoringDevices();
}

#ifdef _WIN32
connect(ui->asioMonitoring, &QPushButton::clicked, this, &OBSBasicSettings::AsioMonitoringShow);
ui->asioMonitoring->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
ui->formLayout_56->setAlignment(ui->asioMonitoring, Qt::AlignLeft);
#else
ui->asioMonitoring->hide();
ui->asioDeviceLabel->hide();
#endif
connect(ui->channelSetup, &QComboBox::currentIndexChanged, this, &OBSBasicSettings::SurroundWarning);
connect(ui->channelSetup, &QComboBox::currentIndexChanged, this, &OBSBasicSettings::SpeakerLayoutChanged);
connect(ui->lowLatencyBuffering, &QCheckBox::clicked, this, &OBSBasicSettings::LowLatencyBufferingChanged);
Expand Down Expand Up @@ -5545,6 +5553,23 @@ void OBSBasicSettings::SimpleRecordingEncoderChanged()
ui->simpleOutInfoLayout->addWidget(simpleOutRecWarning);
}

#ifdef _WIN32
void OBSBasicSettings::AsioMonitoringShow()
{
QList<QAction *> actions = main->ui->menuTools->actions();
QAction *asioAction = nullptr;
for (QAction *action : actions) {
if (action->objectName() == "asioOutputSetupAction") {
asioAction = action;
break;
}
}
if (asioAction) {
asioAction->trigger();
}
}
#endif

void OBSBasicSettings::SurroundWarning(int idx)
{
if (idx == lastChannelSetupIdx || idx == -1) {
Expand Down
3 changes: 3 additions & 0 deletions frontend/settings/OBSBasicSettings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ private slots:
void AudioChanged();
void AudioChangedRestart();
void ReloadAudioSources();
#ifdef _WIN32
void AsioMonitoringShow();
#endif
Comment thread
pkviet marked this conversation as resolved.
void SurroundWarning(int idx);
void SpeakerLayoutChanged(int idx);
void LowLatencyBufferingChanged(bool checked);
Expand Down
20 changes: 10 additions & 10 deletions libobs/media-io/audio-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ struct audio_output {
audio_input_callback_t input_cb;
void *input_param;
pthread_mutex_t input_mutex;
struct audio_mix mixes[MAX_AUDIO_MIXES];
struct audio_mix mixes[MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES];
};

/* ------------------------------------------------------------------------- */
Expand Down Expand Up @@ -133,7 +133,7 @@ static inline void clamp_audio_output(struct audio_output *audio, size_t bytes)
{
size_t float_size = bytes / sizeof(float);

for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
for (size_t mix_idx = 0; mix_idx < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix_idx++) {
struct audio_mix *mix = &audio->mixes[mix_idx];

/* do not process mixing if a specific mix is inactive */
Expand All @@ -160,7 +160,7 @@ static inline void clamp_audio_output(struct audio_output *audio, size_t bytes)
static void input_and_output(struct audio_output *audio, uint64_t audio_time, uint64_t prev_time)
{
size_t bytes = AUDIO_OUTPUT_FRAMES * audio->block_size;
struct audio_output_data data[MAX_AUDIO_MIXES];
struct audio_output_data data[MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES];
uint32_t active_mixes = 0;
uint64_t new_ts = 0;
bool success;
Expand All @@ -173,14 +173,14 @@ static void input_and_output(struct audio_output *audio, uint64_t audio_time, ui

/* get mixers */
pthread_mutex_lock(&audio->input_mutex);
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
for (size_t i = 0; i < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); i++) {
if (audio->mixes[i].inputs.num)
active_mixes |= (1 << i);
}
pthread_mutex_unlock(&audio->input_mutex);

/* clear mix buffers */
for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
for (size_t mix_idx = 0; mix_idx < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix_idx++) {
struct audio_mix *mix = &audio->mixes[mix_idx];

memset(mix->buffer, 0, sizeof(mix->buffer));
Expand All @@ -198,7 +198,7 @@ static void input_and_output(struct audio_output *audio, uint64_t audio_time, ui
clamp_audio_output(audio, bytes);

/* output */
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++)
for (size_t i = 0; i < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); i++)
do_audio_output(audio, i, new_ts, AUDIO_OUTPUT_FRAMES);
}

Expand Down Expand Up @@ -291,7 +291,7 @@ bool audio_output_connect(audio_t *audio, size_t mi, const struct audio_convert_
{
bool success = false;

if (!audio || mi >= MAX_AUDIO_MIXES)
if (!audio || mi >= (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES))
return false;

pthread_mutex_lock(&audio->input_mutex);
Expand Down Expand Up @@ -330,7 +330,7 @@ bool audio_output_connect(audio_t *audio, size_t mi, const struct audio_convert_

void audio_output_disconnect(audio_t *audio, size_t mix_idx, audio_output_callback_t callback, void *param)
{
if (!audio || mix_idx >= MAX_AUDIO_MIXES)
if (!audio || mix_idx >= (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES))
return;

pthread_mutex_lock(&audio->input_mutex);
Expand Down Expand Up @@ -403,7 +403,7 @@ void audio_output_close(audio_t *audio)
pthread_mutex_destroy(&audio->input_mutex);
}

for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
for (size_t mix_idx = 0; mix_idx < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix_idx++) {
struct audio_mix *mix = &audio->mixes[mix_idx];

for (size_t i = 0; i < mix->inputs.num; i++)
Expand All @@ -424,7 +424,7 @@ bool audio_output_active(const audio_t *audio)
if (!audio)
return false;

for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
for (size_t mix_idx = 0; mix_idx < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix_idx++) {
const struct audio_mix *mix = &audio->mixes[mix_idx];

if (mix->inputs.num != 0)
Expand Down
9 changes: 8 additions & 1 deletion libobs/media-io/audio-io.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,20 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
// extra track for ASIO monitoring on windows only
#define MAX_AUDIO_MONITORING_MIXES 1
#else
#define MAX_AUDIO_MONITORING_MIXES 0
#endif
Comment thread
pkviet marked this conversation as resolved.

#define MAX_AUDIO_MIXES 6

#define MAX_AUDIO_CHANNELS 8
#define MAX_DEVICE_INPUT_CHANNELS 64
#define AUDIO_OUTPUT_FRAMES 1024

#define TOTAL_AUDIO_SIZE (MAX_AUDIO_MIXES * MAX_AUDIO_CHANNELS * AUDIO_OUTPUT_FRAMES * sizeof(float))
#define TOTAL_AUDIO_SIZE ((MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES) * MAX_AUDIO_CHANNELS * AUDIO_OUTPUT_FRAMES * sizeof(float))

/*
* Base audio output component. Use this to create an audio output track
Expand Down
2 changes: 1 addition & 1 deletion libobs/obs-audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ static inline void mix_audio(struct audio_output_data *mixes, obs_source_t *sour
total_floats -= start_point;
}

for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
for (size_t mix_idx = 0; mix_idx < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix_idx++) {
for (size_t ch = 0; ch < channels; ch++) {
register float *mix = mixes[mix_idx].data[ch];
register float *aud = source->audio_output_buf[mix_idx][ch];
Expand Down
4 changes: 2 additions & 2 deletions libobs/obs-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@ struct obs_source {
struct deque audio_input_buf[MAX_AUDIO_CHANNELS];
size_t last_audio_input_buf_size;
DARRAY(struct audio_action) audio_actions;
float *audio_output_buf[MAX_AUDIO_MIXES][MAX_AUDIO_CHANNELS];
float *audio_output_buf[MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES][MAX_AUDIO_CHANNELS];
float *audio_mix_buf[MAX_AUDIO_CHANNELS];
struct resample_info sample_info;
audio_resampler_t *resampler;
Expand Down Expand Up @@ -1257,7 +1257,7 @@ struct obs_output {

struct pause_data pause;

struct deque audio_buffer[MAX_AUDIO_MIXES][MAX_AV_PLANES];
struct deque audio_buffer[MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES][MAX_AV_PLANES];
uint64_t audio_start_ts;
uint64_t video_start_ts;
size_t audio_size;
Expand Down
8 changes: 4 additions & 4 deletions libobs/obs-output.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ static inline void free_packets(struct obs_output *output)

static inline void clear_raw_audio_buffers(obs_output_t *output)
{
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
for (size_t i = 0; i < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); i++) {
for (size_t j = 0; j < MAX_AV_PLANES; j++) {
deque_free(&output->audio_buffer[i][j]);
}
Expand Down Expand Up @@ -918,7 +918,7 @@ audio_t *obs_output_audio(const obs_output_t *output)

static inline size_t get_first_mixer(const obs_output_t *output)
{
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
for (size_t i = 0; i < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); i++) {
if ((((size_t)1 << i) & output->mixer_mask) != 0) {
return i;
}
Expand Down Expand Up @@ -2448,7 +2448,7 @@ static inline void start_video_encoders(struct obs_output *output, encoded_callb
static inline void start_raw_audio(obs_output_t *output)
{
if (output->info.raw_audio2) {
for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++) {
for (int idx = 0; idx < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); idx++) {
if ((output->mixer_mask & ((size_t)1 << idx)) != 0) {
audio_output_connect(output->audio, idx, get_audio_conversion(output),
default_raw_audio_callback, output);
Expand Down Expand Up @@ -2824,7 +2824,7 @@ static inline void stop_video_encoders(obs_output_t *output, encoded_callback_t
static inline void stop_raw_audio(obs_output_t *output)
{
if (output->info.raw_audio2) {
for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++) {
for (int idx = 0; idx < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); idx++) {
if ((output->mixer_mask & ((size_t)1 << idx)) != 0) {
audio_output_disconnect(output->audio, idx, default_raw_audio_callback, output);
}
Expand Down
2 changes: 1 addition & 1 deletion libobs/obs-scene.c
Original file line number Diff line number Diff line change
Expand Up @@ -1699,7 +1699,7 @@ static bool scene_audio_render(void *data, uint64_t *ts_out, struct obs_source_a
obs_source_get_audio_mix(source, &child_audio);

if (!source->audio_is_duplicated) {
for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
for (size_t mix = 0; mix < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix++) {
if ((mixers & (1 << mix)) == 0)
continue;

Expand Down
2 changes: 1 addition & 1 deletion libobs/obs-source-transition.c
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,7 @@ static void process_audio(obs_source_t *transition, obs_source_t *child, struct
if (pos > AUDIO_OUTPUT_FRAMES)
return;

for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
for (size_t mix_idx = 0; mix_idx < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix_idx++) {
struct audio_output_data *output = &audio->output[mix_idx];
struct audio_output_data *input = &child_audio.output[mix_idx];

Expand Down
Loading
Loading