Browse Source

Merge pull request #431 from in2core/feature/improve-capi-sscr

Improve capi for ssrc manipulation
Paul-Louis Ageneau 4 years ago
parent
commit
1156fbe434
4 changed files with 171 additions and 3 deletions
  1. 2 0
      include/rtc/description.hpp
  2. 24 0
      include/rtc/rtc.h
  3. 123 0
      src/capi.cpp
  4. 22 3
      src/description.cpp

+ 2 - 0
include/rtc/description.hpp

@@ -150,6 +150,7 @@ public:
 						 optional<string> msid = nullopt, optional<string> trackID = nullopt);
 		bool hasSSRC(uint32_t ssrc);
 		std::vector<uint32_t> getSSRCs();
+		std::optional<std::string> getCNameForSsrc(uint32_t ssrc);
 
 		void setBitrate(int bitrate);
 		int getBitrate() const;
@@ -195,6 +196,7 @@ public:
 
 		std::map<int, RTPMap> mRtpMap;
 		std::vector<uint32_t> mSsrcs;
+        std::map<uint32_t, string> mCNameMap;
 
 	public:
 		void addRTPMap(const RTPMap &map);

+ 24 - 0
include/rtc/rtc.h

@@ -206,6 +206,7 @@ RTC_EXPORT int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb);
 RTC_EXPORT int rtcCreateDataChannel(int pc, const char *label); // returns dc id
 RTC_EXPORT int rtcCreateDataChannelEx(int pc, const char *label,
                                       const rtcDataChannelInit *init); // returns dc id
+RTC_EXPORT int rtcIsOpen(int dc);
 RTC_EXPORT int rtcDeleteDataChannel(int dc);
 
 RTC_EXPORT int rtcGetDataChannelStream(int dc);
@@ -254,6 +255,13 @@ typedef struct {
 	uint32_t timestamp; // Start timestamp
 } rtcStartTime;
 
+typedef struct {
+	uint32_t ssrc;
+	const char *name;    // optional
+	const char *msid;    // optional
+	const char *trackId; // optional, track ID used in MSID
+} rtcSsrcForTypeInit;
+
 // Set H264PacketizationHandler for track
 RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init);
 
@@ -298,6 +306,22 @@ RTC_EXPORT int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timest
 // Set NeedsToReport flag in RtcpSrReporter handler identified by given track id
 RTC_EXPORT int rtcSetNeedsToSendRtcpSr(int id);
 
+/// Get all available payload types for given codec and stores them in buffer, does nothing if buffer is NULL
+int rtcGetTrackPayloadTypesForCodec(int tr, const char * ccodec, int * buffer, int size);
+
+/// Get all SSRCs for given track
+int rtcGetSsrcsForTrack(int tr, uint32_t * buffer, int count);
+
+/// Get CName for SSRC
+int rtcGetCNameForSsrc(int tr, uint32_t ssrc, char * cname, int cnameSize);
+
+/// Get all SSRCs for given media type in given SDP
+/// @param mediaType Media type (audio/video)
+int rtcGetSsrcsForType(const char * mediaType, const char * sdp, uint32_t * buffer, int bufferSize);
+
+/// Set SSRC for given media type in given SDP
+int rtcSetSsrcForType(const char * mediaType, const char * sdp, char * buffer, const int bufferSize, rtcSsrcForTypeInit * init);
+
 #endif // RTC_ENABLE_MEDIA
 
 #if RTC_ENABLE_WEBSOCKET

+ 123 - 0
src/capi.cpp

@@ -268,6 +268,24 @@ int copyAndReturn(binary b, char *buffer, int size) {
 	return int(b.size());
 }
 
+template<typename T>
+int copyAndReturn(std::vector<T> b, T *buffer, int size) {
+	if (!buffer)
+		return int(b.size());
+
+	if (size < int(b.size()))
+		return RTC_ERR_TOO_SMALL;
+    std::copy(b.begin(), b.end(), buffer);
+	return int(b.size());
+}
+
+#if RTC_ENABLE_MEDIA
+// function is used in RTC_ENABLE_MEDIA only
+string lowercased(string str) {
+	std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); });
+	return str;
+}
+#endif // RTC_ENABLE_MEDIA
 } // namespace
 
 void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb) {
@@ -365,6 +383,12 @@ int rtcCreateDataChannelEx(int pc, const char *label, const rtcDataChannelInit *
 	});
 }
 
+int rtcIsOpen(int cid) {
+	return wrap([cid] {
+        return getChannel(cid)->isOpen();
+	});
+}
+
 int rtcDeleteDataChannel(int dc) {
 	return wrap([dc] {
 		auto dataChannel = getDataChannel(dc);
@@ -503,6 +527,26 @@ int rtcGetTrackDescription(int tr, char *buffer, int size) {
 
 #if RTC_ENABLE_MEDIA
 
+void setSSRC(Description::Media *description, uint32_t ssrc, const char *_name, const char *_msid, const char *_trackID) {
+
+	optional<string> name = nullopt;
+	if (_name) {
+		name = string(_name);
+	}
+
+	optional<string> msid = nullopt;
+	if (_msid) {
+		msid = string(_msid);
+	}
+
+	optional<string> trackID = nullopt;
+	if (_trackID) {
+		trackID = string(_trackID);
+	}
+
+	description->addSSRC(ssrc, name, msid, trackID);
+}
+
 int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
 	return wrap([&] {
 		auto track = getTrack(tr);
@@ -633,6 +677,85 @@ int rtcSetNeedsToSendRtcpSr(int id) {
 	});
 }
 
+int rtcGetTrackPayloadTypesForCodec(int tr, const char * ccodec, int * buffer, int size) {
+	return wrap([&] {
+		auto track = getTrack(tr);
+		auto codec = lowercased(string(ccodec));
+		auto description = track->description();
+		std::vector<int> payloadTypes{};
+		payloadTypes.reserve(std::max(size, 0));
+		for (auto it = description.beginMaps(); it != description.endMaps(); it++) {
+			auto element = *it;
+			if (lowercased(element.second.format) == codec) {
+				payloadTypes.push_back(element.first);
+			}
+		}
+		return copyAndReturn(payloadTypes, buffer, size);
+	});
+}
+
+int rtcGetSsrcsForTrack(int tr, uint32_t * buffer, int count) {
+	return wrap([&] {
+		auto track = getTrack(tr);
+		auto ssrcs = track->description().getSSRCs();
+		return copyAndReturn(ssrcs, buffer, count);
+	});
+}
+
+int rtcGetCNameForSsrc(int tr, uint32_t ssrc, char * cname, int cnameSize) {
+	return wrap([&] {
+		auto track = getTrack(tr);
+		auto description = track->description();
+		auto optCName = description.getCNameForSsrc(ssrc);
+		if (optCName.has_value()) {
+			return copyAndReturn(optCName.value(), cname, cnameSize);
+		} else {
+			return 0;
+		}
+	});
+}
+
+int rtcGetSsrcsForType(const char * mediaType, const char * sdp, uint32_t * buffer, int bufferSize) {
+	return wrap([&] {
+		auto type = lowercased(string(mediaType));
+		auto oldSDP = string(sdp);
+		auto description = Description(oldSDP, "unspec");
+		auto mediaCount = description.mediaCount();
+		for (unsigned int i = 0; i < mediaCount; i++) {
+			if (std::holds_alternative<Description::Media *>(description.media(i))) {
+				auto media = std::get<Description::Media *>(description.media(i));
+				auto currentMediaType = lowercased(media->type());
+				if (currentMediaType == type) {
+					auto ssrcs = media->getSSRCs();
+					return copyAndReturn(ssrcs, buffer, bufferSize);
+				}
+			}
+		}
+		return 0;
+	});
+}
+
+int rtcSetSsrcForType(const char * mediaType, const char * sdp, char * buffer, const int bufferSize,
+					  rtcSsrcForTypeInit * init) {
+	return wrap([&] {
+		auto type = lowercased(string(mediaType));
+		auto prevSDP = string(sdp);
+		auto description = Description(prevSDP, "unspec");
+		auto mediaCount = description.mediaCount();
+		for (unsigned int i = 0; i < mediaCount; i++) {
+			if (std::holds_alternative<Description::Media *>(description.media(i))) {
+				auto media = std::get<Description::Media *>(description.media(i));
+				auto currentMediaType = lowercased(media->type());
+				if (currentMediaType == type) {
+					setSSRC(media, init->ssrc, init->name, init->msid, init->trackId);
+					break;
+				}
+			}
+		}
+		return copyAndReturn(string(description), buffer, bufferSize);
+	});
+}
+
 #endif // RTC_ENABLE_MEDIA
 #if RTC_ENABLE_WEBSOCKET
 

+ 22 - 3
src/description.cpp

@@ -556,10 +556,12 @@ Description::Entry::removeAttribute(std::vector<string>::iterator it) {
 
 void Description::Media::addSSRC(uint32_t ssrc, optional<string> name, optional<string> msid,
                                  optional<string> trackID) {
-	if (name)
+    if (name) {
 		mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " cname:" + *name);
-	else
+        mCNameMap.emplace(ssrc, *name);
+    } else {
 		mAttributes.emplace_back("ssrc:" + std::to_string(ssrc));
+    }
 
 	if (msid)
 		mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " msid:" + *msid + " " +
@@ -858,7 +860,16 @@ void Description::Media::parseSdpLine(string_view line) {
 		} else if (key == "rtcp-mux") {
 			// always added
 		} else if (key == "ssrc") {
-			mSsrcs.emplace_back(to_integer<uint32_t>(value));
+			auto ssrc = to_integer<uint32_t>(value);
+			if (!hasSSRC(ssrc)) {
+				mSsrcs.emplace_back(ssrc);
+			}
+            auto cnamePos = value.find("cname:");
+            if (cnamePos != std::string::npos) {
+                auto cname = value.substr(cnamePos + 6);
+                mCNameMap.emplace(ssrc, cname);
+            }
+			mAttributes.emplace_back(attr);
 		} else {
 			Entry::parseSdpLine(line);
 		}
@@ -875,6 +886,14 @@ void Description::Media::addRTPMap(const Description::Media::RTPMap &map) {
 
 std::vector<uint32_t> Description::Media::getSSRCs() { return mSsrcs; }
 
+std::optional<std::string> Description::Media::getCNameForSsrc(uint32_t ssrc) {
+    auto it = mCNameMap.find(ssrc);
+    if (it != mCNameMap.end()) {
+        return it->second;
+    }
+	return std::nullopt;
+}
+
 std::map<int, Description::Media::RTPMap>::iterator Description::Media::beginMaps() {
 	return mRtpMap.begin();
 }