Browse Source

Implemented removed media and remove tracks instead of marking them inactive

Paul-Louis Ageneau 3 years ago
parent
commit
2dbd0bb3d0
4 changed files with 78 additions and 48 deletions
  1. 7 1
      include/rtc/description.hpp
  2. 24 12
      src/description.cpp
  3. 45 32
      src/impl/peerconnection.cpp
  4. 2 3
      src/impl/track.cpp

+ 7 - 1
include/rtc/description.hpp

@@ -91,9 +91,13 @@ public:
 		virtual string type() const { return mType; }
 		virtual string type() const { return mType; }
 		virtual string description() const { return mDescription; }
 		virtual string description() const { return mDescription; }
 		virtual string mid() const { return mMid; }
 		virtual string mid() const { return mMid; }
+
 		Direction direction() const { return mDirection; }
 		Direction direction() const { return mDirection; }
 		void setDirection(Direction dir);
 		void setDirection(Direction dir);
 
 
+		bool isRemoved() const { return mIsRemoved; }
+		void setRemoved();
+
 		std::vector<string> attributes() const;
 		std::vector<string> attributes() const;
 		void addAttribute(string attr);
 		void addAttribute(string attr);
 		void removeAttribute(const string &attr);
 		void removeAttribute(const string &attr);
@@ -117,7 +121,7 @@ public:
 		void removeExtMap(int id);
 		void removeExtMap(int id);
 
 
 		operator string() const;
 		operator string() const;
-		string generateSdp(string_view eol, string_view addr, string_view port) const;
+		string generateSdp(string_view eol, string_view addr, uint16_t port) const;
 
 
 		virtual void parseSdpLine(string_view line);
 		virtual void parseSdpLine(string_view line);
 
 
@@ -143,11 +147,13 @@ public:
 		string mDescription;
 		string mDescription;
 		string mMid;
 		string mMid;
 		Direction mDirection;
 		Direction mDirection;
+		bool mIsRemoved;
 	};
 	};
 
 
 	struct RTC_CPP_EXPORT Application : public Entry {
 	struct RTC_CPP_EXPORT Application : public Entry {
 	public:
 	public:
 		Application(string mid = "data");
 		Application(string mid = "data");
+		Application(const string &mline, string mid);
 		virtual ~Application() = default;
 		virtual ~Application() = default;
 
 
 		string description() const override;
 		string description() const override;

+ 24 - 12
src/description.cpp

@@ -310,8 +310,8 @@ string Description::generateSdp(string_view eol) const {
 	                        ? (string(cand->family() == Candidate::Family::Ipv6 ? "IP6" : "IP4") +
 	                        ? (string(cand->family() == Candidate::Family::Ipv6 ? "IP6" : "IP4") +
 	                           " " + *cand->address())
 	                           " " + *cand->address())
 	                        : "IP4 0.0.0.0";
 	                        : "IP4 0.0.0.0";
-	const string port = std::to_string(
-	    cand && cand->isResolved() ? *cand->port() : 9); // Port 9 is the discard protocol
+	const uint16_t port =
+	    cand && cand->isResolved() ? *cand->port() : 9; // Port 9 is the discard protocol
 
 
 	// Entries
 	// Entries
 	bool first = true;
 	bool first = true;
@@ -345,8 +345,8 @@ string Description::generateApplicationSdp(string_view eol) const {
 	                        ? (string(cand->family() == Candidate::Family::Ipv6 ? "IP6" : "IP4") +
 	                        ? (string(cand->family() == Candidate::Family::Ipv6 ? "IP6" : "IP4") +
 	                           " " + *cand->address())
 	                           " " + *cand->address())
 	                        : "IP4 0.0.0.0";
 	                        : "IP4 0.0.0.0";
-	const string port = std::to_string(
-	    cand && cand->isResolved() ? *cand->port() : 9); // Port 9 is the discard protocol
+	const uint16_t port =
+	    cand && cand->isResolved() ? *cand->port() : 9; // Port 9 is the discard protocol
 
 
 	// Application
 	// Application
 	auto app = mApplication ? mApplication : std::make_shared<Application>();
 	auto app = mApplication ? mApplication : std::make_shared<Application>();
@@ -397,7 +397,7 @@ shared_ptr<Description::Entry> Description::createEntry(string mline, string mid
 	string type = mline.substr(0, mline.find(' '));
 	string type = mline.substr(0, mline.find(' '));
 	if (type == "application") {
 	if (type == "application") {
 		removeApplication();
 		removeApplication();
-		mApplication = std::make_shared<Application>(std::move(mid));
+		mApplication = std::make_shared<Application>(mline, std::move(mid));
 		mEntries.emplace_back(mApplication);
 		mEntries.emplace_back(mApplication);
 		return mApplication;
 		return mApplication;
 	} else {
 	} else {
@@ -418,11 +418,11 @@ void Description::removeApplication() {
 	mApplication.reset();
 	mApplication.reset();
 }
 }
 
 
-bool Description::hasApplication() const { return mApplication != nullptr; }
+bool Description::hasApplication() const { return mApplication && !mApplication->isRemoved(); }
 
 
 bool Description::hasAudioOrVideo() const {
 bool Description::hasAudioOrVideo() const {
 	for (auto entry : mEntries)
 	for (auto entry : mEntries)
-		if (entry != mApplication)
+		if (entry != mApplication && !entry->isRemoved())
 			return true;
 			return true;
 
 
 	return false;
 	return false;
@@ -515,15 +515,21 @@ unsigned int Description::mediaCount() const { return unsigned(mEntries.size());
 Description::Entry::Entry(const string &mline, string mid, Direction dir)
 Description::Entry::Entry(const string &mline, string mid, Direction dir)
     : mMid(std::move(mid)), mDirection(dir) {
     : mMid(std::move(mid)), mDirection(dir) {
 
 
-	unsigned int port;
+	uint16_t port;
 	std::istringstream ss(mline);
 	std::istringstream ss(mline);
 	ss >> mType;
 	ss >> mType;
-	ss >> port; // ignored
+	ss >> port;
 	ss >> mDescription;
 	ss >> mDescription;
+
+	// RFC 3264: Existing media streams are removed by creating a new SDP with the port number for
+	// that stream set to zero.
+	mIsRemoved = (port == 0);
 }
 }
 
 
 void Description::Entry::setDirection(Direction dir) { mDirection = dir; }
 void Description::Entry::setDirection(Direction dir) { mDirection = dir; }
 
 
+void Description::Entry::setRemoved() { mIsRemoved = true; }
+
 std::vector<string> Description::attributes() const { return mAttributes; }
 std::vector<string> Description::attributes() const { return mAttributes; }
 
 
 void Description::addAttribute(string attr) {
 void Description::addAttribute(string attr) {
@@ -561,11 +567,14 @@ void Description::Entry::addExtMap(ExtMap map) {
 
 
 void Description::Entry::removeExtMap(int id) { mExtMaps.erase(id); }
 void Description::Entry::removeExtMap(int id) { mExtMaps.erase(id); }
 
 
-Description::Entry::operator string() const { return generateSdp("\r\n", "IP4 0.0.0.0", "9"); }
+Description::Entry::operator string() const { return generateSdp("\r\n", "IP4 0.0.0.0", 9); }
 
 
-string Description::Entry::generateSdp(string_view eol, string_view addr, string_view port) const {
+string Description::Entry::generateSdp(string_view eol, string_view addr, uint16_t port) const {
 	std::ostringstream sdp;
 	std::ostringstream sdp;
-	sdp << "m=" << type() << ' ' << port << ' ' << description() << eol;
+	// RFC 3264: Existing media streams are removed by creating a new SDP with the port number for
+	// that stream set to zero. [...] A stream that is offered with a port of zero MUST be marked
+	// with port zero in the answer.
+	sdp << "m=" << type() << ' ' << (mIsRemoved ? 0 : port) << ' ' << description() << eol;
 	sdp << "c=IN " << addr << eol;
 	sdp << "c=IN " << addr << eol;
 	sdp << generateSdpLines(eol);
 	sdp << generateSdpLines(eol);
 
 
@@ -761,6 +770,9 @@ bool Description::Media::hasSSRC(uint32_t ssrc) {
 Description::Application::Application(string mid)
 Description::Application::Application(string mid)
     : Entry("application 9 UDP/DTLS/SCTP", std::move(mid), Direction::SendRecv) {}
     : Entry("application 9 UDP/DTLS/SCTP", std::move(mid), Direction::SendRecv) {}
 
 
+Description::Application::Application(const string &mline, string mid)
+    : Entry(mline, std::move(mid), Direction::SendRecv) {}
+
 string Description::Application::description() const {
 string Description::Application::description() const {
 	return Entry::description() + " webrtc-datachannel";
 	return Entry::description() + " webrtc-datachannel";
 }
 }

+ 45 - 32
src/impl/peerconnection.cpp

@@ -707,6 +707,12 @@ void PeerConnection::remoteCloseDataChannels() {
 }
 }
 
 
 shared_ptr<Track> PeerConnection::emplaceTrack(Description::Media description) {
 shared_ptr<Track> PeerConnection::emplaceTrack(Description::Media description) {
+#if !RTC_ENABLE_MEDIA
+	// No media support, mark as removed
+	PLOG_WARNING << "Tracks are disabled (not compiled with media support)";
+	description.setRemoved();
+#endif
+
 	shared_ptr<Track> track;
 	shared_ptr<Track> track;
 	if (auto it = mTracks.find(description.mid()); it != mTracks.end())
 	if (auto it = mTracks.find(description.mid()); it != mTracks.end())
 		if (track = it->second.lock(); track)
 		if (track = it->second.lock(); track)
@@ -718,22 +724,27 @@ shared_ptr<Track> PeerConnection::emplaceTrack(Description::Media description) {
 		mTrackLines.emplace_back(track);
 		mTrackLines.emplace_back(track);
 	}
 	}
 
 
+	if (description.isRemoved())
+		track->close();
+
 	return track;
 	return track;
 }
 }
 
 
 void PeerConnection::incomingTrack(Description::Media description) {
 void PeerConnection::incomingTrack(Description::Media description) {
 	std::unique_lock lock(mTracksMutex); // we are going to emplace
 	std::unique_lock lock(mTracksMutex); // we are going to emplace
-#if !RTC_ENABLE_MEDIA
-	if (mTracks.empty()) {
-		PLOG_WARNING << "Tracks will be inative (not compiled with media support)";
-	}
-#endif
-	if (mTracks.find(description.mid()) == mTracks.end()) {
-		auto track = std::make_shared<Track>(weak_from_this(), std::move(description));
+	shared_ptr<Track> track;
+	if (auto it = mTracks.find(description.mid()); it != mTracks.end()) {
+		if (track = it->second.lock(); track)
+			track->setDescription(std::move(description));
+	} else {
+		track = std::make_shared<Track>(weak_from_this(), std::move(description));
 		mTracks.emplace(std::make_pair(track->mid(), track));
 		mTracks.emplace(std::make_pair(track->mid(), track));
 		mTrackLines.emplace_back(track);
 		mTrackLines.emplace_back(track);
 		triggerTrack(track);
 		triggerTrack(track);
 	}
 	}
+
+	if (track && description.isRemoved())
+		track->close();
 }
 }
 
 
 void PeerConnection::openTracks() {
 void PeerConnection::openTracks() {
@@ -764,9 +775,13 @@ void PeerConnection::validateRemoteDescription(const Description &description) {
 
 
 	int activeMediaCount = 0;
 	int activeMediaCount = 0;
 	for (unsigned int i = 0; i < description.mediaCount(); ++i)
 	for (unsigned int i = 0; i < description.mediaCount(); ++i)
-		std::visit(rtc::overloaded{[&](const Description::Application *) { ++activeMediaCount; },
+		std::visit(rtc::overloaded{[&](const Description::Application *application) {
+			                           if (!application->isRemoved())
+				                           ++activeMediaCount;
+		                           },
 		                           [&](const Description::Media *media) {
 		                           [&](const Description::Media *media) {
-			                           if (media->direction() != Description::Direction::Inactive)
+			                           if (!media->isRemoved() ||
+			                               media->direction() != Description::Direction::Inactive)
 				                           ++activeMediaCount;
 				                           ++activeMediaCount;
 		                           }},
 		                           }},
 		           description.media(i));
 		           description.media(i));
@@ -825,22 +840,20 @@ void PeerConnection::processLocalDescription(Description description) {
 					        // Prefer local description
 					        // Prefer local description
 					        if (auto track = it->second.lock()) {
 					        if (auto track = it->second.lock()) {
 						        auto media = track->description();
 						        auto media = track->description();
-#if !RTC_ENABLE_MEDIA
-						        // No media support, mark as inactive
-						        media.setDirection(Description::Direction::Inactive);
-#endif
-						        PLOG_DEBUG
-						            << "Adding media to local description, mid=\"" << media.mid()
-						            << "\", active=" << std::boolalpha
-						            << (media.direction() != Description::Direction::Inactive);
+
+						        PLOG_DEBUG << "Adding media to local description, mid=\""
+						                   << media.mid() << "\", removed=" << std::boolalpha
+						                   << media.isRemoved();
 
 
 						        description.addMedia(std::move(media));
 						        description.addMedia(std::move(media));
+
 					        } else {
 					        } else {
 						        auto reciprocated = remoteMedia->reciprocate();
 						        auto reciprocated = remoteMedia->reciprocate();
-						        reciprocated.setDirection(Description::Direction::Inactive);
+						        reciprocated.setRemoved();
 
 
-						        PLOG_DEBUG << "Adding inactive media to local description, mid=\""
-						                   << reciprocated.mid() << "\"";
+						        PLOG_DEBUG << "Adding media to local description, mid=\""
+						                   << reciprocated.mid()
+						                   << "\", removed=true (track is destroyed)";
 
 
 						        description.addMedia(std::move(reciprocated));
 						        description.addMedia(std::move(reciprocated));
 					        }
 					        }
@@ -850,15 +863,17 @@ void PeerConnection::processLocalDescription(Description description) {
 
 
 				        auto reciprocated = remoteMedia->reciprocate();
 				        auto reciprocated = remoteMedia->reciprocate();
 #if !RTC_ENABLE_MEDIA
 #if !RTC_ENABLE_MEDIA
-				        // No media support, mark as inactive
-				        reciprocated.setDirection(Description::Direction::Inactive);
+				        if (!reciprocated.isRemoved()) {
+							// No media support, mark as removed
+							PLOG_WARNING << "Rejecting track (not compiled with media support)";
+							reciprocated.setRemoved();
+						}
 #endif
 #endif
 				        incomingTrack(reciprocated);
 				        incomingTrack(reciprocated);
 
 
-				        PLOG_DEBUG
-				            << "Reciprocating media in local description, mid=\""
-				            << reciprocated.mid() << "\", active=" << std::boolalpha
-				            << (reciprocated.direction() != Description::Direction::Inactive);
+				        PLOG_DEBUG << "Reciprocating media in local description, mid=\""
+				                   << reciprocated.mid() << "\", removed=" << std::boolalpha
+				                   << reciprocated.isRemoved();
 
 
 				        description.addMedia(std::move(reciprocated));
 				        description.addMedia(std::move(reciprocated));
 			        },
 			        },
@@ -876,13 +891,9 @@ void PeerConnection::processLocalDescription(Description description) {
 					continue;
 					continue;
 
 
 				auto media = track->description();
 				auto media = track->description();
-#if !RTC_ENABLE_MEDIA
-				// No media support, mark as inactive
-				media.setDirection(Description::Direction::Inactive);
-#endif
+
 				PLOG_DEBUG << "Adding media to local description, mid=\"" << media.mid()
 				PLOG_DEBUG << "Adding media to local description, mid=\"" << media.mid()
-				           << "\", active=" << std::boolalpha
-				           << (media.direction() != Description::Direction::Inactive);
+				           << "\", removed=" << std::boolalpha << media.isRemoved();
 
 
 				description.addMedia(std::move(media));
 				description.addMedia(std::move(media));
 			}
 			}
@@ -991,6 +1002,8 @@ void PeerConnection::processRemoteDescription(Description description) {
 		if (!sctpTransport && dtlsTransport &&
 		if (!sctpTransport && dtlsTransport &&
 		    dtlsTransport->state() == Transport::State::Connected)
 		    dtlsTransport->state() == Transport::State::Connected)
 			initSctpTransport();
 			initSctpTransport();
+	} else {
+		mProcessor->enqueue(&PeerConnection::remoteCloseDataChannels, this);
 	}
 	}
 }
 }
 
 

+ 2 - 3
src/impl/track.cpp

@@ -92,7 +92,7 @@ bool Track::isOpen(void) const {
 	std::shared_lock lock(mMutex);
 	std::shared_lock lock(mMutex);
 	return !mIsClosed && mDtlsSrtpTransport.lock();
 	return !mIsClosed && mDtlsSrtpTransport.lock();
 #else
 #else
-	return !mIsClosed;
+	return false;
 #endif
 #endif
 }
 }
 
 
@@ -184,8 +184,7 @@ bool Track::transportSend([[maybe_unused]] message_ptr message) {
 
 
 	return transport->sendMedia(message);
 	return transport->sendMedia(message);
 #else
 #else
-	PLOG_WARNING << "Ignoring track send (not compiled with media support)";
-	return false;
+	throw std::runtime_error("Track is disabled (not compiled with media support)");
 #endif
 #endif
 }
 }