|
@@ -85,7 +85,6 @@ PeerConnection::~PeerConnection() {
|
|
|
}
|
|
|
|
|
|
void PeerConnection::close() {
|
|
|
- negotiationNeeded = false;
|
|
|
if (!closing.exchange(true)) {
|
|
|
PLOG_VERBOSE << "Closing PeerConnection";
|
|
|
if (auto transport = std::atomic_load(&mSctpTransport))
|
|
@@ -829,27 +828,58 @@ void PeerConnection::iterateTracks(std::function<void(shared_ptr<Track> track)>
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void PeerConnection::iterateRemoteTracks(std::function<void(shared_ptr<Track> track)> func) {
|
|
|
+ auto remote = remoteDescription();
|
|
|
+ if(!remote)
|
|
|
+ return;
|
|
|
+
|
|
|
+ std::vector<shared_ptr<Track>> locked;
|
|
|
+ {
|
|
|
+ std::shared_lock lock(mTracksMutex); // read-only
|
|
|
+ locked.reserve(remote->mediaCount());
|
|
|
+ for(int i = 0; i < remote->mediaCount(); ++i) {
|
|
|
+ if (std::holds_alternative<Description::Media *>(remote->media(i))) {
|
|
|
+ auto remoteMedia = std::get<Description::Media *>(remote->media(i));
|
|
|
+ if (!remoteMedia->isRemoved())
|
|
|
+ if (auto it = mTracks.find(remoteMedia->mid()); it != mTracks.end())
|
|
|
+ if (auto track = it->second.lock())
|
|
|
+ locked.push_back(std::move(track));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (auto &track : locked) {
|
|
|
+ try {
|
|
|
+ func(std::move(track));
|
|
|
+ } catch (const std::exception &e) {
|
|
|
+ PLOG_WARNING << e.what();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
void PeerConnection::openTracks() {
|
|
|
#if RTC_ENABLE_MEDIA
|
|
|
- if (auto transport = std::atomic_load(&mDtlsTransport)) {
|
|
|
- auto srtpTransport = std::dynamic_pointer_cast<DtlsSrtpTransport>(transport);
|
|
|
-
|
|
|
- iterateTracks([&](const shared_ptr<Track> &track) {
|
|
|
- if (!track->isOpen()) {
|
|
|
- if (srtpTransport) {
|
|
|
- track->open(srtpTransport);
|
|
|
- } else {
|
|
|
- // A track was added during a latter renegotiation, whereas SRTP transport was
|
|
|
- // not initialized. This is an optimization to use the library with data
|
|
|
- // channels only. Set forceMediaTransport to true to initialize the transport
|
|
|
- // before dynamically adding tracks.
|
|
|
- auto errorMsg = "The connection has no media transport";
|
|
|
- PLOG_ERROR << errorMsg;
|
|
|
- track->triggerError(errorMsg);
|
|
|
- }
|
|
|
+ auto transport = std::atomic_load(&mDtlsTransport);
|
|
|
+ if (!transport)
|
|
|
+ return;
|
|
|
+
|
|
|
+ auto srtpTransport = std::dynamic_pointer_cast<DtlsSrtpTransport>(transport);
|
|
|
+ iterateRemoteTracks([&](shared_ptr<Track> track) {
|
|
|
+ if(!track->isOpen()) {
|
|
|
+ if (srtpTransport) {
|
|
|
+ track->open(srtpTransport);
|
|
|
+ } else {
|
|
|
+ // A track was added during a latter renegotiation, whereas SRTP transport was
|
|
|
+ // not initialized. This is an optimization to use the library with data
|
|
|
+ // channels only. Set forceMediaTransport to true to initialize the transport
|
|
|
+ // before dynamically adding tracks.
|
|
|
+ auto errorMsg = "The connection has no media transport";
|
|
|
+ PLOG_ERROR << errorMsg;
|
|
|
+ track->triggerError(errorMsg);
|
|
|
}
|
|
|
- });
|
|
|
- }
|
|
|
+ }
|
|
|
+ });
|
|
|
#endif
|
|
|
}
|
|
|
|
|
@@ -872,7 +902,7 @@ void PeerConnection::validateRemoteDescription(const Description &description) {
|
|
|
throw std::invalid_argument("Remote description has no media line");
|
|
|
|
|
|
int activeMediaCount = 0;
|
|
|
- for (unsigned int i = 0; i < description.mediaCount(); ++i)
|
|
|
+ for (int i = 0; i < description.mediaCount(); ++i)
|
|
|
std::visit(rtc::overloaded{[&](const Description::Application *application) {
|
|
|
if (!application->isRemoved())
|
|
|
++activeMediaCount;
|
|
@@ -900,7 +930,7 @@ void PeerConnection::processLocalDescription(Description description) {
|
|
|
|
|
|
if (auto remote = remoteDescription()) {
|
|
|
// Reciprocate remote description
|
|
|
- for (unsigned int i = 0; i < remote->mediaCount(); ++i)
|
|
|
+ for (int i = 0; i < remote->mediaCount(); ++i)
|
|
|
std::visit( // reciprocate each media
|
|
|
rtc::overloaded{
|
|
|
[&](Description::Application *remoteApp) {
|
|
@@ -1027,8 +1057,7 @@ void PeerConnection::processLocalDescription(Description description) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // There might be no media at this point if the user created a Track, deleted it,
|
|
|
- // then called setLocalDescription().
|
|
|
+ // There might be no media at this point, for instance if the user deleted tracks
|
|
|
if (description.mediaCount() == 0)
|
|
|
throw std::runtime_error("No DataChannel or Track to negotiate");
|
|
|
}
|
|
@@ -1102,8 +1131,8 @@ void PeerConnection::processRemoteDescription(Description description) {
|
|
|
mRemoteDescription->addCandidates(std::move(existingCandidates));
|
|
|
}
|
|
|
|
|
|
+ auto dtlsTransport = std::atomic_load(&mDtlsTransport);
|
|
|
if (description.hasApplication()) {
|
|
|
- auto dtlsTransport = std::atomic_load(&mDtlsTransport);
|
|
|
auto sctpTransport = std::atomic_load(&mSctpTransport);
|
|
|
if (!sctpTransport && dtlsTransport &&
|
|
|
dtlsTransport->state() == Transport::State::Connected)
|
|
@@ -1111,6 +1140,10 @@ void PeerConnection::processRemoteDescription(Description description) {
|
|
|
} else {
|
|
|
mProcessor.enqueue(&PeerConnection::remoteCloseDataChannels, shared_from_this());
|
|
|
}
|
|
|
+
|
|
|
+ if (dtlsTransport && dtlsTransport->state() == Transport::State::Connected)
|
|
|
+ mProcessor.enqueue(&PeerConnection::openTracks, shared_from_this());
|
|
|
+
|
|
|
}
|
|
|
|
|
|
void PeerConnection::processRemoteCandidate(Candidate candidate) {
|
|
@@ -1156,6 +1189,45 @@ string PeerConnection::localBundleMid() const {
|
|
|
return mLocalDescription ? mLocalDescription->bundleMid() : "0";
|
|
|
}
|
|
|
|
|
|
+bool PeerConnection::negotiationNeeded() const {
|
|
|
+ auto description = localDescription();
|
|
|
+
|
|
|
+ {
|
|
|
+ std::shared_lock lock(mDataChannelsMutex);
|
|
|
+ if (!mDataChannels.empty() || !mUnassignedDataChannels.empty())
|
|
|
+ if(!description || !description->hasApplication()) {
|
|
|
+ PLOG_DEBUG << "Negotiation needed for data channels";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ std::shared_lock lock(mTracksMutex);
|
|
|
+ for(const auto &[mid, weakTrack] : mTracks)
|
|
|
+ if (auto track = weakTrack.lock())
|
|
|
+ if (!description || !description->hasMid(track->mid())) {
|
|
|
+ PLOG_DEBUG << "Negotiation needed to add track, mid=" << track->mid();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(description) {
|
|
|
+ for(int i = 0; i < description->mediaCount(); ++i) {
|
|
|
+ if (std::holds_alternative<Description::Media *>(description->media(i))) {
|
|
|
+ auto media = std::get<Description::Media *>(description->media(i));
|
|
|
+ if (!media->isRemoved())
|
|
|
+ if (auto it = mTracks.find(media->mid()); it != mTracks.end())
|
|
|
+ if (auto track = it->second.lock(); !track || track->isClosed()) {
|
|
|
+ PLOG_DEBUG << "Negotiation needed to remove track, mid=" << track->mid();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
void PeerConnection::setMediaHandler(shared_ptr<MediaHandler> handler) {
|
|
|
std::unique_lock lock(mMediaHandlerMutex);
|
|
|
mMediaHandler = handler;
|
|
@@ -1321,7 +1393,7 @@ void PeerConnection::updateTrackSsrcCache(const Description &description) {
|
|
|
std::unique_lock lock(mTracksMutex); // for safely writing to mTracksBySsrc
|
|
|
|
|
|
// Setup SSRC -> Track mapping
|
|
|
- for (unsigned int i = 0; i < description.mediaCount(); ++i)
|
|
|
+ for (int i = 0; i < description.mediaCount(); ++i)
|
|
|
std::visit( // ssrc -> track mapping
|
|
|
rtc::overloaded{
|
|
|
[&](Description::Application const *) { return; },
|