@@ -85,7 +85,6 @@ PeerConnection::~PeerConnection() {
85
85
}
86
86
87
87
void PeerConnection::close () {
88
- negotiationNeeded = false ;
89
88
if (!closing.exchange (true )) {
90
89
PLOG_VERBOSE << " Closing PeerConnection" ;
91
90
if (auto transport = std::atomic_load (&mSctpTransport ))
@@ -829,27 +828,58 @@ void PeerConnection::iterateTracks(std::function<void(shared_ptr<Track> track)>
829
828
}
830
829
}
831
830
831
+ void PeerConnection::iterateRemoteTracks (std::function<void (shared_ptr<Track> track)> func) {
832
+ auto remote = remoteDescription ();
833
+ if (!remote)
834
+ return ;
835
+
836
+ std::vector<shared_ptr<Track>> locked;
837
+ {
838
+ std::shared_lock lock (mTracksMutex ); // read-only
839
+ locked.reserve (remote->mediaCount ());
840
+ for (int i = 0 ; i < remote->mediaCount (); ++i) {
841
+ if (std::holds_alternative<Description::Media *>(remote->media (i))) {
842
+ auto remoteMedia = std::get<Description::Media *>(remote->media (i));
843
+ if (!remoteMedia->isRemoved ())
844
+ if (auto it = mTracks .find (remoteMedia->mid ()); it != mTracks .end ())
845
+ if (auto track = it->second .lock ())
846
+ locked.push_back (std::move (track));
847
+ }
848
+ }
849
+ }
850
+
851
+ for (auto &track : locked) {
852
+ try {
853
+ func (std::move (track));
854
+ } catch (const std::exception &e) {
855
+ PLOG_WARNING << e.what ();
856
+ }
857
+ }
858
+ }
859
+
860
+
832
861
void PeerConnection::openTracks () {
833
862
#if RTC_ENABLE_MEDIA
834
- if (auto transport = std::atomic_load (&mDtlsTransport )) {
835
- auto srtpTransport = std::dynamic_pointer_cast<DtlsSrtpTransport>(transport);
836
-
837
- iterateTracks ([&](const shared_ptr<Track> &track) {
838
- if (!track->isOpen ()) {
839
- if (srtpTransport) {
840
- track->open (srtpTransport);
841
- } else {
842
- // A track was added during a latter renegotiation, whereas SRTP transport was
843
- // not initialized. This is an optimization to use the library with data
844
- // channels only. Set forceMediaTransport to true to initialize the transport
845
- // before dynamically adding tracks.
846
- auto errorMsg = " The connection has no media transport" ;
847
- PLOG_ERROR << errorMsg;
848
- track->triggerError (errorMsg);
849
- }
863
+ auto transport = std::atomic_load (&mDtlsTransport );
864
+ if (!transport)
865
+ return ;
866
+
867
+ auto srtpTransport = std::dynamic_pointer_cast<DtlsSrtpTransport>(transport);
868
+ iterateRemoteTracks ([&](shared_ptr<Track> track) {
869
+ if (!track->isOpen ()) {
870
+ if (srtpTransport) {
871
+ track->open (srtpTransport);
872
+ } else {
873
+ // A track was added during a latter renegotiation, whereas SRTP transport was
874
+ // not initialized. This is an optimization to use the library with data
875
+ // channels only. Set forceMediaTransport to true to initialize the transport
876
+ // before dynamically adding tracks.
877
+ auto errorMsg = " The connection has no media transport" ;
878
+ PLOG_ERROR << errorMsg;
879
+ track->triggerError (errorMsg);
850
880
}
851
- });
852
- }
881
+ }
882
+ });
853
883
#endif
854
884
}
855
885
@@ -872,7 +902,7 @@ void PeerConnection::validateRemoteDescription(const Description &description) {
872
902
throw std::invalid_argument (" Remote description has no media line" );
873
903
874
904
int activeMediaCount = 0 ;
875
- for (unsigned int i = 0 ; i < description.mediaCount (); ++i)
905
+ for (int i = 0 ; i < description.mediaCount (); ++i)
876
906
std::visit (rtc::overloaded{[&](const Description::Application *application) {
877
907
if (!application->isRemoved ())
878
908
++activeMediaCount;
@@ -900,7 +930,7 @@ void PeerConnection::processLocalDescription(Description description) {
900
930
901
931
if (auto remote = remoteDescription ()) {
902
932
// Reciprocate remote description
903
- for (unsigned int i = 0 ; i < remote->mediaCount (); ++i)
933
+ for (int i = 0 ; i < remote->mediaCount (); ++i)
904
934
std::visit ( // reciprocate each media
905
935
rtc::overloaded{
906
936
[&](Description::Application *remoteApp) {
@@ -1027,8 +1057,7 @@ void PeerConnection::processLocalDescription(Description description) {
1027
1057
}
1028
1058
}
1029
1059
1030
- // There might be no media at this point if the user created a Track, deleted it,
1031
- // then called setLocalDescription().
1060
+ // There might be no media at this point, for instance if the user deleted tracks
1032
1061
if (description.mediaCount () == 0 )
1033
1062
throw std::runtime_error (" No DataChannel or Track to negotiate" );
1034
1063
}
@@ -1102,15 +1131,19 @@ void PeerConnection::processRemoteDescription(Description description) {
1102
1131
mRemoteDescription ->addCandidates (std::move (existingCandidates));
1103
1132
}
1104
1133
1134
+ auto dtlsTransport = std::atomic_load (&mDtlsTransport );
1105
1135
if (description.hasApplication ()) {
1106
- auto dtlsTransport = std::atomic_load (&mDtlsTransport );
1107
1136
auto sctpTransport = std::atomic_load (&mSctpTransport );
1108
1137
if (!sctpTransport && dtlsTransport &&
1109
1138
dtlsTransport->state () == Transport::State::Connected)
1110
1139
initSctpTransport ();
1111
1140
} else {
1112
1141
mProcessor .enqueue (&PeerConnection::remoteCloseDataChannels, shared_from_this ());
1113
1142
}
1143
+
1144
+ if (dtlsTransport && dtlsTransport->state () == Transport::State::Connected)
1145
+ mProcessor .enqueue (&PeerConnection::openTracks, shared_from_this ());
1146
+
1114
1147
}
1115
1148
1116
1149
void PeerConnection::processRemoteCandidate (Candidate candidate) {
@@ -1156,6 +1189,45 @@ string PeerConnection::localBundleMid() const {
1156
1189
return mLocalDescription ? mLocalDescription ->bundleMid () : " 0" ;
1157
1190
}
1158
1191
1192
+ bool PeerConnection::negotiationNeeded () const {
1193
+ auto description = localDescription ();
1194
+
1195
+ {
1196
+ std::shared_lock lock (mDataChannelsMutex );
1197
+ if (!mDataChannels .empty () || !mUnassignedDataChannels .empty ())
1198
+ if (!description || !description->hasApplication ()) {
1199
+ PLOG_DEBUG << " Negotiation needed for data channels" ;
1200
+ return true ;
1201
+ }
1202
+ }
1203
+
1204
+ {
1205
+ std::shared_lock lock (mTracksMutex );
1206
+ for (const auto &[mid, weakTrack] : mTracks )
1207
+ if (auto track = weakTrack.lock ())
1208
+ if (!description || !description->hasMid (track->mid ())) {
1209
+ PLOG_DEBUG << " Negotiation needed to add track, mid=" << track->mid ();
1210
+ return true ;
1211
+ }
1212
+
1213
+ if (description) {
1214
+ for (int i = 0 ; i < description->mediaCount (); ++i) {
1215
+ if (std::holds_alternative<Description::Media *>(description->media (i))) {
1216
+ auto media = std::get<Description::Media *>(description->media (i));
1217
+ if (!media->isRemoved ())
1218
+ if (auto it = mTracks .find (media->mid ()); it != mTracks .end ())
1219
+ if (auto track = it->second .lock (); !track || track->isClosed ()) {
1220
+ PLOG_DEBUG << " Negotiation needed to remove track, mid=" << track->mid ();
1221
+ return true ;
1222
+ }
1223
+ }
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ return false ;
1229
+ }
1230
+
1159
1231
void PeerConnection::setMediaHandler (shared_ptr<MediaHandler> handler) {
1160
1232
std::unique_lock lock (mMediaHandlerMutex );
1161
1233
mMediaHandler = handler;
@@ -1321,7 +1393,7 @@ void PeerConnection::updateTrackSsrcCache(const Description &description) {
1321
1393
std::unique_lock lock (mTracksMutex ); // for safely writing to mTracksBySsrc
1322
1394
1323
1395
// Setup SSRC -> Track mapping
1324
- for (unsigned int i = 0 ; i < description.mediaCount (); ++i)
1396
+ for (int i = 0 ; i < description.mediaCount (); ++i)
1325
1397
std::visit ( // ssrc -> track mapping
1326
1398
rtc::overloaded{
1327
1399
[&](Description::Application const *) { return ; },
0 commit comments