void RRGenerationHandler::handleRtpPacket(std::shared_ptr<dataPacket> packet) { RtpHeader *head = reinterpret_cast<RtpHeader*>(packet->data); auto rr_packet_pair = rr_info_map_.find(head->getSSRC()); if (rr_packet_pair == rr_info_map_.end()) { ELOG_DEBUG("%s message: handleRtpPacket ssrc not found, ssrc: %u", connection_->toLog(), head->getSSRC()); return; } std::shared_ptr<RRPackets> selected_packet_info = rr_packet_pair->second; uint16_t seq_num = head->getSeqNumber(); selected_packet_info->packets_received++; if (selected_packet_info->base_seq == -1) { selected_packet_info->ssrc = head->getSSRC(); selected_packet_info->base_seq = head->getSeqNumber(); } if (selected_packet_info->max_seq == -1) { selected_packet_info->max_seq = seq_num; } else if (!rtpSequenceLessThan(seq_num, selected_packet_info->max_seq)) { if (seq_num < selected_packet_info->max_seq) { selected_packet_info->cycle++; } selected_packet_info->max_seq = seq_num; } selected_packet_info->extended_seq = (selected_packet_info->cycle << 16) | selected_packet_info->max_seq; uint16_t clock_rate = selected_packet_info->type == VIDEO_PACKET ? getVideoClockRate(head->getPayloadType()) : getAudioClockRate(head->getPayloadType()); if (head->getTimestamp() != selected_packet_info->last_rtp_ts && !isRetransmitOfOldPacket(packet, selected_packet_info)) { int transit_time = static_cast<int>((packet->received_time_ms * clock_rate) - head->getTimestamp()); int delta = abs(transit_time - selected_packet_info->jitter.transit_time); if (selected_packet_info->jitter.transit_time != 0 && delta < MAX_DELAY) { selected_packet_info->jitter.jitter += (1. / 16.) * (static_cast<double>(delta) - selected_packet_info->jitter.jitter); } selected_packet_info->jitter.transit_time = transit_time; } selected_packet_info->last_rtp_ts = head->getTimestamp(); selected_packet_info->last_recv_ts = static_cast<uint32_t>(packet->received_time_ms); uint64_t now = ClockUtils::timePointToMs(clock::now()); if (selected_packet_info->next_packet_ms == 0) { // Schedule the first packet uint16_t selected_interval = selectInterval(selected_packet_info); selected_packet_info->next_packet_ms = now + selected_interval; return; } if (now >= selected_packet_info->next_packet_ms) { sendRR(selected_packet_info); } }
bool RtcpRrGenerator::handleRtpPacket(std::shared_ptr<dataPacket> packet) { RtpHeader *head = reinterpret_cast<RtpHeader*>(packet->data); if (ssrc_ != head->getSSRC()) { ELOG_DEBUG("message: handleRtpPacket ssrc not found, ssrc: %u", head->getSSRC()); return false; } uint16_t seq_num = head->getSeqNumber(); rr_info_.packets_received++; if (rr_info_.base_seq == -1) { rr_info_.base_seq = head->getSeqNumber(); } if (rr_info_.max_seq == -1) { rr_info_.max_seq = seq_num; } else if (!RtpUtils::sequenceNumberLessThan(seq_num, rr_info_.max_seq)) { if (seq_num < rr_info_.max_seq) { rr_info_.cycle++; } rr_info_.max_seq = seq_num; } rr_info_.extended_seq = (rr_info_.cycle << 16) | rr_info_.max_seq; uint16_t clock_rate = type_ == VIDEO_PACKET ? getVideoClockRate(head->getPayloadType()) : getAudioClockRate(head->getPayloadType()); if (head->getTimestamp() != rr_info_.last_rtp_ts && !isRetransmitOfOldPacket(packet)) { int transit_time = static_cast<int>((packet->received_time_ms * clock_rate) - head->getTimestamp()); int delta = abs(transit_time - rr_info_.jitter.transit_time); if (rr_info_.jitter.transit_time != 0 && delta < MAX_DELAY) { rr_info_.jitter.jitter += (1. / 16.) * (static_cast<double>(delta) - rr_info_.jitter.jitter); } rr_info_.jitter.transit_time = transit_time; } rr_info_.last_rtp_ts = head->getTimestamp(); rr_info_.last_recv_ts = static_cast<uint32_t>(packet->received_time_ms); uint64_t now = ClockUtils::timePointToMs(clock_->now()); if (rr_info_.next_packet_ms == 0) { // Schedule the first packet uint16_t selected_interval = selectInterval(); rr_info_.next_packet_ms = now + selected_interval; return false; } if (now >= rr_info_.next_packet_ms) { ELOG_DEBUG("message: should send packet, ssrc: %u", ssrc_); return true; } return false; }
void MediaStream::onTransportData(std::shared_ptr<DataPacket> packet, Transport *transport) { if ((audio_sink_ == nullptr && video_sink_ == nullptr && fb_sink_ == nullptr)) { return; } if (transport->mediaType == AUDIO_TYPE) { packet->type = AUDIO_PACKET; } else if (transport->mediaType == VIDEO_TYPE) { packet->type = VIDEO_PACKET; } char* buf = packet->data; RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); if (!chead->isRtcp()) { uint32_t recvSSRC = head->getSSRC(); if (isVideoSourceSSRC(recvSSRC)) { packet->type = VIDEO_PACKET; } else if (isAudioSourceSSRC(recvSSRC)) { packet->type = AUDIO_PACKET; } } if (!pipeline_initialized_) { ELOG_DEBUG("%s message: Pipeline not initialized yet.", toLog()); return; } pipeline_->read(std::move(packet)); }
int main(int argc, const char * argv[]) { // data setup uint32_t first = 0xFFFF | 0x1FFFFFFF; uint32_t timestamp = 0x0128; uint32_t ssrc = 0x01 | 0x02 | 0x04 | 0x08 | 0x256; int somedata[4]; // The htonl() function converts the unsigned integer hostlong from host byte order to network byte order. // on the other side: // The ntohl() function converts the unsigned integer netlong from network byte order to host byte order. somedata[0] = htonl(first); somedata[1] = htonl(timestamp); somedata[2] = htonl(ssrc); somedata[2] = htonl(ssrc); somedata[3] = htonl(ssrc); RtpHeader* head = reinterpret_cast<RtpHeader*>(somedata); printf("version: %" PRIu8 "\n", head->getVersion()); printf("padding: %" PRIu8 "\n", head->hasPadding()); printf("extension: %" PRIu8 "\n", head->getExtension()); printf("marker: %" PRIu8 "\n", head->getMarker()); printf("payload type: %" PRIu8 "\n", head->getPayloadType()); printf("sequence number: %" PRIu16 "\n", head->getSeqNumber()); printf("timestamp %" PRIu32 "\n", head->getTimestamp()); printf("ssrc %" PRIu32 "\n", head->getSSRC()); printf("header length: %u\n", head->getHeaderLength()); return 0; }
void MediaStream::onTransportData(std::shared_ptr<DataPacket> incoming_packet, Transport *transport) { if ((audio_sink_ == nullptr && video_sink_ == nullptr && fb_sink_ == nullptr)) { return; } std::shared_ptr<DataPacket> packet = std::make_shared<DataPacket>(*incoming_packet); if (transport->mediaType == AUDIO_TYPE) { packet->type = AUDIO_PACKET; } else if (transport->mediaType == VIDEO_TYPE) { packet->type = VIDEO_PACKET; } auto stream_ptr = shared_from_this(); worker_->task([stream_ptr, packet]{ if (!stream_ptr->pipeline_initialized_) { ELOG_DEBUG("%s message: Pipeline not initialized yet.", stream_ptr->toLog()); return; } char* buf = packet->data; RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); if (!chead->isRtcp()) { uint32_t recvSSRC = head->getSSRC(); if (stream_ptr->isVideoSourceSSRC(recvSSRC)) { packet->type = VIDEO_PACKET; } else if (stream_ptr->isAudioSourceSSRC(recvSSRC)) { packet->type = AUDIO_PACKET; } } stream_ptr->pipeline_->read(std::move(packet)); }); }
int ExternalOutput::deliverVideoData_(char* buf, int len) { if (videoSourceSsrc_ == 0) { RtpHeader* h = reinterpret_cast<RtpHeader*>(buf); videoSourceSsrc_ = h->getSSRC(); } this->queueData(buf, len, VIDEO_PACKET); return 0; }
int ExternalOutput::deliverVideoData_(std::shared_ptr<dataPacket> video_packet) { std::shared_ptr<dataPacket> copied_packet = std::make_shared<dataPacket>(*video_packet); if (videoSourceSsrc_ == 0) { RtpHeader* h = reinterpret_cast<RtpHeader*>(copied_packet->data); videoSourceSsrc_ = h->getSSRC(); } this->queueData(copied_packet->data, copied_packet->length, VIDEO_PACKET); return 0; }
void MediaStream::read(std::shared_ptr<DataPacket> packet) { char* buf = packet->data; int len = packet->length; // PROCESS RTCP RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); uint32_t recvSSRC = 0; if (!chead->isRtcp()) { recvSSRC = head->getSSRC(); } else if (chead->packettype == RTCP_Sender_PT) { // Sender Report recvSSRC = chead->getSSRC(); } // DELIVER FEEDBACK (RR, FEEDBACK PACKETS) if (chead->isFeedback()) { if (fb_sink_ != nullptr && should_send_feedback_) { fb_sink_->deliverFeedback(std::move(packet)); } } else { // RTP or RTCP Sender Report if (bundle_) { // Check incoming SSRC // Deliver data if (isVideoSourceSSRC(recvSSRC)) { parseIncomingPayloadType(buf, len, VIDEO_PACKET); video_sink_->deliverVideoData(std::move(packet)); } else if (isAudioSourceSSRC(recvSSRC)) { parseIncomingPayloadType(buf, len, AUDIO_PACKET); audio_sink_->deliverAudioData(std::move(packet)); } else { ELOG_DEBUG("%s read video unknownSSRC: %u, localVideoSSRC: %u, localAudioSSRC: %u", toLog(), recvSSRC, this->getVideoSourceSSRC(), this->getAudioSourceSSRC()); } } else { if (packet->type == AUDIO_PACKET && audio_sink_ != nullptr) { parseIncomingPayloadType(buf, len, AUDIO_PACKET); // Firefox does not send SSRC in SDP if (getAudioSourceSSRC() == 0) { ELOG_DEBUG("%s discoveredAudioSourceSSRC:%u", toLog(), recvSSRC); this->setAudioSourceSSRC(recvSSRC); } audio_sink_->deliverAudioData(std::move(packet)); } else if (packet->type == VIDEO_PACKET && video_sink_ != nullptr) { parseIncomingPayloadType(buf, len, VIDEO_PACKET); // Firefox does not send SSRC in SDP if (getVideoSourceSSRC() == 0) { ELOG_DEBUG("%s discoveredVideoSourceSSRC:%u", toLog(), recvSSRC); this->setVideoSourceSSRC(recvSSRC); } // change ssrc for RTP packets, don't touch here if RTCP video_sink_->deliverVideoData(std::move(packet)); } } // if not bundle } // if not Feedback }
int ExternalOutput::deliverVideoData_(std::shared_ptr<DataPacket> video_packet) { if (video_source_ssrc_ == 0) { RtpHeader* h = reinterpret_cast<RtpHeader*>(video_packet->data); video_source_ssrc_ = h->getSSRC(); } std::shared_ptr<DataPacket> copied_packet = std::make_shared<DataPacket>(*video_packet); copied_packet->type = VIDEO_PACKET; queueDataAsync(copied_packet); return 0; }
void SRPacketHandler::handleRtpPacket(std::shared_ptr<dataPacket> packet) { RtpHeader *head = reinterpret_cast<RtpHeader*>(packet->data); uint32_t ssrc = head->getSSRC(); auto sr_selected_info_iter = sr_info_map_.find(ssrc); std::shared_ptr<SRInfo> selected_info; if (sr_selected_info_iter == sr_info_map_.end()) { ELOG_DEBUG("message: Inserting new SSRC in sr_info_map, ssrc: %u", ssrc); sr_info_map_[ssrc] = std::make_shared<SRInfo>(); } selected_info = sr_info_map_[ssrc]; selected_info->sent_packets++; selected_info->sent_octets += (packet->length - head->getHeaderLength()); }
bool RtcpNackGenerator::handleRtpPacket(std::shared_ptr<dataPacket> packet) { if (packet->type != VIDEO_PACKET) { return false; } RtpHeader *head = reinterpret_cast<RtpHeader*>(packet->data); uint16_t seq_num = head->getSeqNumber(); if (head->getSSRC() != ssrc_) { ELOG_DEBUG("message: handleRtpPacket Unknown SSRC, ssrc: %u", head->getSSRC()); return false; } if (!initialized_) { highest_seq_num_ = seq_num; initialized_ = true; return 0; } if (seq_num == highest_seq_num_) { return false; } // TODO(pedro) Consider clearing the nack list if this is a keyframe if (RtpUtils::sequenceNumberLessThan(seq_num, highest_seq_num_)) { ELOG_DEBUG("message: packet out of order, ssrc: %u, seq_num: %u, highest_seq_num: %u", seq_num, highest_seq_num_, ssrc_); // Look for it in nack list, remove it if its there auto nack_info = std::find_if(nack_info_list_.begin(), nack_info_list_.end(), [seq_num](NackInfo& current_nack) { return (current_nack.seq_num == seq_num); }); if (nack_info != nack_info_list_.end()) { ELOG_DEBUG("message: Recovered Packet %u", seq_num); nack_info_list_.erase(nack_info); } return false; } bool available_nacks = addNacks(seq_num); highest_seq_num_ = seq_num; return available_nacks; }
void RtcpFeedbackGenerationHandler::read(Context *ctx, std::shared_ptr<DataPacket> packet) { // Pass packets to RR and NACK Generator RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data); if (!initialized_) { ctx->fireRead(std::move(packet)); return; } if (chead->getPacketType() == RTCP_Sender_PT) { uint32_t ssrc = chead->getSSRC(); auto generator_it = generators_map_.find(ssrc); if (generator_it != generators_map_.end()) { generator_it->second->rr_generator->handleSr(packet); } else { ELOG_DEBUG("message: no RrGenerator found, ssrc: %u", ssrc); } ctx->fireRead(std::move(packet)); return; } bool should_send_rr = false; bool should_send_nack = false; if (!chead->isRtcp()) { RtpHeader *head = reinterpret_cast<RtpHeader*>(packet->data); uint32_t ssrc = head->getSSRC(); auto generator_it = generators_map_.find(ssrc); if (generator_it != generators_map_.end()) { should_send_rr = generator_it->second->rr_generator->handleRtpPacket(packet); if (nacks_enabled_) { should_send_nack = generator_it->second->nack_generator->handleRtpPacket(packet); } } else { ELOG_DEBUG("message: no Generator found, ssrc: %u", ssrc); } if (should_send_rr || should_send_nack) { ELOG_DEBUG("message: Should send Rtcp, ssrc %u", ssrc); std::shared_ptr<DataPacket> rtcp_packet = generator_it->second->rr_generator->generateReceiverReport(); if (nacks_enabled_ && generator_it->second->nack_generator != nullptr) { generator_it->second->nack_generator->addNackPacketToRr(rtcp_packet); } ctx->fireWrite(std::move(rtcp_packet)); } } ctx->fireRead(std::move(packet)); }
void WebRtcConnection::onTransportData(char* buf, int len, Transport *transport) { if (audioSink_ == NULL && videoSink_ == NULL && fbSink_==NULL){ return; } // PROCESS STATS if (this->statsListener_){ // if there is no listener we dont process stats RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); if (head->payloadtype != RED_90000_PT && head->payloadtype != PCMU_8000_PT) thisStats_.processRtcpPacket(buf, len); } RtcpHeader* chead = reinterpret_cast<RtcpHeader*>(buf); // DELIVER FEEDBACK (RR, FEEDBACK PACKETS) if (chead->isFeedback()){ if (fbSink_ != NULL) { fbSink_->deliverFeedback(buf,len); } } else { // RTP or RTCP Sender Report if (bundle_) { // Check incoming SSRC RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); unsigned int recvSSRC; if (chead->packettype == RTCP_Sender_PT) { //Sender Report recvSSRC = chead->getSSRC(); }else{ recvSSRC = head->getSSRC(); } // Deliver data if (recvSSRC==this->getVideoSourceSSRC() || recvSSRC==this->getVideoSinkSSRC()) { videoSink_->deliverVideoData(buf, len); } else if (recvSSRC==this->getAudioSourceSSRC() || recvSSRC==this->getAudioSinkSSRC()) { audioSink_->deliverAudioData(buf, len); } else { ELOG_ERROR("Unknown SSRC %u, localVideo %u, remoteVideo %u, ignoring", recvSSRC, this->getVideoSourceSSRC(), this->getVideoSinkSSRC()); } } else if (transport->mediaType == AUDIO_TYPE) { if (audioSink_ != NULL) { RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); // Firefox does not send SSRC in SDP if (this->getAudioSourceSSRC() == 0) { ELOG_DEBUG("Audio Source SSRC is %u", head->getSSRC()); this->setAudioSourceSSRC(head->getSSRC()); //this->updateState(TRANSPORT_READY, transport); } head->setSSRC(this->getAudioSinkSSRC()); audioSink_->deliverAudioData(buf, len); } } else if (transport->mediaType == VIDEO_TYPE) { if (videoSink_ != NULL) { RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); // Firefox does not send SSRC in SDP if (this->getVideoSourceSSRC() == 0) { unsigned int recvSSRC; if (chead->packettype == RTCP_Sender_PT) { //Sender Report recvSSRC = chead->getSSRC(); } else { recvSSRC = head->getSSRC(); } ELOG_DEBUG("Video Source SSRC is %u", recvSSRC); this->setVideoSourceSSRC(recvSSRC); //this->updateState(TRANSPORT_READY, transport); } // change ssrc for RTP packets, don't touch here if RTCP if (chead->packettype != RTCP_Sender_PT) { head->setSSRC(this->getVideoSinkSSRC()); } videoSink_->deliverVideoData(buf, len); } } } }
void WebRtcConnection::onTransportData(char* buf, int len, Transport *transport) { if (audioSink_ == NULL && videoSink_ == NULL && fbSink_==NULL){ return; } // PROCESS RTCP RtcpHeader* chead = reinterpret_cast<RtcpHeader*>(buf); if (chead->isRtcp()) { thisStats_.processRtcpPacket(buf, len); if (chead->packettype == RTCP_Sender_PT) { //Sender Report rtcpProcessor_->analyzeSr(chead); } } // DELIVER FEEDBACK (RR, FEEDBACK PACKETS) if (chead->isFeedback()){ if (fbSink_ != NULL && shouldSendFeedback_) { fbSink_->deliverFeedback(buf,len); } } else { // RTP or RTCP Sender Report if (bundle_) { // Check incoming SSRC RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); uint32_t recvSSRC; if (chead->packettype == RTCP_Sender_PT) { //Sender Report recvSSRC = chead->getSSRC(); }else{ recvSSRC = head->getSSRC(); } // Deliver data if (recvSSRC==this->getVideoSourceSSRC()) { parseIncomingPayloadType(buf, len, VIDEO_PACKET); videoSink_->deliverVideoData(buf, len); } else if (recvSSRC==this->getAudioSourceSSRC()) { parseIncomingPayloadType(buf, len, AUDIO_PACKET); audioSink_->deliverAudioData(buf, len); } else { ELOG_ERROR("Unknown SSRC %u, localVideo %u, remoteVideo %u, ignoring", recvSSRC, this->getVideoSourceSSRC(), this->getVideoSinkSSRC()); } } else if (transport->mediaType == AUDIO_TYPE) { if (audioSink_ != NULL) { parseIncomingPayloadType(buf, len, AUDIO_PACKET); RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); // Firefox does not send SSRC in SDP if (this->getAudioSourceSSRC() == 0) { unsigned int recvSSRC; this->setAudioSourceSSRC(head->getSSRC()); if (chead->packettype == RTCP_Sender_PT) { // Sender Report recvSSRC = chead->getSSRC(); } else { recvSSRC = head->getSSRC(); } ELOG_DEBUG("Audio Source SSRC is %u", recvSSRC); this->setAudioSourceSSRC(recvSSRC); } audioSink_->deliverAudioData(buf, len); } } else if (transport->mediaType == VIDEO_TYPE) { if (videoSink_ != NULL) { parseIncomingPayloadType(buf, len, VIDEO_PACKET); RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); // Firefox does not send SSRC in SDP if (this->getVideoSourceSSRC() == 0) { unsigned int recvSSRC; if (chead->packettype == RTCP_Sender_PT) { //Sender Report recvSSRC = chead->getSSRC(); } else { recvSSRC = head->getSSRC(); } ELOG_DEBUG("Video Source SSRC is %u", recvSSRC); this->setVideoSourceSSRC(recvSSRC); } // change ssrc for RTP packets, don't touch here if RTCP videoSink_->deliverVideoData(buf, len); } } } // check if we need to send FB || RR messages rtcpProcessor_->checkRtcpFb(); }