diff --git a/docs/sphinx/reference-outputs.rst b/docs/sphinx/reference-outputs.rst index 404dd23cabd0877942c674af67cf43038e9df2db..70213a8ab8ba36ff21524f99b05fceefac59726a 100644 --- a/docs/sphinx/reference-outputs.rst +++ b/docs/sphinx/reference-outputs.rst @@ -117,6 +117,18 @@ Output Definition Structure (obs_output_info) This is called when the output recieves raw audio data. Only applies to outputs that are not encoded. + **This callback must be used with single-track raw outputs.** + + :param frames: The raw audio frames + +.. member:: void (*obs_output_info.raw_audio2)(void *data, size_t idx, struct audio_data *frames) + + This is called when the output recieves raw audio data. Only applies + to outputs that are not encoded. + + **This callback must be used with multi-track raw outputs.** + + :param idx: The audio track index :param frames: The raw audio frames .. member:: void (*obs_output_info.encoded_packet)(void *data, struct encoder_packet *packet) @@ -472,7 +484,19 @@ General Output Functions .. function:: void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx) size_t obs_output_get_mixer(const obs_output_t *output) - Sets/gets the current audio mixer for non-encoded outputs. + Sets/gets the current audio mixer for non-encoded outputs. For + multi-track outputs, this would be the equivalent of setting the mask + only for the specified mixer index. + +--------------------- + +.. function:: void obs_output_set_mixers(obs_output_t *output, size_t mixers) + size_t obs_output_get_mixers(const obs_output_t *output) + + Sets/gets the current audio mixers (via mask) for non-encoded + multi-track outputs. If used with single-track outputs, the + single-track output will use either the first set mixer track in the + bitmask, or the first track if none is set in the bitmask. --------------------- diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 0aea022470bd6c674c2c5c33b696dd5d4df1a7c5..a9bc035bfa643fc1e5fb1838c8b0c08d280da7b5 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -863,7 +863,7 @@ struct obs_output { obs_encoder_t *video_encoder; obs_encoder_t *audio_encoders[MAX_AUDIO_MIXES]; obs_service_t *service; - size_t mixer_idx; + size_t mixer_mask; uint32_t scaled_width; uint32_t scaled_height; diff --git a/libobs/obs-module.c b/libobs/obs-module.c index 41369659c7b880a1f1b3e5cd5bf71081260797fe..68bfe25e4581ed19f06d75a5614f6f0f40a4bd28 100644 --- a/libobs/obs-module.c +++ b/libobs/obs-module.c @@ -675,9 +675,15 @@ void obs_register_output_s(const struct obs_output_info *info, size_t size) CHECK_REQUIRED_VAL_(info, raw_video, obs_register_output); - if (info->flags & OBS_OUTPUT_AUDIO) - CHECK_REQUIRED_VAL_(info, raw_audio, - obs_register_output); + if (info->flags & OBS_OUTPUT_AUDIO) { + if (info->flags & OBS_OUTPUT_MULTI_TRACK) { + CHECK_REQUIRED_VAL_(info, raw_audio2, + obs_register_output); + } else { + CHECK_REQUIRED_VAL_(info, raw_audio, + obs_register_output); + } + } } #undef CHECK_REQUIRED_VAL_ diff --git a/libobs/obs-output.c b/libobs/obs-output.c index f82382fb41290bbfe7b51d9a5a3e29726d3de803..e8cda627acbacd8e4e2f94419901fafe7fc8a8c8 100644 --- a/libobs/obs-output.c +++ b/libobs/obs-output.c @@ -544,19 +544,46 @@ audio_t *obs_output_audio(const obs_output_t *output) output->audio : NULL; } +static inline size_t get_first_mixer(const obs_output_t *output) +{ + for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) { + if ((((size_t)1 << i) & output->mixer_mask) != 0) { + return i; + } + } + + return 0; +} + void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx) { if (!obs_output_valid(output, "obs_output_set_mixer")) return; if (!active(output)) - output->mixer_idx = mixer_idx; + output->mixer_mask = (size_t)1 << mixer_idx; } size_t obs_output_get_mixer(const obs_output_t *output) { - return obs_output_valid(output, "obs_output_get_mixer") ? - output->mixer_idx : 0; + if (!obs_output_valid(output, "obs_output_get_mixer")) + return 0; + + return get_first_mixer(output); +} + +void obs_output_set_mixers(obs_output_t *output, size_t mixers) +{ + if (!obs_output_valid(output, "obs_output_set_mixers")) + return; + + output->mixer_mask = mixers; +} + +size_t obs_output_get_mixers(const obs_output_t *output) +{ + return obs_output_valid(output, "obs_output_get_mixers") ? + output->mixer_mask : 0; } void obs_output_remove_encoder(struct obs_output *output, @@ -1476,6 +1503,7 @@ static void default_raw_video_callback(void *param, struct video_data *frame) output->total_frames++; } + static void default_raw_audio_callback(void *param, size_t mix_idx, struct audio_data *frames) { @@ -1483,9 +1511,10 @@ static void default_raw_audio_callback(void *param, size_t mix_idx, if (!data_active(output)) return; - output->info.raw_audio(output->context.data, frames); - - UNUSED_PARAMETER(mix_idx); + if (output->info.raw_audio2) + output->info.raw_audio2(output->context.data, mix_idx, frames); + else + output->info.raw_audio(output->context.data, frames); } static inline void start_audio_encoders(struct obs_output *output, @@ -1499,6 +1528,25 @@ static inline void start_audio_encoders(struct obs_output *output, } } +static inline void start_raw_audio(obs_output_t *output) +{ + if (output->info.raw_audio2) { + for (int idx = 0; idx < MAX_AUDIO_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); + } + } + } else { + audio_output_connect(output->audio, get_first_mixer(output), + get_audio_conversion(output), + default_raw_audio_callback, + output); + } +} + static void reset_packet_data(obs_output_t *output) { output->received_audio = false; @@ -1557,9 +1605,7 @@ static void hook_data_capture(struct obs_output *output, bool encoded, get_video_conversion(output), default_raw_video_callback, output); if (has_audio) - audio_output_connect(output->audio, output->mixer_idx, - get_audio_conversion(output), - default_raw_audio_callback, output); + start_raw_audio(output); } } @@ -1786,6 +1832,25 @@ static inline void stop_audio_encoders(obs_output_t *output, } } +static inline void stop_raw_audio(obs_output_t *output) +{ + if (output->info.raw_audio2) { + for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++) { + if ((output->mixer_mask & ((size_t)1 << idx)) != 0) { + audio_output_disconnect(output->audio, + idx, + default_raw_audio_callback, + output); + } + } + } else { + audio_output_disconnect(output->audio, + get_first_mixer(output), + default_raw_audio_callback, + output); + } +} + static void *end_data_capture_thread(void *data) { bool encoded, has_video, has_audio, has_service; @@ -1812,9 +1877,7 @@ static void *end_data_capture_thread(void *data) stop_raw_video(output->video, default_raw_video_callback, output); if (has_audio) - audio_output_disconnect(output->audio, - output->mixer_idx, - default_raw_audio_callback, output); + stop_raw_audio(output); } if (has_service) diff --git a/libobs/obs-output.h b/libobs/obs-output.h index df50fa077aeb1cb733368df6c300ccf7d095aff6..db30fe0ab1ced51815d24e01e8080788e7fdeee5 100644 --- a/libobs/obs-output.h +++ b/libobs/obs-output.h @@ -71,6 +71,9 @@ struct obs_output_info { /* only used with encoded outputs, separated with semicolon */ const char *encoded_video_codecs; const char *encoded_audio_codecs; + + /* raw audio callback for multi track outputs */ + void (*raw_audio2)(void *data, size_t idx, struct audio_data *frames); }; EXPORT void obs_register_output_s(const struct obs_output_info *info, diff --git a/libobs/obs.h b/libobs/obs.h index 14db159768c3bd52f5208b116dd7f3a5b3b6385d..8059175c70bcdd7762d0f050d180a73bd3a0c4af 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -1632,6 +1632,12 @@ EXPORT void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx); /** Gets the current audio mixer for non-encoded outputs */ EXPORT size_t obs_output_get_mixer(const obs_output_t *output); +/** Sets the current audio mixes (mask) for a non-encoded multi-track output */ +EXPORT void obs_output_set_mixers(obs_output_t *output, size_t mixers); + +/** Gets the current audio mixes (mask) for a non-encoded multi-track output */ +EXPORT size_t obs_output_get_mixers(const obs_output_t *output); + /** * Sets the current video encoder associated with this output, * required for encoded outputs