Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.

Commit 4211a9f

Browse files
committed
Allow subscribing with SVC params.
1 parent fa8b907 commit 4211a9f

File tree

6 files changed

+267
-28
lines changed

6 files changed

+267
-28
lines changed

talk/owt/sdk/conference/conferenceclient.cc

+95-1
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,95 @@ void ConferenceClient::Subscribe(
783783
},
784784
on_failure);
785785
}
786-
void ConferenceClient::UnPublish(
786+
void ConferenceClient::Subscribe(
787+
std::shared_ptr<RemoteStream> stream,
788+
const SubscribeOptions2& options,
789+
std::function<void(std::shared_ptr<ConferenceSubscription>)> on_success,
790+
std::function<void(std::unique_ptr<Exception>)> on_failure) {
791+
if (!CheckNullPointer((uintptr_t)stream.get(), on_failure)) {
792+
RTC_LOG(LS_ERROR) << "Remote stream cannot be nullptr.";
793+
return;
794+
}
795+
if (added_stream_type_.find(stream->Id()) == added_stream_type_.end()) {
796+
std::string failure_message(
797+
"Subscribing an invalid stream. Please check whether this stream is "
798+
"removed.");
799+
if (on_failure != nullptr) {
800+
event_queue_->PostTask([on_failure, failure_message]() {
801+
std::unique_ptr<Exception> e(
802+
new Exception(ExceptionType::kConferenceUnknown, failure_message));
803+
on_failure(std::move(e));
804+
});
805+
}
806+
return;
807+
}
808+
if (!stream->VideoEnabled()) {
809+
std::string failure_message(
810+
"Stream without video is not allowed to be subcribed with simulcast/SVC constraints");
811+
if (on_failure != nullptr) {
812+
event_queue_->PostTask([on_failure, failure_message]() {
813+
std::unique_ptr<Exception> e(
814+
new Exception(ExceptionType::kConferenceUnknown, failure_message));
815+
on_failure(std::move(e));
816+
});
817+
}
818+
return;
819+
}
820+
// Avoid subscribing the same stream twice.
821+
{
822+
std::lock_guard<std::mutex> lock(subscribe_pcs_mutex_);
823+
// Search subscirbe pcs
824+
auto it = std::find_if(
825+
subscribe_pcs_.begin(), subscribe_pcs_.end(),
826+
[&](std::shared_ptr<ConferencePeerConnectionChannel> o) -> bool {
827+
return o->GetSubStreamId() == stream->Id();
828+
});
829+
if (it != subscribe_pcs_.end()) {
830+
std::string failure_message(
831+
"The same remote stream has already been subscribed. Subcribe after "
832+
"it is unsubscribed");
833+
if (on_failure != nullptr) {
834+
event_queue_->PostTask([on_failure, failure_message]() {
835+
std::unique_ptr<Exception> e(new Exception(
836+
ExceptionType::kConferenceUnknown, failure_message));
837+
on_failure(std::move(e));
838+
});
839+
}
840+
return;
841+
}
842+
}
843+
// Reorder SDP according to perference list.
844+
PeerConnectionChannelConfiguration config =
845+
GetPeerConnectionChannelConfiguration();
846+
for (auto codec : options.audio.codecs) {
847+
config.audio.push_back(AudioEncodingParameters(codec, 0));
848+
}
849+
std::shared_ptr<ConferencePeerConnectionChannel> pcc(
850+
new ConferencePeerConnectionChannel(config, signaling_channel_,
851+
event_queue_));
852+
pcc->AddObserver(*this);
853+
{
854+
std::lock_guard<std::mutex> lock(subscribe_pcs_mutex_);
855+
subscribe_pcs_.push_back(pcc);
856+
}
857+
std::weak_ptr<ConferenceClient> weak_this = shared_from_this();
858+
std::string stream_id = stream->Id();
859+
pcc->Subscribe(
860+
stream, options,
861+
[on_success, weak_this, stream_id](std::string session_id) {
862+
auto that = weak_this.lock();
863+
if (!that)
864+
return;
865+
// map current pcc
866+
if (on_success != nullptr) {
867+
std::shared_ptr<ConferenceSubscription> cp(
868+
new ConferenceSubscription(that, session_id, stream_id));
869+
on_success(cp);
870+
}
871+
},
872+
on_failure);
873+
}
874+
void ConferenceClient::UnPublish(
787875
const std::string& session_id,
788876
std::function<void()> on_success,
789877
std::function<void(std::unique_ptr<Exception>)> on_failure) {
@@ -1491,6 +1579,12 @@ void ConferenceClient::ParseStreamInfo(sio::message::ptr stream_info,
14911579
rid_obj->get_flag() == sio::message::flag_string) {
14921580
video_publication_settings.rid = rid_obj->get_string();
14931581
}
1582+
auto scalability_mode_obj = (*tit)->get_map()["scalabilityMode"];
1583+
if (scalability_mode_obj != nullptr &&
1584+
scalability_mode_obj->get_flag() == sio::message::flag_string) {
1585+
video_publication_settings.scalability_mode =
1586+
scalability_mode_obj->get_string();
1587+
}
14941588
auto trackid_obj = (*tit)->get_map()["id"];
14951589
if (trackid_obj != nullptr &&
14961590
trackid_obj->get_flag() == sio::message::flag_string) {

talk/owt/sdk/conference/conferencepeerconnectionchannel.cc

+113-23
Original file line numberDiff line numberDiff line change
@@ -496,15 +496,6 @@ static bool SubOptionAllowed(
496496
// specifies codec, though signaling allows specifying sample rate and channel
497497
// number.
498498

499-
// If rid is specified, search in publication_settings for rid;
500-
if (subscribe_options.video.rid != "") {
501-
for (auto video_setting : publication_settings.video) {
502-
if (video_setting.rid == subscribe_options.video.rid)
503-
return true;
504-
}
505-
return false;
506-
}
507-
508499
bool resolution_supported = (subscribe_options.video.resolution.width == 0 &&
509500
subscribe_options.video.resolution.height == 0);
510501
bool frame_rate_supported = (subscribe_options.video.frameRate == 0);
@@ -647,19 +638,7 @@ void ConferencePeerConnectionChannel::Subscribe(
647638
video_options->get_map()["mid"] = sio::string_message::create("1");
648639
}
649640
auto publication_settings = stream->Settings();
650-
if (subscribe_options.video.rid != "") {
651-
for (auto video_setting : publication_settings.video) {
652-
if (video_setting.rid == subscribe_options.video.rid) {
653-
std::string track_id = video_setting.track_id;
654-
video_options->get_map()["from"] =
655-
sio::string_message::create(track_id);
656-
break;
657-
}
658-
}
659-
} else {
660-
video_options->get_map()["from"] =
661-
sio::string_message::create(stream->Id());
662-
}
641+
video_options->get_map()["from"] = sio::string_message::create(stream->Id());
663642
sio::message::ptr video_spec = sio::object_message::create();
664643
sio::message::ptr resolution_options = sio::object_message::create();
665644
if (subscribe_options.video.resolution.width != 0 &&
@@ -691,10 +670,121 @@ void ConferencePeerConnectionChannel::Subscribe(
691670
sio::int_message::create(subscribe_options.video.frameRate);
692671
}
693672
video_options->get_map()["parameters"] = video_spec;
673+
tracks_options->get_vector().push_back(video_options);
674+
}
675+
676+
media_options->get_map()["tracks"] = tracks_options;
677+
sio_options->get_map()["media"] = media_options;
678+
sio::message::ptr transport_ptr = sio::object_message::create();
679+
transport_ptr->get_map()["type"] = sio::string_message::create("webrtc");
680+
sio_options->get_map()["transport"] = transport_ptr;
681+
682+
signaling_channel_->SendInitializationMessage(
683+
sio_options, "", stream->Id(),
684+
[this](std::string session_id, std::string transport_id) {
685+
// Pre-set the session's ID.
686+
SetSessionId(session_id);
687+
CreateOffer();
688+
},
689+
on_failure); // TODO: on_failure
690+
subscribed_stream_ = stream;
691+
}
692+
693+
void ConferencePeerConnectionChannel::Subscribe(
694+
std::shared_ptr<RemoteStream> stream,
695+
const SubscribeOptions2& subscribe_options,
696+
std::function<void(std::string)> on_success,
697+
std::function<void(std::unique_ptr<Exception>)> on_failure) {
698+
if (!CheckNullPointer((uintptr_t)stream.get(), on_failure)) {
699+
RTC_LOG(LS_ERROR) << "Remote stream cannot be nullptr.";
700+
return;
701+
}
702+
if (subscribe_success_callback_) {
703+
if (on_failure) {
704+
event_queue_->PostTask([on_failure]() {
705+
std::unique_ptr<Exception> e(new Exception(
706+
ExceptionType::kConferenceUnknown, "Subscribing this stream."));
707+
on_failure(std::move(e));
708+
});
709+
}
710+
}
711+
if ((subscribe_options.video.rid == "") &&
712+
(subscribe_options.video.spatialLayerId == -1) &&
713+
(subscribe_options.video.temporalLayerId == -1)) {
714+
if (on_failure) {
715+
event_queue_->PostTask([on_failure]() {
716+
std::unique_ptr<Exception> e(new Exception(
717+
ExceptionType::kConferenceUnknown,
718+
"Either rid/spatialLayer/temporalLayer needs to be set for subscribing."));
719+
on_failure(std::move(e));
720+
});
721+
}
722+
}
723+
subscribe_success_callback_ = on_success;
724+
failure_callback_ = on_failure;
725+
int audio_track_count = 0, video_track_count = 0;
726+
if (stream->has_audio_ && !subscribe_options.audio.disabled) {
727+
webrtc::RtpTransceiverInit transceiver_init;
728+
transceiver_init.direction = webrtc::RtpTransceiverDirection::kRecvOnly;
729+
AddTransceiver(cricket::MediaType::MEDIA_TYPE_AUDIO, transceiver_init);
730+
audio_track_count = 1;
731+
}
732+
if (stream->has_video_) {
733+
webrtc::RtpTransceiverInit transceiver_init;
734+
transceiver_init.direction = webrtc::RtpTransceiverDirection::kRecvOnly;
735+
AddTransceiver(cricket::MediaType::MEDIA_TYPE_VIDEO, transceiver_init);
736+
video_track_count = 1;
737+
}
738+
sio::message::ptr sio_options = sio::object_message::create();
739+
sio::message::ptr media_options = sio::object_message::create();
740+
sio::message::ptr tracks_options = sio::array_message::create();
741+
if (audio_track_count > 0) {
742+
sio::message::ptr audio_options = sio::object_message::create();
743+
audio_options->get_map()["type"] = sio::string_message::create("audio");
744+
audio_options->get_map()["mid"] = sio::string_message::create("0");
745+
audio_options->get_map()["from"] =
746+
sio::string_message::create(stream->Id());
747+
tracks_options->get_vector().push_back(audio_options);
748+
}
749+
if (video_track_count > 0) {
750+
sio::message::ptr video_options = sio::object_message::create();
751+
video_options->get_map()["type"] = sio::string_message::create("video");
752+
if (audio_track_count == 0) {
753+
video_options->get_map()["mid"] = sio::string_message::create("0");
754+
} else {
755+
video_options->get_map()["mid"] = sio::string_message::create("1");
756+
}
757+
auto publication_settings = stream->Settings();
758+
if (subscribe_options.video.rid != "") {
759+
for (auto video_setting : publication_settings.video) {
760+
if (video_setting.rid == subscribe_options.video.rid) {
761+
std::string track_id = video_setting.track_id;
762+
video_options->get_map()["from"] =
763+
sio::string_message::create(track_id);
764+
break;
765+
}
766+
}
767+
} else {
768+
video_options->get_map()["from"] =
769+
sio::string_message::create(stream->Id());
770+
}
771+
sio::message::ptr layer_spec = sio::object_message::create();
772+
if (subscribe_options.video.spatialLayerId >= 0) {
773+
sio::message::ptr spatial_layer_options =
774+
sio::int_message::create(subscribe_options.video.spatialLayerId);
775+
layer_spec->get_map()["spatialLayer"] = spatial_layer_options;
776+
}
777+
if (subscribe_options.video.temporalLayerId >= 0) {
778+
sio::message::ptr temporal_layer_options =
779+
sio::int_message::create(subscribe_options.video.temporalLayerId);
780+
layer_spec->get_map()["temporallLayer"] = temporal_layer_options;
781+
}
694782
if (subscribe_options.video.rid != "") {
695-
video_options->get_map()["simulcastRid"] =
783+
sio::message::ptr rid_options =
696784
sio::string_message::create(subscribe_options.video.rid);
785+
layer_spec->get_map()["rid"] = rid_options;
697786
}
787+
video_options->get_map()["parameters"] = layer_spec;
698788
tracks_options->get_vector().push_back(video_options);
699789
}
700790

talk/owt/sdk/conference/conferencepeerconnectionchannel.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,17 @@ class ConferencePeerConnectionChannel
4343
const std::string& session_id,
4444
std::function<void()> on_success,
4545
std::function<void(std::unique_ptr<Exception>)> on_failure);
46-
// Subscribe a stream from the conference.
46+
// Subscribe a non-simulcast/non-SVC stream from the conference.
4747
void Subscribe(
4848
std::shared_ptr<RemoteStream> stream,
4949
const SubscribeOptions& options,
5050
std::function<void(std::string)> on_success,
5151
std::function<void(std::unique_ptr<Exception>)> on_failure);
52+
// Subscribe a simulcast or SVC stream from the conference.
53+
void Subscribe(std::shared_ptr<RemoteStream> stream,
54+
const SubscribeOptions2& options,
55+
std::function<void(std::string)> on_success,
56+
std::function<void(std::unique_ptr<Exception>)> on_failure);
5257
// Unsubscribe a remote stream from the conference.
5358
void Unsubscribe(
5459
const std::string& session_id,

talk/owt/sdk/include/cpp/owt/base/options.h

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct VideoPublicationSettings {
4040
unsigned long keyframe_interval;
4141
std::string rid;
4242
std::string track_id;
43+
std::string scalability_mode;
4344
};
4445

4546
#ifdef OWT_ENABLE_QUIC

talk/owt/sdk/include/cpp/owt/conference/conferenceclient.h

+21-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,10 @@ class ConferenceClient final
315315
std::function<void(std::shared_ptr<ConferenceSubscription>)> on_success,
316316
std::function<void(std::unique_ptr<Exception>)> on_failure);
317317
/**
318-
@brief Subscribe a stream from the current room.
318+
@brief Subscribe a stream with transcoding from the current room.
319+
@details Should only be called on stream that is published without simulcast
320+
or SVC opotions. If |stream| is a simulcast stream or an SVC stream,
321+
subscription will fail.
319322
@param stream The remote stream to be subscribed.
320323
@param options Options for subscribing the stream.
321324
@param onSuccess Success callback with a stream that contains media stream.
@@ -325,6 +328,23 @@ class ConferenceClient final
325328
const SubscribeOptions& options,
326329
std::function<void(std::shared_ptr<ConferenceSubscription>)> on_success,
327330
std::function<void(std::unique_ptr<Exception>)> on_failure);
331+
/**
332+
@brief Subscribe a simulcast or SVC stream from the current room with preferred rid
333+
and/or temporal/spatial layers.
334+
@details rid and temporal/spatial layer ID can be specified together. If rid in
335+
|options| is not empty and |stream| is not a simulcast stream, subscribe will fail;
336+
If temporalLayerId/spatialLayerId is larger than -1 in |options| and |stream| is not
337+
an SVC stream, subscribe will fail; If both rid and temporal/spatialLyerId are specified,
338+
temporalLayerId/spatialLayerId only applies to simulcast stream associated with rid.
339+
@param stream The remote stream to be subscribed.
340+
@param options Simulcast and SVC stream subscribe options for subscribing the stream.
341+
@param onSuccess Success callback with a stream that contains media stream.
342+
*/
343+
void Subscribe(
344+
std::shared_ptr<RemoteStream> stream,
345+
const SubscribeOptions2& options,
346+
std::function<void(std::shared_ptr<ConferenceSubscription>)> on_success,
347+
std::function<void(std::unique_ptr<Exception>)> on_failure);
328348
/**
329349
@brief Send messsage to all participants in the conference.
330350
@param message The message to be sent.

talk/owt/sdk/include/cpp/owt/conference/subscribeoptions.h

+31-2
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,21 @@ struct VideoSubscriptionConstraints {
3030
resolution(0, 0),
3131
frameRate(0),
3232
bitrateMultiplier(0),
33-
keyFrameInterval(0),
34-
rid("") {}
33+
keyFrameInterval(0) {}
3534
bool disabled;
3635
std::vector<owt::base::VideoCodecParameters> codecs;
3736
owt::base::Resolution resolution;
3837
double frameRate;
3938
double bitrateMultiplier;
4039
unsigned long keyFrameInterval;
40+
};
41+
/// Simulcast and SVC stream subscription constranits.
42+
struct VideoSubscriptionConstraints2 {
43+
explicit VideoSubscriptionConstraints2()
44+
: rid(""), spatialLayerId(-1), temporalLayerId(-1) {}
4145
std::string rid;
46+
int spatialLayerId;
47+
int temporalLayerId;
4248
};
4349

4450
#ifdef OWT_ENABLE_QUIC
@@ -57,6 +63,12 @@ struct SubscribeOptions {
5763
DataSubscriptionConstraints data;
5864
#endif
5965
};
66+
67+
/// SVC and Simulcast stream subscribe options
68+
struct SubscribeOptions2 {
69+
AudioSubscriptionConstraints audio;
70+
VideoSubscriptionConstraints2 video;
71+
};
6072
/// Video subscription update constrains used by subscription's ApplyOptions
6173
/// API.
6274
struct VideoSubscriptionUpdateConstraints {
@@ -73,11 +85,28 @@ struct VideoSubscriptionUpdateConstraints {
7385
double bitrateMultiplier;
7486
unsigned long keyFrameInterval;
7587
};
88+
/// Simulcast and SVC stream subscription update constraints
89+
struct VideoSubscriptionUpdateConstraints2 {
90+
/**
91+
@brief Construct VideoSubscriptionUpdateConstraints with default value.
92+
*/
93+
explicit VideoSubscriptionUpdateConstraints2()
94+
: rid(""), spatialLayerId(-1), temporalLayerId(-1) {}
95+
std::string rid;
96+
int spatialLayerId;
97+
int temporalLayerId;
98+
};
7699
/// Subscription update option used by subscription's ApplyOptions API.
77100
struct SubscriptionUpdateOptions {
78101
/// Options for updating a subscription.
79102
VideoSubscriptionUpdateConstraints video;
80103
};
104+
/// Simulcast and SVC stream subcription update option used by subscription's
105+
/// ApplyOptions API.
106+
struct SubscriptionUpdateOptions2 {
107+
/// Options for updating a subscription.
108+
VideoSubscriptionUpdateConstraints2 video;
109+
};
81110
} // namespace conference
82111
} // namespace owt
83112
#endif // OWT_CONFERENCE_SUBSCRIBEOPTIONS_H_

0 commit comments

Comments
 (0)