Skip to content

Commit f157f00

Browse files
committed
libobs: Add ASIO monitoring track
On windows, this adds an additional audio track (Track 7) which is used to output a mix of monitored sources. Currently the mixing is left to WASAPI on windows for WASAPI monitoring devices. But ASIO SDK doesn't allow multiple clients (although individual drivers might allow it) and therefore can not mix them. So we have to do the mixing on obs side. Signed-off-by: pkv <[email protected]>
1 parent 79fa1af commit f157f00

File tree

8 files changed

+58
-29
lines changed

8 files changed

+58
-29
lines changed

libobs/media-io/audio-io.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ struct audio_output {
7676
audio_input_callback_t input_cb;
7777
void *input_param;
7878
pthread_mutex_t input_mutex;
79-
struct audio_mix mixes[MAX_AUDIO_MIXES];
79+
struct audio_mix mixes[MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES];
8080
};
8181

8282
/* ------------------------------------------------------------------------- */
@@ -133,7 +133,7 @@ static inline void clamp_audio_output(struct audio_output *audio, size_t bytes)
133133
{
134134
size_t float_size = bytes / sizeof(float);
135135

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

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

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

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

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

200200
/* output */
201-
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++)
201+
for (size_t i = 0; i < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); i++)
202202
do_audio_output(audio, i, new_ts, AUDIO_OUTPUT_FRAMES);
203203
}
204204

@@ -291,7 +291,7 @@ bool audio_output_connect(audio_t *audio, size_t mi, const struct audio_convert_
291291
{
292292
bool success = false;
293293

294-
if (!audio || mi >= MAX_AUDIO_MIXES)
294+
if (!audio || mi >= (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES))
295295
return false;
296296

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

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

336336
pthread_mutex_lock(&audio->input_mutex);
@@ -403,7 +403,7 @@ void audio_output_close(audio_t *audio)
403403
pthread_mutex_destroy(&audio->input_mutex);
404404
}
405405

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

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

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

430430
if (mix->inputs.num != 0)

libobs/media-io/audio-io.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,20 @@
2424
#ifdef __cplusplus
2525
extern "C" {
2626
#endif
27+
#ifdef _WIN32
28+
// extra track for ASIO monitoring on windows only
29+
#define MAX_AUDIO_MONITORING_MIXES 1
30+
#else
31+
#define MAX_AUDIO_MONITORING_MIXES 0
32+
#endif
2733

2834
#define MAX_AUDIO_MIXES 6
35+
2936
#define MAX_AUDIO_CHANNELS 8
3037
#define MAX_DEVICE_INPUT_CHANNELS 64
3138
#define AUDIO_OUTPUT_FRAMES 1024
3239

33-
#define TOTAL_AUDIO_SIZE (MAX_AUDIO_MIXES * MAX_AUDIO_CHANNELS * AUDIO_OUTPUT_FRAMES * sizeof(float))
40+
#define TOTAL_AUDIO_SIZE ((MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES) * MAX_AUDIO_CHANNELS * AUDIO_OUTPUT_FRAMES * sizeof(float))
3441

3542
/*
3643
* Base audio output component. Use this to create an audio output track

libobs/obs-audio.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ static inline void mix_audio(struct audio_output_data *mixes, obs_source_t *sour
153153
total_floats -= start_point;
154154
}
155155

156-
for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
156+
for (size_t mix_idx = 0; mix_idx < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix_idx++) {
157157
for (size_t ch = 0; ch < channels; ch++) {
158158
register float *mix = mixes[mix_idx].data[ch];
159159
register float *aud = source->audio_output_buf[mix_idx][ch];

libobs/obs-internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,7 @@ struct obs_source {
869869
struct deque audio_input_buf[MAX_AUDIO_CHANNELS];
870870
size_t last_audio_input_buf_size;
871871
DARRAY(struct audio_action) audio_actions;
872-
float *audio_output_buf[MAX_AUDIO_MIXES][MAX_AUDIO_CHANNELS];
872+
float *audio_output_buf[MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES][MAX_AUDIO_CHANNELS];
873873
float *audio_mix_buf[MAX_AUDIO_CHANNELS];
874874
struct resample_info sample_info;
875875
audio_resampler_t *resampler;
@@ -1258,7 +1258,7 @@ struct obs_output {
12581258

12591259
struct pause_data pause;
12601260

1261-
struct deque audio_buffer[MAX_AUDIO_MIXES][MAX_AV_PLANES];
1261+
struct deque audio_buffer[MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES][MAX_AV_PLANES];
12621262
uint64_t audio_start_ts;
12631263
uint64_t video_start_ts;
12641264
size_t audio_size;

libobs/obs-output.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ static inline void free_packets(struct obs_output *output)
269269

270270
static inline void clear_raw_audio_buffers(obs_output_t *output)
271271
{
272-
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
272+
for (size_t i = 0; i < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); i++) {
273273
for (size_t j = 0; j < MAX_AV_PLANES; j++) {
274274
deque_free(&output->audio_buffer[i][j]);
275275
}
@@ -918,7 +918,7 @@ audio_t *obs_output_audio(const obs_output_t *output)
918918

919919
static inline size_t get_first_mixer(const obs_output_t *output)
920920
{
921-
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
921+
for (size_t i = 0; i < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); i++) {
922922
if ((((size_t)1 << i) & output->mixer_mask) != 0) {
923923
return i;
924924
}
@@ -2448,7 +2448,7 @@ static inline void start_video_encoders(struct obs_output *output, encoded_callb
24482448
static inline void start_raw_audio(obs_output_t *output)
24492449
{
24502450
if (output->info.raw_audio2) {
2451-
for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++) {
2451+
for (int idx = 0; idx < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); idx++) {
24522452
if ((output->mixer_mask & ((size_t)1 << idx)) != 0) {
24532453
audio_output_connect(output->audio, idx, get_audio_conversion(output),
24542454
default_raw_audio_callback, output);
@@ -2824,7 +2824,7 @@ static inline void stop_video_encoders(obs_output_t *output, encoded_callback_t
28242824
static inline void stop_raw_audio(obs_output_t *output)
28252825
{
28262826
if (output->info.raw_audio2) {
2827-
for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++) {
2827+
for (int idx = 0; idx < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); idx++) {
28282828
if ((output->mixer_mask & ((size_t)1 << idx)) != 0) {
28292829
audio_output_disconnect(output->audio, idx, default_raw_audio_callback, output);
28302830
}

libobs/obs-source-transition.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,7 @@ static void process_audio(obs_source_t *transition, obs_source_t *child, struct
869869
if (pos > AUDIO_OUTPUT_FRAMES)
870870
return;
871871

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

libobs/obs-source.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,11 @@ enum obs_module_load_state obs_source_load_state(const char *id)
172172

173173
static void allocate_audio_output_buffer(struct obs_source *source)
174174
{
175-
size_t size = sizeof(float) * AUDIO_OUTPUT_FRAMES * MAX_AUDIO_CHANNELS * MAX_AUDIO_MIXES;
175+
size_t size = sizeof(float) * AUDIO_OUTPUT_FRAMES * MAX_AUDIO_CHANNELS *
176+
(MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES);
176177
float *ptr = bzalloc(size);
177178

178-
for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
179+
for (size_t mix = 0; mix < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix++) {
179180
size_t mix_pos = mix * AUDIO_OUTPUT_FRAMES * MAX_AUDIO_CHANNELS;
180181

181182
for (size_t i = 0; i < MAX_AUDIO_CHANNELS; i++) {
@@ -5224,7 +5225,7 @@ static void apply_audio_actions(obs_source_t *source, size_t channels, size_t sa
52245225

52255226
pthread_mutex_unlock(&source->audio_actions_mutex);
52265227

5227-
for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
5228+
for (size_t mix = 0; mix < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix++) {
52285229
if ((source->audio_mixers & (1 << mix)) != 0)
52295230
multiply_vol_data(source, mix, channels, vol_data);
52305231
}
@@ -5259,11 +5260,12 @@ static void apply_audio_volume(obs_source_t *source, uint32_t mixers, size_t cha
52595260

52605261
if (vol == 0.0f || mixers == 0) {
52615262
memset(source->audio_output_buf[0][0], 0,
5262-
AUDIO_OUTPUT_FRAMES * sizeof(float) * MAX_AUDIO_CHANNELS * MAX_AUDIO_MIXES);
5263+
AUDIO_OUTPUT_FRAMES * sizeof(float) * MAX_AUDIO_CHANNELS *
5264+
(MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES));
52635265
return;
52645266
}
52655267

5266-
for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
5268+
for (size_t mix = 0; mix < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix++) {
52675269
uint32_t mix_and_val = (1 << mix);
52685270
if ((source->audio_mixers & mix_and_val) != 0 && (mixers & mix_and_val) != 0)
52695271
multiply_output_audio(source, mix, channels, vol);
@@ -5276,7 +5278,7 @@ static void custom_audio_render(obs_source_t *source, uint32_t mixers, size_t ch
52765278
bool success;
52775279
uint64_t ts;
52785280

5279-
for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
5281+
for (size_t mix = 0; mix < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix++) {
52805282
for (size_t ch = 0; ch < channels; ch++) {
52815283
audio_data.output[mix].data[ch] = source->audio_output_buf[mix][ch];
52825284
}
@@ -5293,7 +5295,7 @@ static void custom_audio_render(obs_source_t *source, uint32_t mixers, size_t ch
52935295
if (!success || !source->audio_ts || !mixers)
52945296
return;
52955297

5296-
for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
5298+
for (size_t mix = 0; mix < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix++) {
52975299
uint32_t mix_bit = 1 << mix;
52985300

52995301
if ((mixers & mix_bit) == 0)
@@ -5355,7 +5357,7 @@ static inline void process_audio_source_tick(obs_source_t *source, uint32_t mixe
53555357

53565358
pthread_mutex_unlock(&source->audio_buf_mutex);
53575359

5358-
for (size_t mix = 1; mix < MAX_AUDIO_MIXES; mix++) {
5360+
for (size_t mix = 1; mix < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix++) {
53595361
uint32_t mix_and_val = (1 << mix);
53605362

53615363
if (audio_submix) {
@@ -5435,7 +5437,7 @@ void obs_source_get_audio_mix(const obs_source_t *source, struct obs_source_audi
54355437
if (!obs_ptr_valid(audio, "audio"))
54365438
return;
54375439

5438-
for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
5440+
for (size_t mix = 0; mix < (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES); mix++) {
54395441
for (size_t ch = 0; ch < MAX_AUDIO_CHANNELS; ch++) {
54405442
audio->output[mix].data[ch] = source->audio_output_buf[mix][ch];
54415443
}
@@ -5519,10 +5521,30 @@ void obs_source_set_monitoring_type(obs_source_t *source, enum obs_monitoring_ty
55195521
}
55205522

55215523
source->monitoring_type = type;
5524+
5525+
#ifdef _WIN32
5526+
// On windows, assign to the extra asio monitoring track (track 7) all sources which have not type
5527+
// OBS_MONITORING_TYPE_NONE.
5528+
if (type != OBS_MONITORING_TYPE_NONE) {
5529+
source->audio_mixers |= 1 << (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES - 1);
5530+
} else {
5531+
source->audio_mixers &= ~(1 << (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES - 1));
5532+
}
5533+
#endif
55225534
}
55235535

55245536
enum obs_monitoring_type obs_source_get_monitoring_type(const obs_source_t *source)
55255537
{
5538+
#ifdef _WIN32
5539+
// If type is OBS_MONITORING_TYPE_NONE, unselect the extra asio monitoring track (track 7) on windows.
5540+
uint32_t mixers = obs_source_get_audio_mixers(source);
5541+
if (source->monitoring_type == OBS_MONITORING_TYPE_NONE && mixers) {
5542+
if (mixers & 1 << (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES - 1)) {
5543+
mixers &= ~(1 << (MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES - 1));
5544+
obs_source_set_audio_mixers((obs_source_t *)source, mixers);
5545+
}
5546+
}
5547+
#endif
55265548
return obs_source_valid(source, "obs_source_get_monitoring_type") ? source->monitoring_type
55275549
: OBS_MONITORING_TYPE_NONE;
55285550
}

libobs/obs-source.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ enum obs_media_state {
213213
typedef void (*obs_source_enum_proc_t)(obs_source_t *parent, obs_source_t *child, void *param);
214214

215215
struct obs_source_audio_mix {
216-
struct audio_output_data output[MAX_AUDIO_MIXES];
216+
struct audio_output_data output[MAX_AUDIO_MIXES + MAX_AUDIO_MONITORING_MIXES];
217217
};
218218

219219
/**

0 commit comments

Comments
 (0)