#pragma once #include #include #include #include #include "dtsc.h" #define SDP_PAYLOAD_TYPE_NONE 9999 /// Define that is used to indicate a payload type is not set. #define SDP_LOSS_PREVENTION_NONE 0 #define SDP_LOSS_PREVENTION_NACK (1 << 1) /// Use simple NACK based loss prevention. (e.g. send a NACK to pusher of video stream when a packet is lost) #define SDP_LOSS_PREVENTION_ULPFEC (1 << 2) /// Use FEC (See rtp.cpp, PacketRED). When used we try to add the correct `a=rtpmap` for RED and ULPFEC to the SDP when supported by the offer. namespace SDP{ /// A MediaFormat stores the infomation that is specific for an /// encoding. With RTSP there is often just one media format /// per media line. Though with WebRTC, where an SDP is used to /// determine a common capability, one media line can contain /// different formats. These formats are indicated by with the /// attribute of the media line. For each there may /// be one or more custom properties. For each property, like /// the `encodingName` (e.g. VP8, VP9, H264, etc). we create a /// new `SDP::MediaFormat` object and store it in the `formats` /// member of `SDP::Media`. /// /// When you want to retrieve some specific data and there is a /// getter function defined for it, you SHOULD use this /// function as these functions add some extra logic based on /// the set members. class MediaFormat{ public: MediaFormat(); std::string getFormatParameterForName( const std::string &name) const; ///< Get a parameter which was part of the `a=fmtp:` line. uint32_t getAudioSampleRate() const; ///< Returns the audio sample rate. When `audioSampleRate` has been set this will be ///< returned, otherwise we use the `payloadType` to determine the samplerate or ///< return 0 when we fail to determine to samplerate. uint32_t getAudioNumChannels() const; ///< Returns the number of audio channels. When `audioNumChannels` has been set this ///< will be returned, otherwise we use the `payloadType` when it's set to determine ///< the samplerate or we return 0 when we can't determine the number of channels. uint32_t getAudioBitSize() const; ///< Returns the audio bitsize. When `audioBitSize` has been set this will be ///< returned, othwerise we use the `encodingName` to determine the right ///< `audioBitSize` or 0 when we can't determine the `audioBitSize` uint32_t getVideoRate() const; ///< Returns the video time base. When `videoRate` has been set this will ///< be returned, otherwise we use the `encodingName` to determine the ///< right value or 0 when we can't determine the video rate. uint32_t getVideoOrAudioRate() const; ///< Returns whichever rate has been set. uint64_t getPayloadType() const; ///< Returns the `payloadType` member. int32_t getPacketizationModeForH264(); ///< When this represents a h264 format this will return the ///< packetization mode when it was provided in the SDP std::string getProfileLevelIdForH264(); ///< When this represents a H264 format, this will return the profile-level-id from the format parameters. operator bool() const; public: uint64_t payloadType; ///< The payload type as set in the media line (the is -the- ///< payloadType). uint64_t associatedPayloadType; ///< From `a=fmtp: apt=`; maps this format to another payload type. int32_t audioSampleRate; ///< Samplerate of the audio type. int32_t audioNumChannels; ///< Number of audio channels extracted from the `a=fmtp` or set in ///< `setDefaultsForPayloadType()`. int32_t audioBitSize; ///< Number of bits used in case this is an audio type 8, 16, set in ///< `setDefaultsForCodec()` and `setDefaultsForPayloadType()`. int32_t videoRate; ///< Video framerate, e.g. 9000 std::string encodingName; ///< Stores the UPPERCASED encoding name from the `a=rtpmap: std::string iceUFrag; ///< From `a=ice-ufrag:, used with WebRTC / STUN. std::string icePwd; ///< From `a=ice-pwd:`, used with WebRTC / STUN std::string rtpmap; ///< The `a= value; value between brackets. std::map formatParameters; ///< Stores the var-val pairs from `a=fmtp:` entry e.g. = ///< `packetization-mode=1;profile-level-id=4d0029;sprop-parameter-sets=Z00AKeKQCADDYC3AQEBpB4kRUA==,aO48gA==` ///< */ std::set rtcpFormats; ///< Stores the `fb-val` from the line with `a=rtcp-fb: `. }; class Media{ public: Media(); bool parseMediaLine(const std::string &sdpLine); ///< Parses `m=` line. Creates a `MediaFormat` ///< entry for each of the found values. bool parseRtpMapLine( const std::string &sdpLine); ///< Parses `a=rtpmap:` line which contains the some codec ///< specific info. When this line contains the samplerate and ///< number of audio channels they will be extracted. bool parseRtspControlLine(const std::string &sdpLine); ///< Parses `a=control:` bool parseFrameRateLine(const std::string &sdpLine); ///< Parses `a=framerate:` bool parseFormatParametersLine(const std::string &sdpLine); ///< Parses `a=fmtp:`. bool parseRtcpFeedbackLine( const std::string &sdpLine); ///< Parses `a=rtcp-fb:`. See RFC4584 bool parseFingerprintLine( const std::string &sdpLine); ///< Parses `a=fingerprint: `. See ///< https://tools.ietf.org/html/rfc8122#section-5, used with WebRTC bool parseSSRCLine(const std::string &sdpLine); ///< Parses `a=ssrc:`. MediaFormat *getFormatForSdpLine( const std::string &sdpLine); ///< Returns the track to which this SDP line applies. This means that the ///< SDP line should be formatteed like: `a=something:[payloadtype]`. MediaFormat *getFormatForPayloadType( uint64_t &payloadType); ///< Finds the `MediaFormat` in `formats`. Returns NULL when no ///< format was found for the given payload type. . MediaFormat *getFormatForEncodingName( const std::string &encName); ///< Finds the `MediaFormats in `formats`. Returns NULL when no format was ///< found for the given encoding name. E.g. `VP8`, `VP9`, `H264` std::vector getFormatsForEncodingName(const std::string &encName); std::string getIcePwdForFormat( const MediaFormat &fmt); ///< The `a=ice-pwd` can be session global or media specific. This function will ///< check if the `SDP::MediaFormat` has a ice-pwd that we should use. uint32_t getSSRC() const; ///< Returns the first SSRC `a=ssrc:` value found for the media. operator bool() const; MediaFormat* getRetransMissionFormatForPayloadType(uint64_t pt); ///< When available, it resurns the RTX format that is directly associated with the media (not encapsulated with a RED header). RTX can be combined with FEC in which case it's supposed to be stored in RED packets. The `encName` should be something like H264,VP8; e.g. the format for which you want to get the RTX format. public: std::string type; ///< The `media` field of the media line: `m= `, ///< like "video" or "audio" std::string proto; ///< The `proto` field of the media line: `m= `, ///< like "video" or "audio" std::string control; ///< From `a=control:` The RTSP control url. std::string direction; ///< From `a=sendonly`, `a=recvonly` and `a=sendrecv` std::string iceUFrag; ///< From `a=ice-ufrag:, used with WebRTC / STUN. std::string icePwd; ///< From `a=ice-pwd:`, used with WebRTC / STUN std::string setupMethod; ///< From `a=setup:, used with WebRTC / STUN std::string fingerprintHash; ///< From `a=fingerprint: `, e.g. sha-256, used with ///< WebRTC / STUN std::string fingerprintValue; ///< From `a=fingerprint: `, the actual fingerprint, used ///< with WebRTC / STUN, see https://tools.ietf.org/html/rfc8122#section-5 std::string mediaID; ///< From `a=mid:`. When generating an WebRTC answer this value must ///< be the same as in the offer. std::string candidateIP; ///< Used when we generate a WebRTC answer. uint16_t candidatePort; ///< Used when we generate a WebRTC answer. uint32_t SSRC; ///< From `a=ssrc: `; the first SSRC that we encountered. double framerate; ///< From `a=framerate`. bool supportsRTCPMux; ///< From `a=rtcp-mux`, indicates if it can mux RTP and RTCP on one ///< transport channel. bool supportsRTCPReducedSize; ///< From `a=rtcp-rsize`, reduced size RTCP packets. std::string payloadTypes; ///< From `m=` line, all the payload types as string, separated by space. std::map formats; ///< Formats indexed by payload type. Payload type is the number in the ///< field(s) from the `m=` line. }; class Session{ public: bool parseSDP(const std::string &sdp); Media *getMediaForType( const std::string &type); ///< Get a `SDP::Media*` for the given type, e.g. `video` or ///< `audio`. Returns NULL when the type was not found. MediaFormat *getMediaFormatByEncodingName(const std::string &mediaType, const std::string &encodingName); bool hasReceiveOnlyMedia(); ///< Returns true when one of the media sections has a `a=recvonly` ///< attribute. This is used to determine if the other peer only ///< wants to receive or also sent data. */ public: std::vector medias; ///< For each `m=` line we create a `SDP::Media` instance. The ///< stream specific infomration is stored in a `MediaFormat` std::string icePwd; ///< From `a=ice-pwd`, this property can be session-wide or media specific. ///< Used with WebRTC and STUN when calculating the message-integrity. std::string iceUFrag; ///< From `a=ice-ufag`, this property can be session-wide or media specific. Used ///< with WebRTC and STUN when calculating the message-integrity. }; class Answer{ public: Answer(); bool parseOffer(const std::string &sdp); bool hasVideo(); ///< Check if the offer has video. bool hasAudio(); ///< Check if the offer has audio. bool enableVideo(const std::string &codecName); bool enableAudio(const std::string &codecName); void setCandidate(const std::string &ip, uint16_t port); void setFingerprint(const std::string &fingerprintSha); ///< Set the SHA265 that represents the ///< certificate that is used with DTLS. void setDirection(const std::string &dir); bool setupVideoDTSCTrack(DTSC::Track &result); bool setupAudioDTSCTrack(DTSC::Track &result); std::string toString(); private: bool enableMedia(const std::string &type, const std::string &codecName, SDP::Media &outMedia, SDP::MediaFormat &outFormat); void addLine(const std::string &fmt, ...); std::string generateSessionId(); std::string generateIceUFrag(); ///< Generates the `ice-ufrag` value. std::string generateIcePwd(); ///< Generates the `ice-pwd` value. std::string generateRandomString(const int len); std::vector splitString(const std::string &str, char delim); public: SDP::Session sdpOffer; SDP::Media answerVideoMedia; SDP::Media answerAudioMedia; SDP::MediaFormat answerVideoFormat; SDP::MediaFormat answerAudioFormat; bool isAudioEnabled; bool isVideoEnabled; std::string candidateIP; ///< We use rtcp-mux and BUNDLE; so only one candidate necessary. uint16_t candidatePort; ///< We use rtcp-mux and BUNDLE; so only one candidate necessary. std::string fingerprint; std::string direction; ///< The direction used when generating the answer SDP string. std::vector output; ///< The lines that are used when adding lines (see `addLine()` ///< for the answer sdp.). uint8_t videoLossPrevention; ///< See the SDP_LOSS_PREVENTION_* values at the top of this header. }; }