소스 검색

UI: Enable audio multi-track w/ mpegts streaming

This enables audio multi-track support in UI for mpegts streams (srt,
rist ...).
The UI changes were coded though to allow re-use by other protocols.

Signed-off-by: pkv <[email protected]>
pkv 3 년 전
부모
커밋
f186268507
6개의 변경된 파일294개의 추가작업 그리고 86개의 파일을 삭제
  1. 130 55
      UI/forms/OBSBasicSettings.ui
  2. 105 28
      UI/window-basic-main-outputs.cpp
  3. 2 1
      UI/window-basic-main.cpp
  4. 1 0
      UI/window-basic-settings-stream.cpp
  5. 55 2
      UI/window-basic-settings.cpp
  6. 1 0
      UI/window-basic-settings.hpp

+ 130 - 55
UI/forms/OBSBasicSettings.ui

@@ -2432,73 +2432,142 @@
                             </widget>
                            </item>
                            <item row="1" column="1">
-                            <widget class="QFrame" name="widget_8">
+                            <widget class="QStackedWidget" name="advStreamTrackWidget">
                              <property name="sizePolicy">
                               <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
                                <horstretch>0</horstretch>
                                <verstretch>0</verstretch>
                               </sizepolicy>
                              </property>
-                             <layout class="QHBoxLayout" name="horizontalLayout_7">
-                              <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 name="currentIndex">
+                              <number>0</number>
+                             </property>
+                             <widget class="QFrame" name="streamSingleTracks">
+                              <property name="sizePolicy">
+                               <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+                                <horstretch>0</horstretch>
+                                <verstretch>0</verstretch>
+                               </sizepolicy>
                               </property>
-                              <item>
-                               <widget class="QRadioButton" name="advOutTrack1">
-                                <property name="text">
-                                 <string notr="true">1</string>
-                                </property>
-                                <property name="checked">
-                                 <bool>true</bool>
-                                </property>
-                               </widget>
-                              </item>
-                              <item>
-                               <widget class="QRadioButton" name="advOutTrack2">
-                                <property name="text">
-                                 <string notr="true">2</string>
-                                </property>
-                               </widget>
+                              <layout class="QHBoxLayout" name="horizontalLayout_7">
+                               <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="QRadioButton" name="advOutTrack1">
+                                 <property name="text">
+                                  <string notr="true">1</string>
+                                 </property>
+                                 <property name="checked">
+                                  <bool>true</bool>
+                                 </property>
+                                </widget>
+                               </item>
+                               <item>
+                                <widget class="QRadioButton" name="advOutTrack2">
+                                 <property name="text">
+                                  <string notr="true">2</string>
+                                 </property>
+                                </widget>
+                               </item>
+                               <item>
+                                <widget class="QRadioButton" name="advOutTrack3">
+                                 <property name="text">
+                                  <string notr="true">3</string>
+                                 </property>
+                                </widget>
                               </item>
-                              <item>
-                               <widget class="QRadioButton" name="advOutTrack3">
-                                <property name="text">
-                                 <string notr="true">3</string>
+                               <item>
+                                <widget class="QRadioButton" name="advOutTrack4">
+                                 <property name="text">
+                                  <string notr="true">4</string>
+                                 </property>
+                                </widget>
+                               </item>
+                               <item>
+                                <widget class="QRadioButton" name="advOutTrack5">
+                                 <property name="text">
+                                  <string notr="true">5</string>
+                                 </property>
+                                </widget>
+                               </item>
+                               <item>
+                                <widget class="QRadioButton" name="advOutTrack6">
+                                 <property name="text">
+                                  <string notr="true">6</string>
+                                 </property>
+                                </widget>
+                               </item>
+                              </layout>
+                             </widget>
+                             <widget class="QWidget" name="streamMultiTracks">
+                               <layout class="QHBoxLayout" name="horizontalLayout_multitrack">
+                                <property name="leftMargin">
+                                 <number>0</number>
                                 </property>
-                               </widget>
-                              </item>
-                              <item>
-                               <widget class="QRadioButton" name="advOutTrack4">
-                                <property name="text">
-                                 <string notr="true">4</string>
+                                <property name="topMargin">
+                                 <number>0</number>
                                 </property>
-                               </widget>
-                              </item>
-                              <item>
-                               <widget class="QRadioButton" name="advOutTrack5">
-                                <property name="text">
-                                 <string notr="true">5</string>
+                                <property name="rightMargin">
+                                 <number>0</number>
                                 </property>
-                               </widget>
-                              </item>
-                              <item>
-                               <widget class="QRadioButton" name="advOutTrack6">
-                                <property name="text">
-                                 <string notr="true">6</string>
+                                <property name="bottomMargin">
+                                 <number>0</number>
                                 </property>
-                               </widget>
-                              </item>
-                             </layout>
-                            </widget>
+                                <item>
+                                 <widget class="QCheckBox" name="advOutMultiTrack1">
+                                  <property name="text">
+                                   <string notr="true">1</string>
+                                  </property>
+                                 </widget>
+                                </item>
+                                <item>
+                                 <widget class="QCheckBox" name="advOutMultiTrack2">
+                                  <property name="text">
+                                   <string notr="true">2</string>
+                                  </property>
+                                 </widget>
+                                </item>
+                                <item>
+                                 <widget class="QCheckBox" name="advOutMultiTrack3">
+                                  <property name="text">
+                                   <string notr="true">3</string>
+                                  </property>
+                                 </widget>
+                                </item>
+                                <item>
+                                 <widget class="QCheckBox" name="advOutMultiTrack4">
+                                  <property name="text">
+                                   <string notr="true">4</string>
+                                  </property>
+                                 </widget>
+                                </item>
+                                <item>
+                                 <widget class="QCheckBox" name="advOutMultiTrack5">
+                                  <property name="text">
+                                   <string notr="true">5</string>
+                                  </property>
+                                 </widget>
+                                </item>
+                                <item>
+                                 <widget class="QCheckBox" name="advOutMultiTrack6">
+                                  <property name="text">
+                                   <string notr="true">6</string>
+                                  </property>
+                                 </widget>
+                                </item>
+                               </layout>
+                              </widget>
+			    </widget>
                            </item>
                            <item row="2" column="0">
                             <widget class="QLabel" name="advOutAEncLabel">
@@ -7861,6 +7930,12 @@
   <tabstop>advOutTrack4</tabstop>
   <tabstop>advOutTrack5</tabstop>
   <tabstop>advOutTrack6</tabstop>
+  <tabstop>advOutMultiTrack1</tabstop>
+  <tabstop>advOutMultiTrack2</tabstop>
+  <tabstop>advOutMultiTrack3</tabstop>
+  <tabstop>advOutMultiTrack4</tabstop>
+  <tabstop>advOutMultiTrack5</tabstop>
+  <tabstop>advOutMultiTrack6</tabstop>
   <tabstop>advOutEncoder</tabstop>
   <tabstop>advOutUseRescale</tabstop>
   <tabstop>advOutRescale</tabstop>

+ 105 - 28
UI/window-basic-main-outputs.cpp

@@ -19,6 +19,8 @@ volatile bool virtualcam_active = false;
 
 #define FTL_PROTOCOL "ftl"
 #define RTMP_PROTOCOL "rtmp"
+#define SRT_PROTOCOL "srt"
+#define RIST_PROTOCOL "rist"
 
 static void OBSStreamStarting(void *data, calldata_t *params)
 {
@@ -1473,6 +1475,7 @@ bool SimpleOutput::ReplayBufferActive() const
 struct AdvancedOutput : BasicOutputHandler {
 	OBSEncoder streamAudioEnc;
 	OBSEncoder streamArchiveEnc;
+	OBSEncoder streamTrack[MAX_AUDIO_MIXES];
 	OBSEncoder recordTrack[MAX_AUDIO_MIXES];
 	OBSEncoder videoStreaming;
 	OBSEncoder videoRecording;
@@ -1508,6 +1511,7 @@ struct AdvancedOutput : BasicOutputHandler {
 	virtual bool StreamingActive() const override;
 	virtual bool RecordingActive() const override;
 	virtual bool ReplayBufferActive() const override;
+	bool allowsMultiTrack();
 };
 
 static OBSData GetDataFromJsonFile(const char *jsonFile)
@@ -1669,14 +1673,25 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
 		}
 
 		obs_encoder_release(recordTrack[i]);
+
+		snprintf(name, sizeof(name), "adv_stream_audio_%d", i);
+		streamTrack[i] = obs_audio_encoder_create(
+			streamAudioEncoder, name, nullptr, i, nullptr);
+
+		if (!streamTrack[i]) {
+			throw "Failed to create streaming audio encoders "
+			      "(advanced output)";
+		}
+
+		obs_encoder_release(streamTrack[i]);
 	}
 
 	std::string id;
-	int streamTrack =
+	int streamTrackIndex =
 		config_get_int(main->Config(), "AdvOut", "TrackIndex") - 1;
 	streamAudioEnc = obs_audio_encoder_create(streamAudioEncoder,
 						  "adv_stream_audio", nullptr,
-						  streamTrack, nullptr);
+						  streamTrackIndex, nullptr);
 	if (!streamAudioEnc)
 		throw "Failed to create streaming audio encoder "
 		      "(advanced output)";
@@ -1782,13 +1797,28 @@ static inline bool ServiceSupportsVodTrack(const char *service)
 	return false;
 }
 
+inline bool AdvancedOutput::allowsMultiTrack()
+{
+	const char *protocol = nullptr;
+	obs_service_t *service_obj = main->GetService();
+	protocol = obs_service_get_protocol(service_obj);
+	if (!protocol)
+		return false;
+	return astrcmpi_n(protocol, SRT_PROTOCOL, strlen(SRT_PROTOCOL)) == 0 ||
+	       astrcmpi_n(protocol, RIST_PROTOCOL, strlen(RIST_PROTOCOL)) == 0;
+}
+
 inline void AdvancedOutput::SetupStreaming()
 {
 	bool rescale = config_get_bool(main->Config(), "AdvOut", "Rescale");
 	const char *rescaleRes =
 		config_get_string(main->Config(), "AdvOut", "RescaleRes");
+	int multiTrackAudioMixes = config_get_int(main->Config(), "AdvOut",
+						  "StreamMultiTrackAudioMixes");
 	unsigned int cx = 0;
 	unsigned int cy = 0;
+	int idx = 0;
+	bool is_multitrack_output = allowsMultiTrack();
 
 	if (rescale && rescaleRes && *rescaleRes) {
 		if (sscanf(rescaleRes, "%ux%u", &cx, &cy) != 2) {
@@ -1797,7 +1827,18 @@ inline void AdvancedOutput::SetupStreaming()
 		}
 	}
 
-	obs_output_set_audio_encoder(streamOutput, streamAudioEnc, 0);
+	if (!is_multitrack_output) {
+		obs_output_set_audio_encoder(streamOutput, streamAudioEnc, 0);
+	} else {
+		for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
+			if ((multiTrackAudioMixes & (1 << i)) != 0) {
+				obs_output_set_audio_encoder(
+					streamOutput, streamTrack[i], idx);
+				idx++;
+			}
+		}
+	}
+
 	obs_encoder_set_scaled_size(videoStreaming, cx, cy);
 
 	const char *id = obs_service_get_id(main->GetService());
@@ -1988,6 +2029,9 @@ inline void AdvancedOutput::UpdateAudioSettings()
 		config_get_string(main->Config(), "AdvOut", "AudioEncoder");
 	const char *recAudioEncoder =
 		config_get_string(main->Config(), "AdvOut", "RecAudioEncoder");
+
+	bool is_multitrack_output = allowsMultiTrack();
+
 	OBSDataAutoRelease settings[MAX_AUDIO_MIXES];
 
 	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
@@ -2000,6 +2044,7 @@ inline void AdvancedOutput::UpdateAudioSettings()
 		string def_name = "Track";
 		def_name += to_string((int)i + 1);
 		SetEncoderName(recordTrack[i], name, def_name.c_str());
+		SetEncoderName(streamTrack[i], name, def_name.c_str());
 	}
 
 	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
@@ -2013,24 +2058,31 @@ inline void AdvancedOutput::UpdateAudioSettings()
 		obs_data_set_int(settings[i], "bitrate",
 				 GetAudioBitrate(i, audioEncoder));
 
-		if (track == streamTrackIndex || track == vodTrackIndex) {
-			if (applyServiceSettings) {
-				int bitrate = (int)obs_data_get_int(settings[i],
-								    "bitrate");
-				obs_service_apply_encoder_settings(
-					main->GetService(), nullptr,
-					settings[i]);
-
-				if (!enforceBitrate)
-					obs_data_set_int(settings[i], "bitrate",
-							 bitrate);
+		if (!is_multitrack_output) {
+			if (track == streamTrackIndex ||
+			    track == vodTrackIndex) {
+				if (applyServiceSettings) {
+					int bitrate = (int)obs_data_get_int(
+						settings[i], "bitrate");
+					obs_service_apply_encoder_settings(
+						main->GetService(), nullptr,
+						settings[i]);
+
+					if (!enforceBitrate)
+						obs_data_set_int(settings[i],
+								 "bitrate",
+								 bitrate);
+				}
 			}
-		}
 
-		if (track == streamTrackIndex)
-			obs_encoder_update(streamAudioEnc, settings[i]);
-		if (track == vodTrackIndex)
-			obs_encoder_update(streamArchiveEnc, settings[i]);
+			if (track == streamTrackIndex)
+				obs_encoder_update(streamAudioEnc, settings[i]);
+			if (track == vodTrackIndex)
+				obs_encoder_update(streamArchiveEnc,
+						   settings[i]);
+		} else {
+			obs_encoder_update(streamTrack[i], settings[i]);
+		}
 	}
 }
 
@@ -2039,8 +2091,10 @@ void AdvancedOutput::SetupOutputs()
 	obs_encoder_set_video(videoStreaming, obs_get_video());
 	if (videoRecording)
 		obs_encoder_set_video(videoRecording, obs_get_video());
-	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++)
+	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
+		obs_encoder_set_audio(streamTrack[i], obs_get_audio());
 		obs_encoder_set_audio(recordTrack[i], obs_get_audio());
+	}
 	obs_encoder_set_audio(streamAudioEnc, obs_get_audio());
 	obs_encoder_set_audio(streamArchiveEnc, obs_get_audio());
 
@@ -2064,7 +2118,7 @@ int AdvancedOutput::GetAudioBitrate(size_t i, const char *id) const
 
 inline void AdvancedOutput::SetupVodTrack(obs_service_t *service)
 {
-	int streamTrack =
+	int streamTrackIndex =
 		config_get_int(main->Config(), "AdvOut", "TrackIndex");
 	bool vodTrackEnabled =
 		config_get_bool(main->Config(), "AdvOut", "VodTrackEnabled");
@@ -2083,8 +2137,7 @@ inline void AdvancedOutput::SetupVodTrack(obs_service_t *service)
 		if (!ServiceSupportsVodTrack(service))
 			vodTrackEnabled = false;
 	}
-
-	if (vodTrackEnabled && streamTrack != vodTrackIndex)
+	if (vodTrackEnabled && streamTrackIndex != vodTrackIndex)
 		obs_output_set_audio_encoder(streamOutput, streamArchiveEnc, 1);
 	else
 		clear_archive_encoder(streamOutput, ADV_ARCHIVE_NAME);
@@ -2092,6 +2145,12 @@ inline void AdvancedOutput::SetupVodTrack(obs_service_t *service)
 
 bool AdvancedOutput::SetupStreaming(obs_service_t *service)
 {
+	int multiTrackAudioMixes = config_get_int(main->Config(), "AdvOut",
+						  "StreamMultiTrackAudioMixes");
+	int idx = 0;
+
+	bool is_multitrack_output = allowsMultiTrack();
+
 	if (!useStreamEncoder ||
 	    (!ffmpegOutput && !obs_output_active(fileOutput))) {
 		UpdateStreamSettings();
@@ -2147,8 +2206,17 @@ bool AdvancedOutput::SetupStreaming(obs_service_t *service)
 	}
 
 	obs_output_set_video_encoder(streamOutput, videoStreaming);
-	obs_output_set_audio_encoder(streamOutput, streamAudioEnc, 0);
-
+	if (!is_multitrack_output) {
+		obs_output_set_audio_encoder(streamOutput, streamAudioEnc, 0);
+	} else {
+		for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
+			if ((multiTrackAudioMixes & (1 << i)) != 0) {
+				obs_output_set_audio_encoder(
+					streamOutput, streamTrack[i], idx);
+				idx++;
+			}
+		}
+	}
 	return true;
 }
 
@@ -2177,6 +2245,15 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
 	bool enableDynBitrate =
 		config_get_bool(main->Config(), "Output", "DynamicBitrate");
 
+	bool is_rtmp = false;
+	obs_service_t *service_obj = main->GetService();
+	const char *protocol = obs_service_get_protocol(service_obj);
+	if (protocol) {
+		if (strncmp(protocol, RTMP_PROTOCOL, strlen(RTMP_PROTOCOL)) ==
+		    0)
+			is_rtmp = true;
+	}
+
 	OBSDataAutoRelease settings = obs_data_create();
 	obs_data_set_string(settings, "bind_ip", bindIP);
 	obs_data_set_string(settings, "ip_family", ipFamily);
@@ -2196,9 +2273,9 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
 			     preserveDelay ? OBS_OUTPUT_DELAY_PRESERVE : 0);
 
 	obs_output_set_reconnect_settings(streamOutput, maxRetries, retryDelay);
-
-	SetupVodTrack(service);
-
+	if (is_rtmp) {
+		SetupVodTrack(service);
+	}
 	if (obs_output_start(streamOutput)) {
 		return true;
 	}

+ 2 - 1
UI/window-basic-main.cpp

@@ -1650,7 +1650,8 @@ bool OBSBasic::InitBasicConfigDefaults()
 	config_set_default_uint(basicConfig, "AdvOut", "RecTracks", (1 << 0));
 	config_set_default_string(basicConfig, "AdvOut", "RecEncoder", "none");
 	config_set_default_uint(basicConfig, "AdvOut", "FLVTrack", 1);
-
+	config_set_default_uint(basicConfig, "AdvOut",
+				"StreamMultiTrackAudioMixes", 1);
 	config_set_default_bool(basicConfig, "AdvOut", "FFOutputToFile", true);
 	config_set_default_string(basicConfig, "AdvOut", "FFFilePath",
 				  GetDefaultVideoSavePath().c_str());

+ 1 - 0
UI/window-basic-settings-stream.cpp

@@ -255,6 +255,7 @@ void OBSBasicSettings::SaveStream1Settings()
 
 	main->SetService(newService);
 	main->SaveService();
+	LoadOutputSettings();
 	main->auth = auth;
 	if (!!main->auth) {
 		main->auth->LoadUI();

+ 55 - 2
UI/window-basic-settings.cpp

@@ -450,6 +450,12 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
 	HookWidget(ui->advOutTrack4,         CHECK_CHANGED,  OUTPUTS_CHANGED);
 	HookWidget(ui->advOutTrack5,         CHECK_CHANGED,  OUTPUTS_CHANGED);
 	HookWidget(ui->advOutTrack6,         CHECK_CHANGED,  OUTPUTS_CHANGED);
+	HookWidget(ui->advOutMultiTrack1,    CHECK_CHANGED,  OUTPUTS_CHANGED);
+	HookWidget(ui->advOutMultiTrack2,    CHECK_CHANGED,  OUTPUTS_CHANGED);
+	HookWidget(ui->advOutMultiTrack3,    CHECK_CHANGED,  OUTPUTS_CHANGED);
+	HookWidget(ui->advOutMultiTrack4,    CHECK_CHANGED,  OUTPUTS_CHANGED);
+	HookWidget(ui->advOutMultiTrack5,    CHECK_CHANGED,  OUTPUTS_CHANGED);
+	HookWidget(ui->advOutMultiTrack6,    CHECK_CHANGED,  OUTPUTS_CHANGED);
 	HookWidget(ui->advOutRecType,        COMBO_CHANGED,  OUTPUTS_CHANGED);
 	HookWidget(ui->advOutRecPath,        EDIT_CHANGED,   OUTPUTS_CHANGED);
 	HookWidget(ui->advOutNoSpace,        CHECK_CHANGED,  OUTPUTS_CHANGED);
@@ -2022,13 +2028,24 @@ static inline QString makeFormatToolTip()
 	return html;
 }
 
+#define RTMP_PROTOCOL "rtmp"
+#define SRT_PROTOCOL "srt"
+#define RIST_PROTOCOL "rist"
+
+inline bool allowsMultiTrack(const char *protocol)
+{
+	return astrcmpi_n(protocol, SRT_PROTOCOL, strlen(SRT_PROTOCOL)) == 0 ||
+	       astrcmpi_n(protocol, RIST_PROTOCOL, strlen(RIST_PROTOCOL)) == 0;
+}
+
 void OBSBasicSettings::LoadAdvOutputStreamingSettings()
 {
 	bool rescale = config_get_bool(main->Config(), "AdvOut", "Rescale");
 	const char *rescaleRes =
 		config_get_string(main->Config(), "AdvOut", "RescaleRes");
 	int trackIndex = config_get_int(main->Config(), "AdvOut", "TrackIndex");
-
+	int audioMixes = config_get_int(main->Config(), "AdvOut",
+					"StreamMultiTrackAudioMixes");
 	ui->advOutUseRescale->setChecked(rescale);
 	ui->advOutRescale->setEnabled(rescale);
 	ui->advOutRescale->setCurrentText(rescaleRes);
@@ -2061,6 +2078,28 @@ void OBSBasicSettings::LoadAdvOutputStreamingSettings()
 		ui->advOutTrack6->setChecked(true);
 		break;
 	}
+	ui->advOutMultiTrack1->setChecked(audioMixes & (1 << 0));
+	ui->advOutMultiTrack2->setChecked(audioMixes & (1 << 1));
+	ui->advOutMultiTrack3->setChecked(audioMixes & (1 << 2));
+	ui->advOutMultiTrack4->setChecked(audioMixes & (1 << 3));
+	ui->advOutMultiTrack5->setChecked(audioMixes & (1 << 4));
+	ui->advOutMultiTrack6->setChecked(audioMixes & (1 << 5));
+
+	bool is_multitrack_output = false;
+	obs_service_t *service_obj = main->GetService();
+	const char *protocol = nullptr;
+	protocol = obs_service_get_protocol(service_obj);
+	if (protocol) {
+		is_multitrack_output = allowsMultiTrack(protocol);
+	}
+
+	if (is_multitrack_output) {
+		ui->advStreamTrackWidget->setCurrentWidget(
+			ui->streamMultiTracks);
+	} else {
+		ui->advStreamTrackWidget->setCurrentWidget(
+			ui->streamSingleTracks);
+	}
 }
 
 OBSPropertiesView *
@@ -3821,7 +3860,8 @@ void OBSBasicSettings::SaveOutputSettings()
 	SaveTrackIndex(main->Config(), "AdvOut", "TrackIndex", ui->advOutTrack1,
 		       ui->advOutTrack2, ui->advOutTrack3, ui->advOutTrack4,
 		       ui->advOutTrack5, ui->advOutTrack6);
-
+	config_set_int(main->Config(), "AdvOut", "StreamMultiTrackAudioMixes",
+		       AdvOutGetStreamingSelectedAudioTracks());
 	config_set_string(main->Config(), "AdvOut", "RecType",
 			  RecTypeFromIdx(ui->advOutRecType->currentIndex()));
 
@@ -4191,6 +4231,8 @@ bool OBSBasicSettings::QueryAllowedToClose()
 		QString format = ui->advOutRecFormat->currentData().toString();
 		if (AdvOutGetSelectedAudioTracks() == 0 && format != "flv")
 			invalidTracks = true;
+		if (AdvOutGetStreamingSelectedAudioTracks() == 0)
+			invalidTracks = true;
 	}
 
 	if (invalidEncoder) {
@@ -6135,6 +6177,17 @@ int OBSBasicSettings::AdvOutGetSelectedAudioTracks()
 	return tracks;
 }
 
+int OBSBasicSettings::AdvOutGetStreamingSelectedAudioTracks()
+{
+	int tracks = (ui->advOutMultiTrack1->isChecked() ? (1 << 0) : 0) |
+		     (ui->advOutMultiTrack2->isChecked() ? (1 << 1) : 0) |
+		     (ui->advOutMultiTrack3->isChecked() ? (1 << 2) : 0) |
+		     (ui->advOutMultiTrack4->isChecked() ? (1 << 3) : 0) |
+		     (ui->advOutMultiTrack5->isChecked() ? (1 << 4) : 0) |
+		     (ui->advOutMultiTrack6->isChecked() ? (1 << 5) : 0);
+	return tracks;
+}
+
 /* Using setEditable(true) on a QComboBox when there's a custom style in use
  * does not work properly, so instead completely recreate the widget, which
  * seems to work fine. */

+ 1 - 0
UI/window-basic-settings.hpp

@@ -375,6 +375,7 @@ private:
 	int CurrentFLVTrack();
 	int SimpleOutGetSelectedAudioTracks();
 	int AdvOutGetSelectedAudioTracks();
+	int AdvOutGetStreamingSelectedAudioTracks();
 
 	OBSService GetStream1Service();