Implemented WebRTC
This commit is contained in:
parent
dce4cddadd
commit
7e8eb634e6
20 changed files with 6712 additions and 1 deletions
1524
src/output/output_webrtc.cpp
Normal file
1524
src/output/output_webrtc.cpp
Normal file
File diff suppressed because it is too large
Load diff
173
src/output/output_webrtc.h
Normal file
173
src/output/output_webrtc.h
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
|
||||
SOME NOTES ON MIST
|
||||
|
||||
- When a user wants to start pushing video into Mist we need to
|
||||
check if the user is actually allowed to do this. When the user
|
||||
is allowed to push we have to call the function `allowPush("")`.
|
||||
|
||||
SIGNALING
|
||||
|
||||
1. Client sends the offer:
|
||||
|
||||
{
|
||||
type: "offer_sdp",
|
||||
offer_sdp: <the-client-offer-sdp>,
|
||||
}
|
||||
|
||||
Server responds with:
|
||||
|
||||
SUCCESS:
|
||||
{
|
||||
type: "on_answer_sdp",
|
||||
result: true,
|
||||
answer_sdp: <the-server-answer-sdp>,
|
||||
}
|
||||
|
||||
ERROR:
|
||||
{
|
||||
type: "on_answer_sdp",
|
||||
result: false,
|
||||
}
|
||||
|
||||
2. Client request new bitrate:
|
||||
|
||||
{
|
||||
type: "video_bitrate"
|
||||
video_bitrate: 600000
|
||||
}
|
||||
|
||||
Server responds with:
|
||||
|
||||
SUCCESS:
|
||||
{
|
||||
type: "on_video_bitrate"
|
||||
result: true
|
||||
}
|
||||
|
||||
ERROR:
|
||||
{
|
||||
type: "on_video_bitrate"
|
||||
result: false
|
||||
}
|
||||
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "output.h"
|
||||
#include "output_http.h"
|
||||
#include <mist/h264.h>
|
||||
#include <mist/http_parser.h>
|
||||
#include <mist/rtp_fec.h>
|
||||
#include <mist/sdp_media.h>
|
||||
#include <mist/socket.h>
|
||||
#include <mist/tinythread.h>
|
||||
#include <mist/websocket.h>
|
||||
#include <mist/certificate.h>
|
||||
#include <mist/stun.h>
|
||||
#include <mist/dtls_srtp_handshake.h>
|
||||
#include <mist/srtp.h>
|
||||
|
||||
#if defined(WEBRTC_PCAP)
|
||||
# include <mist/pcap.h>
|
||||
#endif
|
||||
|
||||
namespace Mist {
|
||||
|
||||
/* ------------------------------------------------ */
|
||||
|
||||
class WebRTCTrack {
|
||||
public:
|
||||
WebRTCTrack(); ///< Initializes to some defaults.
|
||||
|
||||
public:
|
||||
RTP::toDTSC rtpToDTSC; ///< Converts RTP packets into DTSC packets.
|
||||
RTP::FECSorter sorter; ///< Takes care of sorting the received RTP packet and keeps track of some statistics. Will call a callback whenever a packet can be used. (e.g. not lost, in correct order).
|
||||
RTP::Packet rtpPacketizer; ///< Used when we're sending RTP data back to the other peer.
|
||||
uint64_t payloadType; ///< The payload type that was extracted from the `m=` media line in the SDP.
|
||||
std::string localIcePwd;
|
||||
std::string localIceUFrag;
|
||||
uint32_t SSRC; ///< The SSRC of the RTP packets.
|
||||
uint32_t timestampMultiplier; ///< Used for outgoing streams to convert the DTSC timestamps into RTP timestamps.
|
||||
uint8_t ULPFECPayloadType; ///< When we've enabled FEC for a video stream this holds the payload type that is used to distinguish between ordinary video RTP packets and FEC packets.
|
||||
uint8_t REDPayloadType; ///< When using RED and ULPFEC this holds the payload type of the RED stream.
|
||||
uint8_t RTXPayloadType; ///< The retransmission payload type when we use RTX (retransmission with separate SSRC/payload type)
|
||||
uint16_t prevReceivedSequenceNumber; ///< The previously received sequence number. This is used to NACK packets when we loose one.
|
||||
};
|
||||
|
||||
/* ------------------------------------------------ */
|
||||
|
||||
class OutWebRTC : public HTTPOutput {
|
||||
public:
|
||||
OutWebRTC(Socket::Connection &myConn);
|
||||
~OutWebRTC();
|
||||
static void init(Util::Config *cfg);
|
||||
virtual void sendHeader();
|
||||
virtual void sendNext();
|
||||
virtual void onWebsocketFrame();
|
||||
bool doesWebsockets(){return true;}
|
||||
void handleWebRTCInputOutputFromThread();
|
||||
int onDTLSHandshakeWantsToWrite(const uint8_t* data, int* nbytes);
|
||||
void onRTPSorterHasPacket(const uint64_t trackID, const RTP::Packet &pkt);
|
||||
void onDTSCConverterHasPacket(const DTSC::Packet& pkt);
|
||||
void onDTSCConverterHasInitData(const uint64_t trackID, const std::string &initData);
|
||||
void onRTPPacketizerHasRTPPacket(char* data, uint32_t nbytes);
|
||||
void onRTPPacketizerHasRTCPPacket(char* data, uint32_t nbytes);
|
||||
|
||||
private:
|
||||
bool handleWebRTCInputOutput(); ///< Reads data from the UDP socket. Returns true when we read some data, othewise false.
|
||||
void handleReceivedSTUNPacket();
|
||||
void handleReceivedDTLSPacket();
|
||||
void handleReceivedRTPOrRTCPPacket();
|
||||
void handleSignalingCommand(HTTP::Websocket& webSock, const JSON::Value &command);
|
||||
bool handleSignalingCommandRemoteOffer(HTTP::Websocket &webSock, const JSON::Value &command);
|
||||
bool handleSignalingCommandRemoteOfferForInput(HTTP::Websocket &webSocket, SDP::Session &sdpSession, const std::string &sdpOffer);
|
||||
bool handleSignalingCommandRemoteOfferForOutput(HTTP::Websocket &webSocket, SDP::Session &sdpSession, const std::string &sdpOffer);
|
||||
bool handleSignalingCommandVideoBitrate(HTTP::Websocket& webSock, const JSON::Value &command);
|
||||
bool handleSignalingCommandSeek(HTTP::Websocket& webSock, const JSON::Value &command);
|
||||
bool handleSignalingCommandKeyFrameInterval(HTTP::Websocket &webSock, const JSON::Value &command); ///< Handles the command that can be used to set the keyframe interval for the current connection. We will sent RTCP PLI messages every X-millis; the other agent -should- generate keyframes when it receives PLI messages (Picture Loss Indication).
|
||||
void sendSignalingError(HTTP::Websocket& webSock, const std::string& commandType, const std::string& errorMessage);
|
||||
bool validateSignalingCommand(HTTP::Websocket& webSock, const JSON::Value &command, JSON::Value &errorResult);
|
||||
|
||||
bool createWebRTCTrackFromAnswer(const SDP::Media& mediaAnswer, const SDP::MediaFormat& formatAnswer, WebRTCTrack& result);
|
||||
void sendRTCPFeedbackREMB(const WebRTCTrack &rtcTrack);
|
||||
void sendRTCPFeedbackPLI(const WebRTCTrack &rtcTrack); ///< Picture Los Indication: request keyframe.
|
||||
void sendRTCPFeedbackRR(WebRTCTrack &rtcTrack);
|
||||
void sendRTCPFeedbackNACK(const WebRTCTrack &rtcTrack, uint16_t missingSequenceNumber); ///< Notify sender that we're missing a sequence number.
|
||||
void sendSPSPPS(DTSC::Track& dtscTrack, WebRTCTrack& rtcTrack);///< When we're streaming H264 to e.g. the browser we inject the PPS and SPS nals.
|
||||
void extractFrameSizeFromVP8KeyFrame(const DTSC::Packet &pkt);
|
||||
void updateCapabilitiesWithSDPOffer(SDP::Session &sdpSession);
|
||||
bool bindUDPSocketOnLocalCandidateAddress(uint16_t port); ///< Binds our UDP socket onto the IP address that we shared via our SDP answer. We *have to* bind on a specific IP, see https://gist.github.com/roxlu/6c5ab696840256dac71b6247bab59ce9
|
||||
std::string getLocalCandidateAddress();
|
||||
|
||||
private:
|
||||
SDP::Session sdp; ///< SDP parser.
|
||||
SDP::Answer sdpAnswer; ///< WIP: Replacing our `sdp` member ..
|
||||
Certificate cert; ///< The TLS certificate. Used to generate a fingerprint in SDP answers.
|
||||
DTLSSRTPHandshake dtlsHandshake; ///< Implements the DTLS handshake using the mbedtls library (fork).
|
||||
SRTPReader srtpReader; ///< Used to unprotect incoming RTP and RTCP data. Uses the keys that were exchanged with DTLS.
|
||||
SRTPWriter srtpWriter; ///< Used to protect our RTP and RTCP data when sending data to another peer. Uses the keys that were exchanged with DTLS.
|
||||
Socket::UDPConnection udp; ///< Our UDP socket over which WebRTC data is received and sent.
|
||||
StunReader stunReader; ///< Decodes STUN messages; during a session we keep receiving STUN messages to which we need to reply.
|
||||
std::map<uint64_t, WebRTCTrack> webrtcTracks; ///< WebRTCTracks indexed by payload type for incoming data and indexed by myMeta.tracks[].trackID for outgoing data.
|
||||
tthread::thread* webRTCInputOutputThread; ///< The thread in which we read WebRTC data when we're receive media from another peer.
|
||||
uint16_t udpPort; ///< The port on which our webrtc socket is bound. This is where we receive RTP, STUN, DTLS, etc. */
|
||||
uint32_t SSRC; ///< The SSRC for this local instance. Is used when generating RTCP reports. */
|
||||
uint64_t rtcpTimeoutInMillis; ///< When current time in millis exceeds this timeout we have to send a new RTCP packet.
|
||||
uint64_t rtcpKeyFrameTimeoutInMillis;
|
||||
uint64_t rtcpKeyFrameDelayInMillis;
|
||||
char* rtpOutBuffer; ///< Buffer into which we copy (unprotected) RTP data that we need to deliver to the other peer. This gets protected.
|
||||
uint32_t videoBitrate; ///< The bitrate to use for incoming video streams. Can be configured via the signaling channel. Defaults to 6mbit.
|
||||
|
||||
bool didReceiveKeyFrame; /* TODO burst delay */
|
||||
|
||||
#if defined(WEBRTC_PCAP)
|
||||
PCAPWriter pcapOut; ///< Used during development to write unprotected packets that can be inspected in e.g. wireshark.
|
||||
PCAPWriter pcapIn; ///< Used during development to write unprotected packets that can be inspected in e.g. wireshark.
|
||||
#endif
|
||||
|
||||
std::map<uint8_t, uint64_t> payloadTypeToWebRTCTrack; ///< Maps e.g. RED to the corresponding track. Used when input supports RED/ULPFEC; can also be used to map RTX in the future.
|
||||
};
|
||||
}
|
||||
|
||||
typedef Mist::OutWebRTC mistOut;
|
Loading…
Add table
Add a link
Reference in a new issue