bool RRGenerationHandler::isRetransmitOfOldPacket(std::shared_ptr<dataPacket> packet, std::shared_ptr<RRPackets> rr_info) { RtpHeader *head = reinterpret_cast<RtpHeader*>(packet->data); if (!rtpSequenceLessThan(head->getSeqNumber(), rr_info->max_seq) || rr_info->jitter.jitter == 0) { return false; } int64_t time_diff_ms = static_cast<uint32_t>(packet->received_time_ms) - rr_info->last_recv_ts; int64_t timestamp_diff = static_cast<int32_t>(head->getTimestamp() - rr_info->last_rtp_ts); uint16_t clock_rate = rr_info->type == VIDEO_PACKET ? getVideoClockRate(head->getPayloadType()) : getAudioClockRate(head->getPayloadType()); int64_t rtp_time_stamp_diff_ms = timestamp_diff / clock_rate; int64_t max_delay_ms = ((2 * rr_info->jitter.jitter) / clock_rate); return time_diff_ms > rtp_time_stamp_diff_ms + max_delay_ms; }
void RtpPacketQueue::pushPacket(const char *data, int length) { const RTPHeader *currentHeader = reinterpret_cast<const RTPHeader*>(data); uint16_t currentSequenceNumber = currentHeader->getSeqNumber(); if(lastSequenceNumberGiven_ >= 0 && (rtpSequenceLessThan(currentSequenceNumber, (uint16_t)lastSequenceNumberGiven_) || currentSequenceNumber == lastSequenceNumberGiven_)) { // this sequence number is less than the stuff we've already handed out, which means it's too late to be of any value. // TODO adaptive depth? ELOG_WARN("SSRC:%u, Payload: %u, discarding very late sample %d that is <= %d. Current queue depth is %d",currentHeader->getSSRC(),currentHeader->getPayloadType(), currentSequenceNumber, lastSequenceNumberGiven_, this->getSize()); return; } // TODO this should be a secret of the dataPacket class. It should maintain its own memory // and copy stuff as necessary. boost::shared_ptr<dataPacket> packet(new dataPacket()); memcpy(packet->data, data, length); packet->length = length; // let's insert this packet where it belongs in the queue. boost::mutex::scoped_lock lock(queueMutex_); std::list<boost::shared_ptr<dataPacket> >::iterator it; for (it=queue_.begin(); it != queue_.end(); ++it) { const RTPHeader *header = reinterpret_cast<const RTPHeader*>((*it)->data); uint16_t sequenceNumber = header->getSeqNumber(); if (sequenceNumber == currentSequenceNumber) { // We already have this sequence number in the queue. ELOG_INFO("discarding duplicate sample %d", currentSequenceNumber); break; } if (this->rtpSequenceLessThan(sequenceNumber, currentSequenceNumber)) { queue_.insert(it, packet); break; } } if (it == queue_.end()) { // something old, or queue is empty. queue_.push_back(packet); } // Enforce our max queue size. while(queue_.size() > max_) { ELOG_DEBUG("RtpPacketQueue - Discarding a sample due to hitting MAX_SIZE"); queue_.pop_back(); // remove oldest samples. } }
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); } }