Browse Source

Merge pull request #416 from paullouisageneau/cleanup-api

Refactor C media API
Paul-Louis Ageneau 4 years ago
parent
commit
aea6708d27
3 changed files with 277 additions and 320 deletions
  1. 8 1
      include/rtc/description.hpp
  2. 124 141
      include/rtc/rtc.h
  3. 145 178
      src/capi.cpp

+ 8 - 1
include/rtc/description.hpp

@@ -42,7 +42,14 @@ class RTC_CPP_EXPORT Description {
 public:
 public:
 	enum class Type { Unspec, Offer, Answer, Pranswer, Rollback };
 	enum class Type { Unspec, Offer, Answer, Pranswer, Rollback };
 	enum class Role { ActPass, Passive, Active };
 	enum class Role { ActPass, Passive, Active };
-	enum class Direction { SendOnly, RecvOnly, SendRecv, Inactive, Unknown };
+
+	enum class Direction {
+		SendOnly = RTC_DIRECTION_SENDONLY,
+		RecvOnly = RTC_DIRECTION_RECVONLY,
+		SendRecv = RTC_DIRECTION_SENDRECV,
+		Inactive = RTC_DIRECTION_INACTIVE,
+		Unknown = RTC_DIRECTION_UNKNOWN
+	};
 
 
 	Description(const string &sdp, Type type = Type::Unspec, Role role = Role::ActPass);
 	Description(const string &sdp, Type type = Type::Unspec, Role role = Role::ActPass);
 	Description(const string &sdp, string typeString);
 	Description(const string &sdp, string typeString);

+ 124 - 141
include/rtc/rtc.h

@@ -95,8 +95,6 @@ typedef enum {
 	RTC_CERTIFICATE_RSA = 2,
 	RTC_CERTIFICATE_RSA = 2,
 } rtcCertificateType;
 } rtcCertificateType;
 
 
-#if RTC_ENABLE_MEDIA
-
 typedef enum {
 typedef enum {
 	// video
 	// video
 	RTC_CODEC_H264 = 0,
 	RTC_CODEC_H264 = 0,
@@ -115,41 +113,12 @@ typedef enum {
 	RTC_DIRECTION_INACTIVE = 4
 	RTC_DIRECTION_INACTIVE = 4
 } rtcDirection;
 } rtcDirection;
 
 
-#endif // RTC_ENABLE_MEDIA
-
 #define RTC_ERR_SUCCESS 0
 #define RTC_ERR_SUCCESS 0
 #define RTC_ERR_INVALID -1   // invalid argument
 #define RTC_ERR_INVALID -1   // invalid argument
 #define RTC_ERR_FAILURE -2   // runtime error
 #define RTC_ERR_FAILURE -2   // runtime error
 #define RTC_ERR_NOT_AVAIL -3 // element not available
 #define RTC_ERR_NOT_AVAIL -3 // element not available
 #define RTC_ERR_TOO_SMALL -4 // buffer too small
 #define RTC_ERR_TOO_SMALL -4 // buffer too small
 
 
-typedef struct {
-	const char **iceServers;
-	int iceServersCount;
-	rtcCertificateType certificateType;
-	bool enableIceTcp;
-	bool disableAutoNegotiation;
-	uint16_t portRangeBegin;
-	uint16_t portRangeEnd;
-	int mtu;            // <= 0 means automatic
-	int maxMessageSize; // <= 0 means default
-} rtcConfiguration;
-
-typedef struct {
-	bool unordered;
-	bool unreliable;
-	int maxPacketLifeTime; // ignored if reliable
-	int maxRetransmits;    // ignored if reliable
-} rtcReliability;
-
-typedef struct {
-	rtcReliability reliability;
-	const char *protocol; // empty string if NULL
-	bool negotiated;
-	bool manualStream;
-	uint16_t stream; // numeric ID 0-65534, ignored if manualStream is false
-} rtcDataChannelInit;
-
 typedef void(RTC_API *rtcLogCallbackFunc)(rtcLogLevel level, const char *message);
 typedef void(RTC_API *rtcLogCallbackFunc)(rtcLogLevel level, const char *message);
 typedef void(RTC_API *rtcDescriptionCallbackFunc)(int pc, const char *sdp, const char *type,
 typedef void(RTC_API *rtcDescriptionCallbackFunc)(int pc, const char *sdp, const char *type,
                                                   void *ptr);
                                                   void *ptr);
@@ -168,6 +137,7 @@ typedef void(RTC_API *rtcBufferedAmountLowCallbackFunc)(int id, void *ptr);
 typedef void(RTC_API *rtcAvailableCallbackFunc)(int id, void *ptr);
 typedef void(RTC_API *rtcAvailableCallbackFunc)(int id, void *ptr);
 
 
 // Log
 // Log
+
 // NULL cb on the first call will log to stdout
 // NULL cb on the first call will log to stdout
 RTC_EXPORT void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb);
 RTC_EXPORT void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb);
 
 
@@ -176,6 +146,19 @@ RTC_EXPORT void rtcSetUserPointer(int id, void *ptr);
 RTC_EXPORT void *rtcGetUserPointer(int i);
 RTC_EXPORT void *rtcGetUserPointer(int i);
 
 
 // PeerConnection
 // PeerConnection
+
+typedef struct {
+	const char **iceServers;
+	int iceServersCount;
+	rtcCertificateType certificateType;
+	bool enableIceTcp;
+	bool disableAutoNegotiation;
+	uint16_t portRangeBegin;
+	uint16_t portRangeEnd;
+	int mtu;            // <= 0 means automatic
+	int maxMessageSize; // <= 0 means default
+} rtcConfiguration;
+
 RTC_EXPORT int rtcCreatePeerConnection(const rtcConfiguration *config); // returns pc id
 RTC_EXPORT int rtcCreatePeerConnection(const rtcConfiguration *config); // returns pc id
 RTC_EXPORT int rtcDeletePeerConnection(int pc);
 RTC_EXPORT int rtcDeletePeerConnection(int pc);
 
 
@@ -202,6 +185,22 @@ RTC_EXPORT int rtcGetSelectedCandidatePair(int pc, char *local, int localSize, c
                                            int remoteSize);
                                            int remoteSize);
 
 
 // DataChannel
 // DataChannel
+
+typedef struct {
+	bool unordered;
+	bool unreliable;
+	int maxPacketLifeTime; // ignored if reliable
+	int maxRetransmits;    // ignored if reliable
+} rtcReliability;
+
+typedef struct {
+	rtcReliability reliability;
+	const char *protocol; // empty string if NULL
+	bool negotiated;
+	bool manualStream;
+	uint16_t stream; // numeric ID 0-65534, ignored if manualStream is false
+} rtcDataChannelInit;
+
 RTC_EXPORT int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb);
 RTC_EXPORT int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb);
 RTC_EXPORT int rtcCreateDataChannel(int pc, const char *label); // returns dc id
 RTC_EXPORT int rtcCreateDataChannel(int pc, const char *label); // returns dc id
 RTC_EXPORT int rtcCreateDataChannelEx(int pc, const char *label,
 RTC_EXPORT int rtcCreateDataChannelEx(int pc, const char *label,
@@ -214,131 +213,96 @@ RTC_EXPORT int rtcGetDataChannelProtocol(int dc, char *buffer, int size);
 RTC_EXPORT int rtcGetDataChannelReliability(int dc, rtcReliability *reliability);
 RTC_EXPORT int rtcGetDataChannelReliability(int dc, rtcReliability *reliability);
 
 
 // Track
 // Track
+
+typedef struct {
+	rtcDirection direction;
+	rtcCodec codec;
+	int payloadType;
+	uint32_t ssrc;
+	const char *mid;
+	const char *name;    // optional
+	const char *msid;    // optional
+	const char *trackId; // optional, track ID used in MSID
+} rtcTrackInit;
+
 RTC_EXPORT int rtcSetTrackCallback(int pc, rtcTrackCallbackFunc cb);
 RTC_EXPORT int rtcSetTrackCallback(int pc, rtcTrackCallbackFunc cb);
 RTC_EXPORT int rtcAddTrack(int pc, const char *mediaDescriptionSdp); // returns tr id
 RTC_EXPORT int rtcAddTrack(int pc, const char *mediaDescriptionSdp); // returns tr id
+RTC_EXPORT int rtcAddTrackEx(int pc, const rtcTrackInit *init);      // returns tr id
 RTC_EXPORT int rtcDeleteTrack(int tr);
 RTC_EXPORT int rtcDeleteTrack(int tr);
 
 
 RTC_EXPORT int rtcGetTrackDescription(int tr, char *buffer, int size);
 RTC_EXPORT int rtcGetTrackDescription(int tr, char *buffer, int size);
 
 
-// SCTP settings
+#if RTC_ENABLE_MEDIA
+
+// Media
+
 typedef struct {
 typedef struct {
-	int recvBufferSize;          // in bytes, <= 0 means optimized default
-	int sendBufferSize;          // in bytes, <= 0 means optimized default
-	int maxChunksOnQueue;        // in chunks, <= 0 means optimized default
-	int initialCongestionWindow; // in MTUs, <= 0 means optimized default
-	int maxBurst;				 // in MTUs, 0 means optimized default, < 0 means disabled
-	int congestionControlModule; // 0: RFC2581 (default), 1: HSTCP, 2: H-TCP, 3: RTCC
-	int delayedSackTimeMs;       // in msecs, <= 0 means optimized default
-} rtcSctpSettings;
+	uint32_t ssrc;
+	const char *cname;
+	uint8_t payloadType;
+	uint32_t clockRate;
+	uint16_t maxFragmentSize; // Maximum NALU fragment size
+	uint16_t sequenceNumber;
+	uint32_t timestamp;
+} rtcPacketizationHandlerInit;
 
 
-// Note: SCTP settings apply to newly-created PeerConnections only
-RTC_EXPORT int rtcSetSctpSettings(const rtcSctpSettings *settings);
+typedef struct {
+	double seconds;     // Start time in seconds
+	bool since1970;     // true if seconds since 1970
+	                    // false if seconds since 1900
+	uint32_t timestamp; // Start timestamp
+} rtcStartTime;
 
 
-// Media
-#if RTC_ENABLE_MEDIA
+// Set H264PacketizationHandler for track
+RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init);
+
+// Set OpusPacketizationHandler for track
+RTC_EXPORT int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init);
 
 
-/// Add track
-/// @param pc Peer connection id
-/// @param codec Codec
-/// @param payloadType Payload type
-/// @param ssrc SSRC
-/// @param _mid MID
-/// @param _direction Direction
-/// @param _name Name (optional)
-/// @param _msid MSID (optional)
-/// @param _trackID Track ID used in MSID (optional)
-/// @returns Track id
-RTC_EXPORT int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc,
-                             const char *_mid, rtcDirection direction, const char *_name,
-                             const char *_msid, const char *_trackID);
-
-/// Set H264PacketizationHandler for track
-/// @param tr Track id
-/// @param ssrc SSRC
-/// @param cname CName
-/// @param payloadType Payload Type
-/// @param clockRate Clock rate
-/// @param maxFragmentSize Maximum NALU fragment size
-/// @param sequenceNumber Sequence number
-/// @param timestamp Timestamp
-RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, uint32_t ssrc, const char *cname,
-                                              uint8_t payloadType, uint32_t clockRate,
-                                              uint16_t maxFragmentSize, uint16_t sequenceNumber,
-                                              uint32_t timestamp);
-
-/// Set OpusPacketizationHandler for track
-/// @param tr Track id
-/// @param ssrc SSRC
-/// @param cname CName
-/// @param payloadType Payload Type
-/// @param clockRate Clock rate
-/// @param _sequenceNumber Sequence number
-/// @param _timestamp Timestamp
-RTC_EXPORT int rtcSetOpusPacketizationHandler(int tr, uint32_t ssrc, const char *cname,
-                                              uint8_t payloadType, uint32_t clockRate,
-                                              uint16_t _sequenceNumber, uint32_t _timestamp);
-
-/// Chain RtcpSrReporter to handler chain for given track
-/// @param tr Track id
-int rtcChainRtcpSrReporter(int tr);
-
-/// Chain RtcpNackResponder to handler chain for given track
-/// @param tr Track id
-/// @param maxStoredPacketsCount Maximum stored packet count
-int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount);
+// Chain RtcpSrReporter to handler chain for given track
+RTC_EXPORT int rtcChainRtcpSrReporter(int tr);
+
+// Chain RtcpNackResponder to handler chain for given track
+RTC_EXPORT int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount);
 
 
 /// Set start time for RTP stream
 /// Set start time for RTP stream
-/// @param startTime_s Start time in seconds
-/// @param timeIntervalSince1970 Set true if `startTime_s` is time interval since 1970, false if
-/// `startTime_s` is time interval since 1900
-/// @param _timestamp Start timestamp
-int rtcSetRtpConfigurationStartTime(int id, double startTime_s, bool timeIntervalSince1970,
-                                    uint32_t _timestamp);
-
-/// Start stats recording for RTCP Sender Reporter
-/// @param id Track identifier
-int rtcStartRtcpSenderReporterRecording(int id);
-
-/// Transform seconds to timestamp using track's clock rate
-/// @param id Track id
-/// @param seconds Seconds
-/// @param timestamp Pointer to result
-int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp);
-
-/// Transform timestamp to seconds using track's clock rate
-/// @param id Track id
-/// @param timestamp Timestamp
-/// @param seconds Pointer for result
-int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds);
-
-/// Get current timestamp
-/// @param id Track id
-/// @param timestamp Pointer for result
-int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp);
-
-/// Get start timestamp for track identified by given id
-/// @param id Track id
-/// @param timestamp Pointer for result
-int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp);
-
-/// Set RTP timestamp for track identified by given id
-/// @param id Track id
-/// @param timestamp New timestamp
-int rtcSetTrackRTPTimestamp(int id, uint32_t timestamp);
-
-/// Get timestamp of previous RTCP SR
-/// @param id Track id
-/// @param timestamp Pointer for result
-int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp);
-
-/// Set `NeedsToReport` flag in RtcpSrReporter handler identified by given track id
-/// @param id Track id
-int rtcSetNeedsToSendRtcpSr(int id);
+RTC_EXPORT int rtcSetRtpConfigurationStartTime(int id, const rtcStartTime *startTime);
+
+// Start stats recording for RTCP Sender Reporter
+RTC_EXPORT int rtcStartRtcpSenderReporterRecording(int id);
+
+// Transform seconds to timestamp using track's clock rate
+// Result is written to timestamp
+RTC_EXPORT int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp);
+
+// Transform timestamp to seconds using track's clock rate
+// Result is written to seconds
+RTC_EXPORT int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds);
+
+// Get current timestamp
+// Result is written to timestamp
+RTC_EXPORT int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp);
+
+// Get start timestamp for track identified by given id
+// Result is written to timestamp
+RTC_EXPORT int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp);
+
+// Set RTP timestamp for track identified by given id
+RTC_EXPORT int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp);
+
+// Get timestamp of previous RTCP SR
+// Result is written to timestamp
+RTC_EXPORT int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp);
+
+// Set NeedsToReport flag in RtcpSrReporter handler identified by given track id
+RTC_EXPORT int rtcSetNeedsToSendRtcpSr(int id);
 
 
 #endif // RTC_ENABLE_MEDIA
 #endif // RTC_ENABLE_MEDIA
 
 
-// WebSocket
 #if RTC_ENABLE_WEBSOCKET
 #if RTC_ENABLE_WEBSOCKET
+
+// WebSocket
+
 typedef struct {
 typedef struct {
 	bool disableTlsVerification; // if true, don't verify the TLS certificate
 	bool disableTlsVerification; // if true, don't verify the TLS certificate
 } rtcWsConfiguration;
 } rtcWsConfiguration;
@@ -346,9 +310,11 @@ typedef struct {
 RTC_EXPORT int rtcCreateWebSocket(const char *url); // returns ws id
 RTC_EXPORT int rtcCreateWebSocket(const char *url); // returns ws id
 RTC_EXPORT int rtcCreateWebSocketEx(const char *url, const rtcWsConfiguration *config);
 RTC_EXPORT int rtcCreateWebSocketEx(const char *url, const rtcWsConfiguration *config);
 RTC_EXPORT int rtcDeleteWebsocket(int ws);
 RTC_EXPORT int rtcDeleteWebsocket(int ws);
+
 #endif
 #endif
 
 
 // DataChannel, Track, and WebSocket common API
 // DataChannel, Track, and WebSocket common API
+
 RTC_EXPORT int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb);
 RTC_EXPORT int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb);
 RTC_EXPORT int rtcSetClosedCallback(int id, rtcClosedCallbackFunc cb);
 RTC_EXPORT int rtcSetClosedCallback(int id, rtcClosedCallbackFunc cb);
 RTC_EXPORT int rtcSetErrorCallback(int id, rtcErrorCallbackFunc cb);
 RTC_EXPORT int rtcSetErrorCallback(int id, rtcErrorCallbackFunc cb);
@@ -360,14 +326,31 @@ RTC_EXPORT int rtcSetBufferedAmountLowThreshold(int id, int amount);
 RTC_EXPORT int rtcSetBufferedAmountLowCallback(int id, rtcBufferedAmountLowCallbackFunc cb);
 RTC_EXPORT int rtcSetBufferedAmountLowCallback(int id, rtcBufferedAmountLowCallbackFunc cb);
 
 
 // DataChannel, Track, and WebSocket common extended API
 // DataChannel, Track, and WebSocket common extended API
+
 RTC_EXPORT int rtcGetAvailableAmount(int id); // total size available to receive
 RTC_EXPORT int rtcGetAvailableAmount(int id); // total size available to receive
 RTC_EXPORT int rtcSetAvailableCallback(int id, rtcAvailableCallbackFunc cb);
 RTC_EXPORT int rtcSetAvailableCallback(int id, rtcAvailableCallbackFunc cb);
 RTC_EXPORT int rtcReceiveMessage(int id, char *buffer, int *size);
 RTC_EXPORT int rtcReceiveMessage(int id, char *buffer, int *size);
 
 
-// Optional preload and cleanup
+// Optional global preload and cleanup
+
 RTC_EXPORT void rtcPreload(void);
 RTC_EXPORT void rtcPreload(void);
 RTC_EXPORT void rtcCleanup(void);
 RTC_EXPORT void rtcCleanup(void);
 
 
+// SCTP global settings
+
+typedef struct {
+	int recvBufferSize;          // in bytes, <= 0 means optimized default
+	int sendBufferSize;          // in bytes, <= 0 means optimized default
+	int maxChunksOnQueue;        // in chunks, <= 0 means optimized default
+	int initialCongestionWindow; // in MTUs, <= 0 means optimized default
+	int maxBurst;                // in MTUs, 0 means optimized default, < 0 means disabled
+	int congestionControlModule; // 0: RFC2581 (default), 1: HSTCP, 2: H-TCP, 3: RTCC
+	int delayedSackTimeMs;       // in msecs, <= 0 means optimized default
+} rtcSctpSettings;
+
+// Note: SCTP settings apply to newly-created PeerConnections only
+RTC_EXPORT int rtcSetSctpSettings(const rtcSctpSettings *settings);
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 } // extern "C"
 } // extern "C"
 #endif
 #endif

+ 145 - 178
src/capi.cpp

@@ -110,14 +110,14 @@ int emplaceTrack(shared_ptr<Track> ptr) {
 void erasePeerConnection(int pc) {
 void erasePeerConnection(int pc) {
 	std::lock_guard lock(mutex);
 	std::lock_guard lock(mutex);
 	if (peerConnectionMap.erase(pc) == 0)
 	if (peerConnectionMap.erase(pc) == 0)
-		throw std::invalid_argument("PeerConnection ID does not exist");
+		throw std::invalid_argument("Peer Connection ID does not exist");
 	userPointerMap.erase(pc);
 	userPointerMap.erase(pc);
 }
 }
 
 
 void eraseDataChannel(int dc) {
 void eraseDataChannel(int dc) {
 	std::lock_guard lock(mutex);
 	std::lock_guard lock(mutex);
 	if (dataChannelMap.erase(dc) == 0)
 	if (dataChannelMap.erase(dc) == 0)
-		throw std::invalid_argument("DataChannel ID does not exist");
+		throw std::invalid_argument("Data Channel ID does not exist");
 	userPointerMap.erase(dc);
 	userPointerMap.erase(dc);
 }
 }
 
 
@@ -140,7 +140,7 @@ shared_ptr<RtcpSrReporter> getRtcpSrReporter(int id) {
 	if (auto it = rtcpSrReporterMap.find(id); it != rtcpSrReporterMap.end()) {
 	if (auto it = rtcpSrReporterMap.find(id); it != rtcpSrReporterMap.end()) {
 		return it->second;
 		return it->second;
 	} else {
 	} else {
-		throw std::invalid_argument("RtcpSRReporter ID does not exist");
+		throw std::invalid_argument("RTCP SR reporter ID does not exist");
 	}
 	}
 }
 }
 
 
@@ -154,7 +154,7 @@ shared_ptr<MediaChainableHandler> getMediaChainableHandler(int id) {
 	if (auto it = rtcpChainableHandlerMap.find(id); it != rtcpChainableHandlerMap.end()) {
 	if (auto it = rtcpChainableHandlerMap.find(id); it != rtcpChainableHandlerMap.end()) {
 		return it->second;
 		return it->second;
 	} else {
 	} else {
-		throw std::invalid_argument("RtcpChainableHandler ID does not exist");
+		throw std::invalid_argument("RTCP chainable handler ID does not exist");
 	}
 	}
 }
 }
 
 
@@ -163,44 +163,31 @@ void emplaceMediaChainableHandler(shared_ptr<MediaChainableHandler> ptr, int tr)
 	rtcpChainableHandlerMap.emplace(std::make_pair(tr, ptr));
 	rtcpChainableHandlerMap.emplace(std::make_pair(tr, ptr));
 }
 }
 
 
-shared_ptr<RtpPacketizationConfig> getRTPConfig(int id) {
+shared_ptr<RtpPacketizationConfig> getRtpConfig(int id) {
 	std::lock_guard lock(mutex);
 	std::lock_guard lock(mutex);
 	if (auto it = rtpConfigMap.find(id); it != rtpConfigMap.end()) {
 	if (auto it = rtpConfigMap.find(id); it != rtpConfigMap.end()) {
 		return it->second;
 		return it->second;
 	} else {
 	} else {
-		throw std::invalid_argument("RTPConfiguration ID does not exist");
+		throw std::invalid_argument("RTP configuration ID does not exist");
 	}
 	}
 }
 }
 
 
-void emplaceRTPConfig(shared_ptr<RtpPacketizationConfig> ptr, int tr) {
+void emplaceRtpConfig(shared_ptr<RtpPacketizationConfig> ptr, int tr) {
 	std::lock_guard lock(mutex);
 	std::lock_guard lock(mutex);
 	rtpConfigMap.emplace(std::make_pair(tr, ptr));
 	rtpConfigMap.emplace(std::make_pair(tr, ptr));
 }
 }
 
 
-Description::Direction rtcDirectionToDirection(rtcDirection direction) {
-	switch (direction) {
-	case RTC_DIRECTION_SENDONLY:
-		return Description::Direction::SendOnly;
-	case RTC_DIRECTION_RECVONLY:
-		return Description::Direction::RecvOnly;
-	case RTC_DIRECTION_SENDRECV:
-		return Description::Direction::SendRecv;
-	case RTC_DIRECTION_INACTIVE:
-		return Description::Direction::Inactive;
-	default:
-		return Description::Direction::Unknown;
-	}
-}
-
 shared_ptr<RtpPacketizationConfig>
 shared_ptr<RtpPacketizationConfig>
-getNewRtpPacketizationConfig(uint32_t ssrc, const char *cname, uint8_t payloadType,
-                             uint32_t clockRate, uint16_t sequenceNumber, uint32_t timestamp) {
-	if (!cname) {
+createRtpPacketizationConfig(const rtcPacketizationHandlerInit *init) {
+	if (!init)
+		throw std::invalid_argument("Unexpected null pointer for packetization handler init");
+
+	if (!init->cname)
 		throw std::invalid_argument("Unexpected null pointer for cname");
 		throw std::invalid_argument("Unexpected null pointer for cname");
-	}
 
 
-	return std::make_shared<RtpPacketizationConfig>(ssrc, cname, payloadType, clockRate,
-	                                                sequenceNumber, timestamp);
+	return std::make_shared<RtpPacketizationConfig>(init->ssrc, init->cname, init->payloadType,
+	                                                init->clockRate, init->sequenceNumber,
+	                                                init->timestamp);
 }
 }
 
 
 #endif // RTC_ENABLE_MEDIA
 #endif // RTC_ENABLE_MEDIA
@@ -390,69 +377,65 @@ int rtcDeleteDataChannel(int dc) {
 	});
 	});
 }
 }
 
 
-#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);
-	}
+int rtcAddTrack(int pc, const char *mediaDescriptionSdp) {
+	return wrap([&] {
+		if (!mediaDescriptionSdp)
+			throw std::invalid_argument("Unexpected null pointer for track media description");
 
 
-	optional<string> trackID = nullopt;
-	if (_trackID) {
-		trackID = string(_trackID);
-	}
+		auto peerConnection = getPeerConnection(pc);
+		Description::Media media{string(mediaDescriptionSdp)};
+		int tr = emplaceTrack(peerConnection->addTrack(std::move(media)));
+		if (auto ptr = getUserPointer(pc))
+			rtcSetUserPointer(tr, *ptr);
 
 
-	description->addSSRC(ssrc, name, msid, trackID);
+		return tr;
+	});
 }
 }
 
 
-int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const char *_mid,
-                  rtcDirection _direction, const char *_name, const char *_msid,
-                  const char *_trackID) {
+int rtcAddTrackEx(int pc, const rtcTrackInit *init) {
 	return wrap([&] {
 	return wrap([&] {
 		auto peerConnection = getPeerConnection(pc);
 		auto peerConnection = getPeerConnection(pc);
 
 
-		auto direction = rtcDirectionToDirection(_direction);
+		if (!init)
+			throw std::invalid_argument("Unexpected null pointer for track init");
 
 
-		string mid = "video";
-		switch (codec) {
-		case RTC_CODEC_H264:
-		case RTC_CODEC_VP8:
-		case RTC_CODEC_VP9:
-			mid = "video";
-			break;
-		case RTC_CODEC_OPUS:
-			mid = "audio";
-			break;
-		}
+		auto direction = static_cast<Description::Direction>(init->direction);
 
 
-		if (_mid) {
-			mid = string(_mid);
+		string mid;
+		if (init->mid) {
+			mid = string(init->mid);
+		} else {
+			switch (init->codec) {
+			case RTC_CODEC_H264:
+			case RTC_CODEC_VP8:
+			case RTC_CODEC_VP9:
+				mid = "video";
+				break;
+			case RTC_CODEC_OPUS:
+				mid = "audio";
+				break;
+			default:
+				mid = "video";
+				break;
+			}
 		}
 		}
 
 
 		optional<Description::Media> optDescription = nullopt;
 		optional<Description::Media> optDescription = nullopt;
 
 
-		switch (codec) {
+		switch (init->codec) {
 		case RTC_CODEC_H264:
 		case RTC_CODEC_H264:
 		case RTC_CODEC_VP8:
 		case RTC_CODEC_VP8:
 		case RTC_CODEC_VP9: {
 		case RTC_CODEC_VP9: {
 			auto desc = Description::Video(mid, direction);
 			auto desc = Description::Video(mid, direction);
-			switch (codec) {
+			switch (init->codec) {
 			case RTC_CODEC_H264:
 			case RTC_CODEC_H264:
-				desc.addH264Codec(payloadType);
+				desc.addH264Codec(init->payloadType);
 				break;
 				break;
 			case RTC_CODEC_VP8:
 			case RTC_CODEC_VP8:
-				desc.addVP8Codec(payloadType);
+				desc.addVP8Codec(init->payloadType);
 				break;
 				break;
 			case RTC_CODEC_VP9:
 			case RTC_CODEC_VP9:
-				desc.addVP8Codec(payloadType);
+				desc.addVP8Codec(init->payloadType);
 				break;
 				break;
 			default:
 			default:
 				break;
 				break;
@@ -462,9 +445,9 @@ int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const
 		}
 		}
 		case RTC_CODEC_OPUS: {
 		case RTC_CODEC_OPUS: {
 			auto desc = Description::Audio(mid, direction);
 			auto desc = Description::Audio(mid, direction);
-			switch (codec) {
+			switch (init->codec) {
 			case RTC_CODEC_OPUS:
 			case RTC_CODEC_OPUS:
-				desc.addOpusCodec(payloadType);
+				desc.addOpusCodec(init->payloadType);
 				break;
 				break;
 			default:
 			default:
 				break;
 				break;
@@ -476,55 +459,77 @@ int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const
 			break;
 			break;
 		}
 		}
 
 
-		if (!optDescription.has_value()) {
+		if (!optDescription)
 			throw std::invalid_argument("Unexpected codec");
 			throw std::invalid_argument("Unexpected codec");
-		} else {
-			auto description = optDescription.value();
-			setSSRC(&description, ssrc, _name, _msid, _trackID);
 
 
-			int tr = emplaceTrack(peerConnection->addTrack(std::move(description)));
-			if (auto ptr = getUserPointer(pc)) {
-				rtcSetUserPointer(tr, *ptr);
-			}
-			return tr;
-		}
+		auto desc = std::move(*optDescription);
+		desc.addSSRC(init->ssrc, init->name ? std::make_optional(string(init->name)) : nullopt,
+		             init->msid ? std::make_optional(string(init->msid)) : nullopt,
+		             init->trackId ? std::make_optional(string(init->trackId)) : nullopt);
+
+		int tr = emplaceTrack(peerConnection->addTrack(std::move(desc)));
+
+		if (auto ptr = getUserPointer(pc))
+			rtcSetUserPointer(tr, *ptr);
+
+		return tr;
 	});
 	});
 }
 }
 
 
-int rtcSetH264PacketizationHandler(int tr, uint32_t ssrc, const char *cname, uint8_t payloadType,
-                                   uint32_t clockRate, uint16_t maxFragmentSize,
-                                   uint16_t sequenceNumber, uint32_t timestamp) {
+int rtcDeleteTrack(int tr) {
+	return wrap([&] {
+		auto track = getTrack(tr);
+		track->onOpen(nullptr);
+		track->onClosed(nullptr);
+		track->onError(nullptr);
+		track->onMessage(nullptr);
+		track->onBufferedAmountLow(nullptr);
+		track->onAvailable(nullptr);
+
+		eraseTrack(tr);
+		return RTC_ERR_SUCCESS;
+	});
+}
+
+int rtcGetTrackDescription(int tr, char *buffer, int size) {
+	return wrap([&] {
+		auto track = getTrack(tr);
+		return copyAndReturn(track->description(), buffer, size);
+	});
+}
+
+#if RTC_ENABLE_MEDIA
+
+int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
 	return wrap([&] {
 	return wrap([&] {
 		auto track = getTrack(tr);
 		auto track = getTrack(tr);
 		// create RTP configuration
 		// create RTP configuration
-		auto rtpConfig = getNewRtpPacketizationConfig(ssrc, cname, payloadType, clockRate,
-		                                              sequenceNumber, timestamp);
+		auto rtpConfig = createRtpPacketizationConfig(init);
 		// create packetizer
 		// create packetizer
+		auto maxFragmentSize = init && init->maxFragmentSize ? init->maxFragmentSize
+		                                                     : RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE;
 		auto packetizer = std::make_shared<H264RtpPacketizer>(rtpConfig, maxFragmentSize);
 		auto packetizer = std::make_shared<H264RtpPacketizer>(rtpConfig, maxFragmentSize);
 		// create H264 handler
 		// create H264 handler
 		auto h264Handler = std::make_shared<H264PacketizationHandler>(packetizer);
 		auto h264Handler = std::make_shared<H264PacketizationHandler>(packetizer);
 		emplaceMediaChainableHandler(h264Handler, tr);
 		emplaceMediaChainableHandler(h264Handler, tr);
-		emplaceRTPConfig(rtpConfig, tr);
+		emplaceRtpConfig(rtpConfig, tr);
 		// set handler
 		// set handler
 		track->setMediaHandler(h264Handler);
 		track->setMediaHandler(h264Handler);
 		return RTC_ERR_SUCCESS;
 		return RTC_ERR_SUCCESS;
 	});
 	});
 }
 }
 
 
-int rtcSetOpusPacketizationHandler(int tr, uint32_t ssrc, const char *cname, uint8_t payloadType,
-                                   uint32_t clockRate, uint16_t sequenceNumber,
-                                   uint32_t timestamp) {
+int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) {
 	return wrap([&] {
 	return wrap([&] {
 		auto track = getTrack(tr);
 		auto track = getTrack(tr);
 		// create RTP configuration
 		// create RTP configuration
-		auto rtpConfig = getNewRtpPacketizationConfig(ssrc, cname, payloadType, clockRate,
-		                                              sequenceNumber, timestamp);
+		auto rtpConfig = createRtpPacketizationConfig(init);
 		// create packetizer
 		// create packetizer
 		auto packetizer = std::make_shared<OpusRtpPacketizer>(rtpConfig);
 		auto packetizer = std::make_shared<OpusRtpPacketizer>(rtpConfig);
 		// create Opus handler
 		// create Opus handler
 		auto opusHandler = std::make_shared<OpusPacketizationHandler>(packetizer);
 		auto opusHandler = std::make_shared<OpusPacketizationHandler>(packetizer);
 		emplaceMediaChainableHandler(opusHandler, tr);
 		emplaceMediaChainableHandler(opusHandler, tr);
-		emplaceRTPConfig(rtpConfig, tr);
+		emplaceRtpConfig(rtpConfig, tr);
 		// set handler
 		// set handler
 		track->setMediaHandler(opusHandler);
 		track->setMediaHandler(opusHandler);
 		return RTC_ERR_SUCCESS;
 		return RTC_ERR_SUCCESS;
@@ -533,7 +538,7 @@ int rtcSetOpusPacketizationHandler(int tr, uint32_t ssrc, const char *cname, uin
 
 
 int rtcChainRtcpSrReporter(int tr) {
 int rtcChainRtcpSrReporter(int tr) {
 	return wrap([tr] {
 	return wrap([tr] {
-		auto config = getRTPConfig(tr);
+		auto config = getRtpConfig(tr);
 		auto reporter = std::make_shared<RtcpSrReporter>(config);
 		auto reporter = std::make_shared<RtcpSrReporter>(config);
 		emplaceRtcpSrReporter(reporter, tr);
 		emplaceRtcpSrReporter(reporter, tr);
 		auto chainableHandler = getMediaChainableHandler(tr);
 		auto chainableHandler = getMediaChainableHandler(tr);
@@ -551,15 +556,12 @@ int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount) {
 	});
 	});
 }
 }
 
 
-int rtcSetRtpConfigurationStartTime(int id, double startTime_s, bool timeIntervalSince1970,
-                                    uint32_t timestamp) {
+int rtcSetRtpConfigurationStartTime(int id, const rtcStartTime *startTime) {
 	return wrap([&] {
 	return wrap([&] {
-		auto config = getRTPConfig(id);
-		auto epoch = RtpPacketizationConfig::EpochStart::T1900;
-		if (timeIntervalSince1970) {
-			epoch = RtpPacketizationConfig::EpochStart::T1970;
-		}
-		config->setStartTime(startTime_s, epoch, timestamp);
+		auto config = getRtpConfig(id);
+		auto epoch = startTime->since1970 ? RtpPacketizationConfig::EpochStart::T1970
+		                                  : RtpPacketizationConfig::EpochStart::T1900;
+		config->setStartTime(startTime->seconds, epoch, startTime->timestamp);
 		return RTC_ERR_SUCCESS;
 		return RTC_ERR_SUCCESS;
 	});
 	});
 }
 }
@@ -574,7 +576,7 @@ int rtcStartRtcpSenderReporterRecording(int id) {
 
 
 int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) {
 int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) {
 	return wrap([&] {
 	return wrap([&] {
-		auto config = getRTPConfig(id);
+		auto config = getRtpConfig(id);
 		*timestamp = config->secondsToTimestamp(seconds);
 		*timestamp = config->secondsToTimestamp(seconds);
 		return RTC_ERR_SUCCESS;
 		return RTC_ERR_SUCCESS;
 	});
 	});
@@ -582,7 +584,7 @@ int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp)
 
 
 int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds) {
 int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds) {
 	return wrap([&] {
 	return wrap([&] {
-		auto config = getRTPConfig(id);
+		auto config = getRtpConfig(id);
 		*seconds = config->timestampToSeconds(timestamp);
 		*seconds = config->timestampToSeconds(timestamp);
 		return RTC_ERR_SUCCESS;
 		return RTC_ERR_SUCCESS;
 	});
 	});
@@ -590,7 +592,7 @@ int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds)
 
 
 int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp) {
 int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp) {
 	return wrap([&] {
 	return wrap([&] {
-		auto config = getRTPConfig(id);
+		auto config = getRtpConfig(id);
 		*timestamp = config->timestamp;
 		*timestamp = config->timestamp;
 		return RTC_ERR_SUCCESS;
 		return RTC_ERR_SUCCESS;
 	});
 	});
@@ -598,15 +600,15 @@ int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp) {
 
 
 int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp) {
 int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp) {
 	return wrap([&] {
 	return wrap([&] {
-		auto config = getRTPConfig(id);
+		auto config = getRtpConfig(id);
 		*timestamp = config->startTimestamp;
 		*timestamp = config->startTimestamp;
 		return RTC_ERR_SUCCESS;
 		return RTC_ERR_SUCCESS;
 	});
 	});
 }
 }
 
 
-int rtcSetTrackRTPTimestamp(int id, uint32_t timestamp) {
+int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp) {
 	return wrap([&] {
 	return wrap([&] {
-		auto config = getRTPConfig(id);
+		auto config = getRtpConfig(id);
 		config->timestamp = timestamp;
 		config->timestamp = timestamp;
 		return RTC_ERR_SUCCESS;
 		return RTC_ERR_SUCCESS;
 	});
 	});
@@ -629,77 +631,8 @@ int rtcSetNeedsToSendRtcpSr(int id) {
 }
 }
 
 
 #endif // RTC_ENABLE_MEDIA
 #endif // RTC_ENABLE_MEDIA
-
-int rtcAddTrack(int pc, const char *mediaDescriptionSdp) {
-	return wrap([&] {
-		if (!mediaDescriptionSdp)
-			throw std::invalid_argument("Unexpected null pointer for track media description");
-
-		auto peerConnection = getPeerConnection(pc);
-		Description::Media media{string(mediaDescriptionSdp)};
-		int tr = emplaceTrack(peerConnection->addTrack(std::move(media)));
-		if (auto ptr = getUserPointer(pc))
-			rtcSetUserPointer(tr, *ptr);
-
-		return tr;
-	});
-}
-
-int rtcDeleteTrack(int tr) {
-	return wrap([&] {
-		auto track = getTrack(tr);
-		track->onOpen(nullptr);
-		track->onClosed(nullptr);
-		track->onError(nullptr);
-		track->onMessage(nullptr);
-		track->onBufferedAmountLow(nullptr);
-		track->onAvailable(nullptr);
-
-		eraseTrack(tr);
-		return RTC_ERR_SUCCESS;
-	});
-}
-
-int rtcGetTrackDescription(int tr, char *buffer, int size) {
-	return wrap([&] {
-		auto track = getTrack(tr);
-		return copyAndReturn(track->description(), buffer, size);
-	});
-}
-
-int rtcSetSctpSettings(const rtcSctpSettings *settings) {
-	return wrap([&] {
-		SctpSettings s = {};
-
-		if (settings->recvBufferSize > 0)
-			s.recvBufferSize = size_t(settings->recvBufferSize);
-
-		if (settings->sendBufferSize > 0)
-			s.sendBufferSize = size_t(settings->sendBufferSize);
-
-		if (settings->maxChunksOnQueue > 0)
-			s.maxChunksOnQueue = size_t(settings->maxChunksOnQueue);
-
-		if (settings->initialCongestionWindow > 0)
-			s.initialCongestionWindow = size_t(settings->initialCongestionWindow);
-
-		if (settings->maxBurst > 0)
-			s.maxBurst = size_t(settings->maxBurst);
-		else if (settings->maxBurst < 0)
-			s.maxBurst = size_t(0); // setting to 0 disables, not setting chooses optimized default
-
-		if (settings->congestionControlModule >= 0)
-			s.congestionControlModule = unsigned(settings->congestionControlModule);
-
-		if (settings->delayedSackTimeMs > 0)
-			s.delayedSackTime = std::chrono::milliseconds(settings->delayedSackTimeMs);
-
-		SetSctpSettings(std::move(s));
-		return RTC_ERR_SUCCESS;
-	});
-}
-
 #if RTC_ENABLE_WEBSOCKET
 #if RTC_ENABLE_WEBSOCKET
+
 int rtcCreateWebSocket(const char *url) {
 int rtcCreateWebSocket(const char *url) {
 	return wrap([&] {
 	return wrap([&] {
 		auto ws = std::make_shared<WebSocket>();
 		auto ws = std::make_shared<WebSocket>();
@@ -732,6 +665,7 @@ int rtcDeleteWebsocket(int ws) {
 		return RTC_ERR_SUCCESS;
 		return RTC_ERR_SUCCESS;
 	});
 	});
 }
 }
+
 #endif
 #endif
 
 
 int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb) {
 int rtcSetLocalDescriptionCallback(int pc, rtcDescriptionCallbackFunc cb) {
@@ -1173,4 +1107,37 @@ int rtcReceiveMessage(int id, char *buffer, int *size) {
 }
 }
 
 
 void rtcPreload() { rtc::Preload(); }
 void rtcPreload() { rtc::Preload(); }
+
 void rtcCleanup() { rtc::Cleanup(); }
 void rtcCleanup() { rtc::Cleanup(); }
+
+int rtcSetSctpSettings(const rtcSctpSettings *settings) {
+	return wrap([&] {
+		SctpSettings s = {};
+
+		if (settings->recvBufferSize > 0)
+			s.recvBufferSize = size_t(settings->recvBufferSize);
+
+		if (settings->sendBufferSize > 0)
+			s.sendBufferSize = size_t(settings->sendBufferSize);
+
+		if (settings->maxChunksOnQueue > 0)
+			s.maxChunksOnQueue = size_t(settings->maxChunksOnQueue);
+
+		if (settings->initialCongestionWindow > 0)
+			s.initialCongestionWindow = size_t(settings->initialCongestionWindow);
+
+		if (settings->maxBurst > 0)
+			s.maxBurst = size_t(settings->maxBurst);
+		else if (settings->maxBurst < 0)
+			s.maxBurst = size_t(0); // setting to 0 disables, not setting chooses optimized default
+
+		if (settings->congestionControlModule >= 0)
+			s.congestionControlModule = unsigned(settings->congestionControlModule);
+
+		if (settings->delayedSackTimeMs > 0)
+			s.delayedSackTime = std::chrono::milliseconds(settings->delayedSackTimeMs);
+
+		SetSctpSettings(std::move(s));
+		return RTC_ERR_SUCCESS;
+	});
+}