Browse Source

Implemented differenciated application and media handling

Paul-Louis Ageneau 4 years ago
parent
commit
65d1268082
2 changed files with 106 additions and 66 deletions
  1. 57 54
      examples/media/main.cpp
  2. 49 12
      src/peerconnection.cpp

+ 57 - 54
examples/media/main.cpp

@@ -37,58 +37,61 @@ typedef int SOCKET;
 using nlohmann::json;
 
 int main() {
-	rtc::InitLogger(rtc::LogLevel::Debug);
-	auto pc = std::make_shared<rtc::PeerConnection>();
-
-	pc->onStateChange(
-	    [](rtc::PeerConnection::State state) { std::cout << "State: " << state << std::endl; });
-
-	pc->onGatheringStateChange([pc](rtc::PeerConnection::GatheringState state) {
-		std::cout << "Gathering State: " << state << std::endl;
-		if (state == rtc::PeerConnection::GatheringState::Complete) {
-			auto description = pc->localDescription();
-			json message = {{"type", description->typeString()},
-			                {"sdp", std::string(description.value())}};
-			std::cout << message << std::endl;
-		}
-	});
-
-	SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
-	sockaddr_in addr;
-	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-	addr.sin_port = htons(5000);
-	addr.sin_family = AF_INET;
-
-	rtc::Description::Video media("video", rtc::Description::Direction::RecvOnly);
-	media.addH264Codec(96);
-	media.setBitrate(
-	    3000); // Request 3Mbps (Browsers do not encode more than 2.5MBps from a webcam)
-
-	auto track = pc->createTrack(media);
-	auto dc = pc->createDataChannel("test");
-
-	auto session = std::make_shared<rtc::RtcpSession>();
-	track->setRtcpHandler(session);
-
-	track->onMessage(
-	    [session, sock, addr](rtc::binary message) {
-		    // This is an RTP packet
-		    sendto(sock, reinterpret_cast<const char *>(message.data()), message.size(), 0,
-		           reinterpret_cast<const struct sockaddr *>(&addr), sizeof(addr));
-	    },
-	    nullptr);
-
-	// TODO
-	// pc->setLocalDescription();
-
-	std::cout << "Expect RTP video traffic on localhost:5000" << std::endl;
-	std::cout << "Please copy/paste the answer provided by the browser: " << std::endl;
-	std::string sdp;
-	std::getline(std::cin, sdp);
-	std::cout << "Got answer" << sdp << std::endl;
-	json j = json::parse(sdp);
-	rtc::Description answer(j["sdp"].get<std::string>(), j["type"].get<std::string>());
-	pc->setRemoteDescription(answer);
-	std::cout << "Press any key to exit." << std::endl;
-	std::cin >> sdp;
+	try {
+		rtc::InitLogger(rtc::LogLevel::Debug);
+		auto pc = std::make_shared<rtc::PeerConnection>();
+
+		pc->onStateChange(
+		    [](rtc::PeerConnection::State state) { std::cout << "State: " << state << std::endl; });
+
+		pc->onGatheringStateChange([pc](rtc::PeerConnection::GatheringState state) {
+			std::cout << "Gathering State: " << state << std::endl;
+			if (state == rtc::PeerConnection::GatheringState::Complete) {
+				auto description = pc->localDescription();
+				json message = {{"type", description->typeString()},
+				                {"sdp", std::string(description.value())}};
+				std::cout << message << std::endl;
+			}
+		});
+
+		SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
+		sockaddr_in addr;
+		addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+		addr.sin_port = htons(5000);
+		addr.sin_family = AF_INET;
+
+		rtc::Description::Video media("video", rtc::Description::Direction::RecvOnly);
+		media.addH264Codec(96);
+		media.setBitrate(
+		    3000); // Request 3Mbps (Browsers do not encode more than 2.5MBps from a webcam)
+
+		auto track = pc->createTrack(media);
+
+		auto session = std::make_shared<rtc::RtcpSession>();
+		track->setRtcpHandler(session);
+
+		track->onMessage(
+		    [session, sock, addr](rtc::binary message) {
+			    // This is an RTP packet
+			    sendto(sock, reinterpret_cast<const char *>(message.data()), message.size(), 0,
+			           reinterpret_cast<const struct sockaddr *>(&addr), sizeof(addr));
+		    },
+		    nullptr);
+
+		pc->setLocalDescription();
+
+		std::cout << "Expect RTP video traffic on localhost:5000" << std::endl;
+		std::cout << "Please copy/paste the answer provided by the browser: " << std::endl;
+		std::string sdp;
+		std::getline(std::cin, sdp);
+		std::cout << "Got answer" << sdp << std::endl;
+		json j = json::parse(sdp);
+		rtc::Description answer(j["sdp"].get<std::string>(), j["type"].get<std::string>());
+		pc->setRemoteDescription(answer);
+		std::cout << "Press any key to exit." << std::endl;
+		std::cin >> sdp;
+
+	} catch (const std::exception &e) {
+		std::cerr << "Error: " << e.what() << std::endl;
+	}
 }

+ 49 - 12
src/peerconnection.cpp

@@ -30,6 +30,7 @@
 #include "dtlssrtptransport.hpp"
 #endif
 
+#include <iomanip>
 #include <thread>
 
 namespace rtc {
@@ -186,6 +187,11 @@ std::optional<string> PeerConnection::remoteAddress() const {
 
 shared_ptr<DataChannel> PeerConnection::createDataChannel(string label, string protocol,
                                                           Reliability reliability) {
+	if (auto local = localDescription(); local && !local->hasApplication()) {
+		PLOG_ERROR << "The PeerConnection was negociated without DataChannel support.";
+		throw std::runtime_error("No DataChannel support on the PeerConnection");
+	}
+
 	// RFC 5763: The answerer MUST use either a setup attribute value of setup:active or
 	// setup:passive. [...] Thus, setup:active is RECOMMENDED.
 	// See https://tools.ietf.org/html/rfc5763#section-5
@@ -245,6 +251,10 @@ std::shared_ptr<Track> PeerConnection::createTrack(Description::Media descriptio
 		if (auto track = it->second.lock())
 			return track;
 
+#if !RTC_ENABLE_MEDIA
+	PLOG_WARNING << "Tracks will be inative (not compiled with SRTP support)";
+#endif
+
 	auto track = std::make_shared<Track>(std::move(description));
 	mTracks.emplace(std::make_pair(track->mid(), track));
 	return track;
@@ -672,45 +682,62 @@ void PeerConnection::openTracks() {
 
 
 void PeerConnection::processLocalDescription(Description description) {
+	int activeMediaCount = 0;
+
 	if (auto remote = remoteDescription()) {
 		// Reciprocate remote description
 		for (int i = 0; i < remote->mediaCount(); ++i)
 			std::visit( // reciprocate each media
 			    rtc::overloaded{
 			        [&](Description::Application *app) {
-				        PLOG_DEBUG << "Reciprocating application in local description, mid=\""
-				                   << app->mid() << "\"";
 				        auto reciprocated = app->reciprocate();
 				        reciprocated.hintSctpPort(DEFAULT_SCTP_PORT);
 				        reciprocated.setMaxMessageSize(LOCAL_MAX_MESSAGE_SIZE);
+				        ++activeMediaCount;
+
+				        PLOG_DEBUG << "Reciprocating application in local description, mid=\""
+				                   << reciprocated.mid() << "\"";
+
 				        description.addMedia(std::move(reciprocated));
 			        },
 			        [&](Description::Media *media) {
-				        PLOG_DEBUG << "Reciprocating media in local description, mid=\""
-				                   << media->mid() << "\"";
-
 				        auto reciprocated = media->reciprocate();
 #if RTC_ENABLE_MEDIA
 				        if (reciprocated.direction() != Description::Direction::Inactive)
-					        incomingTrack(reciprocated);
+					        ++activeMediaCount;
 #else
 				        // No media support, mark as inactive
 				        reciprocated.setDirection(Description::Direction::Inactive);
 #endif
+
+				        incomingTrack(reciprocated);
+
+				        PLOG_DEBUG
+				            << "Reciprocating media in local description, mid=\""
+				            << reciprocated.mid() << "\", active=" << std::boolalpha
+				            << (reciprocated.direction() != Description::Direction::Inactive);
+
 				        description.addMedia(std::move(reciprocated));
 			        },
 			    },
 			    remote->media(i));
+
+		if (activeMediaCount == 0) {
+			PLOG_ERROR << "No active media found in remote description";
+		}
 	} else {
 		// Add application for data channels
 		{
 			std::shared_lock lock(mDataChannelsMutex);
 			if (!mDataChannels.empty()) {
-				const string mid = "data";
-				PLOG_DEBUG << "Adding application to local description, mid=\"" << mid << "\"";
-				Description::Application app;
+				Description::Application app("data");
 				app.setSctpPort(DEFAULT_SCTP_PORT);
 				app.setMaxMessageSize(LOCAL_MAX_MESSAGE_SIZE);
+				++activeMediaCount;
+
+				PLOG_DEBUG << "Adding application to local description, mid=\"" << app.mid()
+				           << "\"";
+
 				description.addMedia(std::move(app));
 			}
 		}
@@ -720,19 +747,29 @@ void PeerConnection::processLocalDescription(Description description) {
 			std::shared_lock lock(mTracksMutex);
 			for (auto it = mTracks.begin(); it != mTracks.end(); ++it) {
 				if (auto track = it->second.lock()) {
-					PLOG_DEBUG << "Adding media to local description, mid=\"" << track->mid()
-					           << "\"";
 					auto media = track->description();
-#if !RTC_ENABLE_MEDIA
+#if RTC_ENABLE_MEDIA
+					if (media.direction() != Description::Direction::Inactive)
+						++activeMediaCount;
+#else
 					// 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);
+
 					description.addMedia(std::move(media));
 				}
 			}
 		}
 	}
 
+	// There must be at least one active media to negociate
+	if (activeMediaCount == 0) {
+		throw std::runtime_error("Nothing to negociate");
+	}
+
 	// Set local fingerprint (wait for certificate if necessary)
 	description.setFingerprint(mCertificate.get()->fingerprint());