2424#include " nodeobs_audio_encoders.h"
2525#include " osn-audio-track.hpp"
2626
27+ #include " osn-multitrack-video.hpp"
28+
2729void osn::IAdvancedStreaming::Register (ipc::server &srv)
2830{
2931 std::shared_ptr<ipc::collection> cls = std::make_shared<ipc::collection>(" AdvancedStreaming" );
@@ -42,6 +44,9 @@ void osn::IAdvancedStreaming::Register(ipc::server &srv)
4244 cls->register_function (std::make_shared<ipc::function>(" GetEnableTwitchVOD" , std::vector<ipc::type>{ipc::type::UInt64}, GetEnableTwitchVOD));
4345 cls->register_function (
4446 std::make_shared<ipc::function>(" SetEnableTwitchVOD" , std::vector<ipc::type>{ipc::type::UInt64, ipc::type::UInt32}, SetEnableTwitchVOD));
47+ cls->register_function (std::make_shared<ipc::function>(" GetEnhancedBroadcasting" , std::vector<ipc::type>{ipc::type::UInt64}, GetEnhancedBroadcasting));
48+ cls->register_function (
49+ std::make_shared<ipc::function>(" SetEnhancedBroadcasting" , std::vector<ipc::type>{ipc::type::UInt64, ipc::type::UInt32}, SetEnhancedBroadcasting));
4550 cls->register_function (std::make_shared<ipc::function>(" GetAudioTrack" , std::vector<ipc::type>{ipc::type::UInt64}, GetAudioTrack));
4651 cls->register_function (std::make_shared<ipc::function>(" SetAudioTrack" , std::vector<ipc::type>{ipc::type::UInt64, ipc::type::UInt32}, SetAudioTrack));
4752 cls->register_function (std::make_shared<ipc::function>(" GetTwitchTrack" , std::vector<ipc::type>{ipc::type::UInt64}, GetTwitchTrack));
@@ -369,17 +374,94 @@ void osn::IAdvancedStreaming::Start(void *data, const int64_t id, const std::vec
369374 PRETTY_ERROR_RETURN (ErrorCode::InvalidReference, " Advanced streaming reference is not valid." );
370375 }
371376
377+ if (!streaming->service ) {
378+ PRETTY_ERROR_RETURN (ErrorCode::InvalidReference, " Invalid service." );
379+ }
380+
381+ if (streaming->enhancedBroadcasting ) {
382+ const bool dualStreamingMode = true ;
383+
384+ blog (LOG_INFO, " osn::IAdvancedStreaming::Start - service id: %s" , obs_service_get_id (streaming->service ));
385+
386+ const bool is_custom = strncmp (" rtmp_custom" , obs_service_get_type (streaming->service ), 11 ) == 0 ;
387+
388+ OBSDataAutoRelease settings = obs_service_get_settings (streaming->service );
389+ std::string key = obs_data_get_string (settings, " key" );
390+
391+ const char *service_name = " <unknown>" ;
392+ if (is_custom && obs_data_has_user_value (settings, " service_name" )) {
393+ service_name = obs_data_get_string (settings, " service_name" );
394+ } else if (!is_custom) {
395+ service_name = obs_data_get_string (settings, " service" );
396+ }
397+
398+ std::optional<std::string> custom_rtmp_url;
399+ auto server = obs_data_get_string (settings, " server" );
400+ if (strcmp (server, " auto" ) != 0 ) {
401+ custom_rtmp_url = server;
402+ }
403+
404+ auto service_custom_server = obs_data_get_bool (settings, " using_custom_server" );
405+ if (custom_rtmp_url.has_value ()) {
406+ blog (LOG_INFO, " Using %sserver '%s'" , service_custom_server ? " custom " : " " , custom_rtmp_url->c_str ());
407+ }
408+
409+ auto auto_config_url = osn::MultitrackVideoAutoConfigURL (streaming->service );
410+ blog (LOG_INFO, " Auto config URL: %s" , auto_config_url.c_str ());
411+
412+ // TODO: !!!!!!!!!!!!!!!! VOD track index from options instead of global config??????????????????????????????????????????????????????
413+ const auto vodTrackIndex = int (config_get_int (ConfigManager::getInstance ().getBasic (), " AdvOut" , " VodTrackIndex" )) - 1 ;
414+ blog (LOG_INFO, " vodTrackIndex: %d" , vodTrackIndex);
415+
416+ auto vod_track_mixer = streaming->enableTwitchVOD ? std::optional{vodTrackIndex} : std::nullopt ;
417+
418+ auto go_live_post = osn::constructGoLivePost (StreamServiceId::Main, dualStreamingMode, key, std::nullopt , std::nullopt , vod_track_mixer.has_value ());
419+ std::optional<osn::Config> go_live_config = osn::DownloadGoLiveConfig (auto_config_url, go_live_post);
420+ if (!go_live_config.has_value ()) {
421+ throw std::runtime_error (" startStreaming - go live config is empty" );
422+ }
423+
424+ const auto audio_bitrate = osn::GetMultitrackAudioBitrate ();
425+ const auto audio_encoder_id = osn::GetSimpleAACEncoderForBitrate (audio_bitrate);
426+
427+ std::vector<OBSEncoderAutoRelease> audio_encoders;
428+ std::shared_ptr<obs_encoder_group_t > video_encoder_group;
429+ auto output =
430+ osn::SetupOBSOutput (" Enhanced Broadcasting" , go_live_config.value (), audio_encoders, video_encoder_group, audio_encoder_id, 0 , vod_track_mixer);
431+ if (!output) {
432+ throw std::runtime_error (" startStreaming - failed to create multitrack output" );
433+ }
434+
435+ auto multitrack_video_service = osn::create_service (*go_live_config, std::nullopt , " " ); // Stream key is defined by config from Twitch
436+ if (!multitrack_video_service) {
437+ throw std::runtime_error (" startStreaming - failed to create multitrack video service" );
438+ }
439+
440+ streaming->SetOutput (output.Get ());
441+ obs_output_set_service (output, multitrack_video_service);
442+
443+ // Register the BPM (Broadcast Performance Metrics) callback
444+ obs_output_add_packet_callback (output, bpm_inject, NULL );
445+
446+ streaming->StartOutput ();
447+
448+ streaming->enhancedBroadcastContext .emplace (EnhancedBroadcastOutputObjects{
449+ std::move (output),
450+ video_encoder_group,
451+ std::move (audio_encoders),
452+ std::move (multitrack_video_service),
453+ });
454+ }
455+
372456 // TODO: enhanced broadcasting case
457+ return ;
458+
373459 if (!streaming->videoEncoder ) {
374460 PRETTY_ERROR_RETURN (ErrorCode::InvalidReference, " Invalid video encoder." );
375461 }
376462
377463 streaming->UpdateEncoders ();
378464
379- if (!streaming->service ) {
380- PRETTY_ERROR_RETURN (ErrorCode::InvalidReference, " Invalid service." );
381- }
382-
383465 const char *type = OBS_service::getStreamOutputType (streaming->service );
384466 if (!type)
385467 type = " rtmp_output" ;
0 commit comments