Example #1
0
 void WebRtcConnection::writeSsrc(char* buf, int len, unsigned int ssrc) {
   ELOG_DEBUG("LEN %d", len);
   RtpHeader *head = reinterpret_cast<RtpHeader*> (buf);
   RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf);
   //if it is RTCP we check it it is a compound packet
   if (chead->isRtcp()) {      
     char* movingBuf = buf;
     int rtcpLength = 0;
     int totalLength = 0;
     do{
       movingBuf+=rtcpLength;
       RtcpHeader *chead= reinterpret_cast<RtcpHeader*>(movingBuf);
       rtcpLength= (ntohs(chead->length)+1)*4;      
       totalLength+= rtcpLength;
       ELOG_DEBUG("Is RTCP, prev SSRC %u, new %u, len %d ", chead->getSSRC(), ssrc, rtcpLength);
       chead->ssrc=htonl(ssrc);
       if (chead->packettype == RTCP_PS_Feedback_PT){
         FirHeader *thefir = reinterpret_cast<FirHeader*>(movingBuf);
         if (thefir->fmt == 4){ // It is a FIR Packet, we generate it
           this->sendPLI();
         }
       }
     } while(totalLength<len);
   } else {
     head->setSSRC(ssrc);
   }
 }
Example #2
0
  int InputProcessor::unpackageVideo(unsigned char* inBuff, int inBuffLen, unsigned char* outBuff, int* gotFrame) {

    if (videoUnpackager == 0) {
      ELOG_DEBUG("Unpackager not correctly initialized");
      return -1;
    }

    int inBuffOffset = 0;
    *gotFrame = 0;
    RtpHeader* head = reinterpret_cast<RtpHeader*>(inBuff);
    if (head->getPayloadType() != 100) {
      return -1;
    }

    int l = inBuffLen - head->getHeaderLength();
    inBuffOffset+=head->getHeaderLength();

    erizo::RTPPayloadVP8* parsed = pars.parseVP8((unsigned char*) &inBuff[inBuffOffset], l);
    memcpy(outBuff, parsed->data, parsed->dataLength);
    if (head->getMarker()) {
      *gotFrame = 1;
    }
    int ret = parsed->dataLength;
    delete parsed;
    return ret;
  }
Example #3
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));
  });
}
Example #4
0
  int OutputProcessor::packageAudio(unsigned char* inBuff, int inBuffLen,
      unsigned char* outBuff, long int pts) {

    if (audioPackager == 0) {
      ELOG_DEBUG("No se ha inicializado el codec de output audio RTP");
      return -1;
    }


    timeval time;
    gettimeofday(&time, NULL);
    long millis = (time.tv_sec * 1000) + (time.tv_usec / 1000);

    RtpHeader head;
    head.setSeqNumber(audioSeqnum_++);
//    head.setTimestamp(millis*8);
    head.setMarker(1);
    if (pts==0){
//      head.setTimestamp(audioSeqnum_*160);
      head.setTimestamp(av_rescale(audioSeqnum_, (mediaInfo.audioCodec.sampleRate/1000), 1));
    }else{
//      head.setTimestamp(pts*8);
      head.setTimestamp(av_rescale(pts, mediaInfo.audioCodec.sampleRate,1000));
    }
    head.setSSRC(44444);
    head.setPayloadType(mediaInfo.rtpAudioInfo.PT);

//    memcpy (rtpAudioBuffer_, &head, head.getHeaderLength());
//    memcpy(&rtpAudioBuffer_[head.getHeaderLength()], inBuff, inBuffLen);
    memcpy (outBuff, &head, head.getHeaderLength());
    memcpy(&outBuff[head.getHeaderLength()], inBuff, inBuffLen);
    //			sink_->sendData(rtpBuffer_, l);
    //	rtpReceiver_->receiveRtpData(rtpBuffer_, (inBuffLen + RTP_HEADER_LEN));
    return (inBuffLen+head.getHeaderLength());
  }
Example #5
0
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;
}
Example #6
0
void ExternalOutput::writeVideoData(char* buf, int len) {
  RtpHeader* head = reinterpret_cast<RtpHeader*>(buf);

  uint16_t current_video_sequence_number = head->getSeqNumber();
  if (current_video_sequence_number != last_video_sequence_number_ + 1) {
    // Something screwy.  We should always see sequence numbers incrementing monotonically.
    ELOG_DEBUG("Unexpected video sequence number; current %d, previous %d",
              current_video_sequence_number, last_video_sequence_number_);
    // Restart the depacketizer so it looks for the start of a frame
    if (depacketizer_!= nullptr) {
      depacketizer_->reset();
    }
  }

  last_video_sequence_number_ = current_video_sequence_number;

  if (first_video_timestamp_ == -1) {
    first_video_timestamp_ = head->getTimestamp();
  }
  auto map_iterator = video_maps_.find(head->getPayloadType());
  if (map_iterator != video_maps_.end()) {
    updateVideoCodec(map_iterator->second);
    if (map_iterator->second.encoding_name == "VP8" || map_iterator->second.encoding_name == "H264") {
      maybeWriteVideoPacket(buf, len);
    }
  }
}
Example #7
0
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));
}
Example #8
0
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;
}
Example #9
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;
}
Example #10
0
void ExternalOutput::writeAudioData(char* buf, int len){
    RtpHeader* head = reinterpret_cast<RtpHeader*>(buf);

    if (firstAudioTimestamp_ == -1) {
        firstAudioTimestamp_ = head->getTimestamp();
    }

    timeval time;
    gettimeofday(&time, NULL);

    // Figure out our audio codec.
    if(context_->oformat->audio_codec == AV_CODEC_ID_NONE) {
        //We dont need any other payload at this time
        if(head->getPayloadType() == PCMU_8000_PT){
            context_->oformat->audio_codec = AV_CODEC_ID_PCM_MULAW;
        } else if (head->getPayloadType() == OPUS_48000_PT) {
            context_->oformat->audio_codec = AV_CODEC_ID_OPUS;
        }
    }

    initContext();

    if (audio_stream_ == NULL) {
        // not yet.
        return;
    }

    int ret = inputProcessor_->unpackageAudio(reinterpret_cast<unsigned char*>(buf), len, unpackagedAudioBuffer_);
    if (ret <= 0)
        return;

    long long currentTimestamp = head->getTimestamp();
    if (currentTimestamp - firstAudioTimestamp_ < 0) {
        // we wrapped.  add 2^32 to correct this.  We only handle a single wrap around since that's 13 hours of recording, minimum.
        currentTimestamp += 0xFFFFFFFF;
    }

    long long timestampToWrite = (currentTimestamp - firstAudioTimestamp_) / (audio_stream_->codec->time_base.den / audio_stream_->time_base.den);
    // Adjust for our start time offset
    timestampToWrite += audioOffsetMsec_ / (1000 / audio_stream_->time_base.den);   // in practice, our timebase den is 1000, so this operation is a no-op.

    /* ELOG_DEBUG("Writing audio frame %d with timestamp %u, normalized timestamp %u, audio offset msec %u, length %d, input timebase: %d/%d, target timebase: %d/%d", */
    /*            head->getSeqNumber(), head->getTimestamp(), timestampToWrite, audioOffsetMsec_, ret, */
    /*            audio_stream_->codec->time_base.num, audio_stream_->codec->time_base.den,    // timebase we requested */
    /*            audio_stream_->time_base.num, audio_stream_->time_base.den);                 // actual timebase */

    AVPacket avpkt;
    av_init_packet(&avpkt);
    avpkt.data = unpackagedAudioBuffer_;
    avpkt.size = ret;
    avpkt.pts = timestampToWrite;
    avpkt.stream_index = 1;
    av_write_frame(context_, &avpkt);
    av_free_packet(&avpkt);
}
Example #11
0
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;
}
Example #12
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
}
Example #13
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());
}
Example #14
0
bool RtcpRrGenerator::isRetransmitOfOldPacket(std::shared_ptr<dataPacket> packet) {
  RtpHeader *head = reinterpret_cast<RtpHeader*>(packet->data);
  if (!RtpUtils::sequenceNumberLessThan(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 = 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;
}
Example #15
0
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;
}
Example #16
0
int OneToManyTranscoder::deliverVideoData_(char* buf, int len) {
	memcpy(sendVideoBuffer_, buf, len);

	RtpHeader* theHead = reinterpret_cast<RtpHeader*>(buf);
//	ELOG_DEBUG("extension %d pt %u", theHead->getExtension(),
//			theHead->getPayloadType());

	if (theHead->getPayloadType() == 100) {
        ip_->deliverVideoData(sendVideoBuffer_, len);
	} else {
		this->receiveRtpData((unsigned char*) buf, len);
	}

	sentPackets_++;
	return 0;
}
Example #17
0
void MediaStream::changeDeliverPayloadType(DataPacket *dp, packetType type) {
  RtpHeader* h = reinterpret_cast<RtpHeader*>(dp->data);
  RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(dp->data);
  if (!chead->isRtcp()) {
      int internalPT = h->getPayloadType();
      int externalPT = internalPT;
      if (type == AUDIO_PACKET) {
          externalPT = remote_sdp_->getAudioExternalPT(internalPT);
      } else if (type == VIDEO_PACKET) {
          externalPT = remote_sdp_->getVideoExternalPT(externalPT);
      }
      if (internalPT != externalPT) {
          h->setPayloadType(externalPT);
      }
  }
}
Example #18
0
void ExternalOutput::writeAudioData(char* buf, int len){
    RtpHeader* head = reinterpret_cast<RtpHeader*>(buf);
    uint16_t currentAudioSequenceNumber = head->getSeqNumber();
    if (currentAudioSequenceNumber != lastAudioSequenceNumber_ + 1) {
        // Something screwy.  We should always see sequence numbers incrementing monotonically.
        ELOG_DEBUG("Unexpected audio sequence number; current %d, previous %d", currentAudioSequenceNumber, lastAudioSequenceNumber_);
    }

    lastAudioSequenceNumber_ = currentAudioSequenceNumber;
    if (firstAudioTimestamp_ == -1) {
        firstAudioTimestamp_ = head->getTimestamp();
    }

    timeval time;
    gettimeofday(&time, NULL);

    // Figure out our audio codec.
    if(context_->oformat->audio_codec == AV_CODEC_ID_NONE) {
        //We dont need any other payload at this time
        if(head->getPayloadType() == PCMU_8000_PT){
            context_->oformat->audio_codec = AV_CODEC_ID_PCM_MULAW;
        } else if (head->getPayloadType() == OPUS_48000_PT) {
            context_->oformat->audio_codec = AV_CODEC_ID_OPUS;
        }
    }

    initContext();

    if (audio_stream_ == NULL) {
        // not yet.
        return;
    }

    long long currentTimestamp = head->getTimestamp();
    if (currentTimestamp - firstAudioTimestamp_ < 0) {
        // we wrapped.  add 2^32 to correct this.  We only handle a single wrap around since that's 13 hours of recording, minimum.
        currentTimestamp += 0xFFFFFFFF;
    }

    long long timestampToWrite = (currentTimestamp - firstAudioTimestamp_) / (audio_stream_->codec->time_base.den / audio_stream_->time_base.den);
    // Adjust for our start time offset
    timestampToWrite += audioOffsetMsec_ / (1000 / audio_stream_->time_base.den);   // in practice, our timebase den is 1000, so this operation is a no-op.

    /* ELOG_DEBUG("Writing audio frame %d with timestamp %u, normalized timestamp %u, audio offset msec %u, length %d, input timebase: %d/%d, target timebase: %d/%d", */
    /*            head->getSeqNumber(), head->getTimestamp(), timestampToWrite, audioOffsetMsec_, ret, */
    /*            audio_stream_->codec->time_base.num, audio_stream_->codec->time_base.den,    // timebase we requested */
    /*            audio_stream_->time_base.num, audio_stream_->time_base.den);                 // actual timebase */

    AVPacket avpkt;
    av_init_packet(&avpkt);
    avpkt.data = (uint8_t*) buf + head->getHeaderLength();
    avpkt.size = len - head->getHeaderLength();
    avpkt.pts = timestampToWrite;
    avpkt.stream_index = 1;
    av_write_frame(context_, &avpkt);
    av_free_packet(&avpkt);
}
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));
}
Example #20
0
// parses incoming payload type, replaces occurence in buf
void MediaStream::parseIncomingPayloadType(char *buf, int len, packetType type) {
  RtcpHeader* chead = reinterpret_cast<RtcpHeader*>(buf);
  RtpHeader* h = reinterpret_cast<RtpHeader*>(buf);
  if (!chead->isRtcp()) {
    int externalPT = h->getPayloadType();
    int internalPT = externalPT;
    if (type == AUDIO_PACKET) {
      internalPT = remote_sdp_->getAudioInternalPT(externalPT);
    } else if (type == VIDEO_PACKET) {
      internalPT = remote_sdp_->getVideoInternalPT(externalPT);
    }
    if (externalPT != internalPT) {
      h->setPayloadType(internalPT);
    } else {
//        ELOG_WARN("onTransportData did not find mapping for %i", externalPT);
    }
  }
}
Example #21
0
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);
  }
}
Example #22
0
void ExternalOutput::writeAudioData(char* buf, int len) {
  RtpHeader* head = reinterpret_cast<RtpHeader*>(buf);
  uint16_t currentAudioSequenceNumber = head->getSeqNumber();
  if (first_audio_timestamp_ != -1 && currentAudioSequenceNumber != lastAudioSequenceNumber_ + 1) {
      // Something screwy.  We should always see sequence numbers incrementing monotonically.
      ELOG_DEBUG("Unexpected audio sequence number; current %d, previous %d",
                  currentAudioSequenceNumber, lastAudioSequenceNumber_);
  }

  lastAudioSequenceNumber_ = currentAudioSequenceNumber;
  if (first_audio_timestamp_ == -1) {
      first_audio_timestamp_ = head->getTimestamp();
  }

  // Figure out our audio codec.
  if (context_->oformat->audio_codec == AV_CODEC_ID_NONE) {
      // We dont need any other payload at this time
      if (head->getPayloadType() == PCMU_8000_PT) {
          context_->oformat->audio_codec = AV_CODEC_ID_PCM_MULAW;
      } else if (head->getPayloadType() == OPUS_48000_PT) {
          context_->oformat->audio_codec = AV_CODEC_ID_OPUS;
      }
  }

  initContext();

  if (audio_stream_ == NULL) {
      // not yet.
      return;
  }

  long long currentTimestamp = head->getTimestamp();  // NOLINT
  if (currentTimestamp - first_audio_timestamp_ < 0) {
      // we wrapped.  add 2^32 to correct this. We only handle a single wrap around
      // since that's 13 hours of recording, minimum.
      currentTimestamp += 0xFFFFFFFF;
  }

  long long timestampToWrite = (currentTimestamp - first_audio_timestamp_) /  // NOLINT
                                    (audio_stream_->codec->sample_rate / audio_stream_->time_base.den);
  // generally 48000 / 1000 for the denominator portion, at least for opus
  // Adjust for our start time offset

  // in practice, our timebase den is 1000, so this operation is a no-op.
  timestampToWrite += audio_offset_ms_ / (1000 / audio_stream_->time_base.den);

  AVPacket avpkt;
  av_init_packet(&avpkt);
  avpkt.data = reinterpret_cast<uint8_t*>(buf) + head->getHeaderLength();
  avpkt.size = len - head->getHeaderLength();
  avpkt.pts = timestampToWrite;
  avpkt.stream_index = 1;
  av_interleaved_write_frame(context_, &avpkt);   // takes ownership of the packet
}
Example #23
0
  // parses incoming payload type, replaces occurence in buf
  void WebRtcConnection::parseIncomingPayloadType(char *buf, int len, packetType type) {
      RtcpHeader* chead = reinterpret_cast<RtcpHeader*>(buf);
      RtpHeader* h = reinterpret_cast<RtpHeader*>(buf);
      if (!chead->isRtcp()) {
        int externalPT = h->getPayloadType();
        int internalPT = externalPT;
        if (type == AUDIO_PACKET) {
            internalPT = remoteSdp_.getAudioInternalPT(externalPT);
        } else if (type == VIDEO_PACKET) {
            internalPT = remoteSdp_.getVideoInternalPT(externalPT);
        }
        if (externalPT != internalPT) {
            h->setPayloadType(internalPT);
//            ELOG_ERROR("onTransportData mapping %i to %i", externalPT, internalPT);
        } else {
//            ELOG_ERROR("onTransportData did not find mapping for %i", externalPT);
        }
      }
  }
Example #24
0
  int OutputProcessor::packageVideo(unsigned char* inBuff, int buffSize, unsigned char* outBuff, 
      long int pts) {
    if (videoPackager == 0) {
      ELOG_DEBUG("No se ha inicailizado el codec de output vĂ­deo RTP");
      return -1;
    }

    //    ELOG_DEBUG("To packetize %u", buffSize);
    if (buffSize <= 0)
      return -1;
    RtpVP8Fragmenter frag(inBuff, buffSize, 1100);
    bool lastFrame = false;
    unsigned int outlen = 0;
    timeval time;
    gettimeofday(&time, NULL);
    long millis = (time.tv_sec * 1000) + (time.tv_usec / 1000);
    //		timestamp_ += 90000 / mediaInfo.videoCodec.frameRate;

          //int64_t pts = av_rescale(lastPts_, 1000000, (long int)video_time_base_);
    do {
      outlen = 0;
      frag.getPacket(outBuff, &outlen, &lastFrame);
      RtpHeader rtpHeader;
      rtpHeader.setMarker(lastFrame?1:0);
      rtpHeader.setSeqNumber(seqnum_++);
      if (pts==0){
          rtpHeader.setTimestamp(av_rescale(millis, 90000, 1000)); 
      }else{
          rtpHeader.setTimestamp(av_rescale(pts, 90000, 1000)); 
        
      }
      rtpHeader.setSSRC(55543);
      rtpHeader.setPayloadType(100);
      memcpy(rtpBuffer_, &rtpHeader, rtpHeader.getHeaderLength());
      memcpy(&rtpBuffer_[rtpHeader.getHeaderLength()],outBuff, outlen);

      int l = outlen + rtpHeader.getHeaderLength();
      //			sink_->sendData(rtpBuffer_, l);
      rtpReceiver_->receiveRtpData(rtpBuffer_, l);
    } while (!lastFrame);

    return 0;
  }
Example #25
0
 int WebRtcConnection::deliverVideoData_(char* buf, int len) {
   writeSsrc(buf, len, this->getVideoSinkSSRC());
   if (videoTransport_ != NULL) {
     if (videoEnabled_ == true) {
         RtpHeader* h = reinterpret_cast<RtpHeader*>(buf);
         if (h->getPayloadType() == RED_90000_PT && !remoteSdp_.supportPayloadType(RED_90000_PT)) {
             // This is a RED/FEC payload, but our remote endpoint doesn't support that (most likely because it's firefox :/ )
             // Let's go ahead and run this through our fec receiver to convert it to raw VP8
             webrtc::RTPHeader hackyHeader;
             hackyHeader.headerLength = h->getHeaderLength();
             hackyHeader.sequenceNumber = h->getSeqNumber();
             // FEC copies memory, manages its own memory, including memory passed in callbacks (in the callback, be sure to memcpy out of webrtc's buffers
             if (fec_receiver_.AddReceivedRedPacket(hackyHeader, (const uint8_t*) buf, len, ULP_90000_PT) == 0) {
                 fec_receiver_.ProcessReceivedFec();
             }
           } else {
             this->queueData(0, buf, len, videoTransport_);
         }
     }
   }
   return len;
 }
Example #26
0
void ExternalOutput::maybeWriteVideoPacket(char* buf, int len) {
  RtpHeader* head = reinterpret_cast<RtpHeader*>(buf);
  depacketizer_->fetchPacket((unsigned char*)buf, len);
  bool deliver = depacketizer_->processPacket();

  initContext();
  if (video_stream_ == nullptr) {
    // could not init our context yet.
    return;
  }

  if (deliver) {
    long long current_timestamp = head->getTimestamp();  // NOLINT
    if (current_timestamp - first_video_timestamp_ < 0) {
      // we wrapped.  add 2^32 to correct this.
      // We only handle a single wrap around since that's ~13 hours of recording, minimum.
      current_timestamp += 0xFFFFFFFF;
    }

    // All of our video offerings are using a 90khz clock.
    long long timestamp_to_write = (current_timestamp - first_video_timestamp_) /  // NOLINT
                                              (video_map_.clock_rate / video_stream_->time_base.den);

    // Adjust for our start time offset

    // in practice, our timebase den is 1000, so this operation is a no-op.
    timestamp_to_write += video_offset_ms_ / (1000 / video_stream_->time_base.den);

    AVPacket av_packet;
    av_init_packet(&av_packet);
    av_packet.data = depacketizer_->frame();
    av_packet.size = depacketizer_->frameSize();
    av_packet.pts = timestamp_to_write;
    av_packet.stream_index = 0;
    av_interleaved_write_frame(context_, &av_packet);   // takes ownership of the packet
    depacketizer_->reset();
  }
}
Example #27
0
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;
}
Example #28
0
void ExternalOutput::writeAudioData(char* buf, int len) {
  RtpHeader* head = reinterpret_cast<RtpHeader*>(buf);
  uint16_t current_audio_sequence_number = head->getSeqNumber();
  if (first_audio_timestamp_ != -1 && current_audio_sequence_number != last_audio_sequence_number_ + 1) {
      // Something screwy.  We should always see sequence numbers incrementing monotonically.
      ELOG_DEBUG("Unexpected audio sequence number; current %d, previous %d",
                  current_audio_sequence_number, last_audio_sequence_number_);
  }

  last_audio_sequence_number_ = current_audio_sequence_number;
  if (first_audio_timestamp_ == -1) {
      first_audio_timestamp_ = head->getTimestamp();
  }

  auto map_iterator = audio_maps_.find(head->getPayloadType());
  if (map_iterator != audio_maps_.end()) {
    updateAudioCodec(map_iterator->second);
  }

  initContext();

  if (audio_stream_ == nullptr) {
      // not yet.
      return;
  }

  long long current_timestamp = head->getTimestamp();  // NOLINT
  if (current_timestamp - first_audio_timestamp_ < 0) {
      // we wrapped.  add 2^32 to correct this. We only handle a single wrap around
      // since that's 13 hours of recording, minimum.
      current_timestamp += 0xFFFFFFFF;
  }

  long long timestamp_to_write = (current_timestamp - first_audio_timestamp_) /  // NOLINT
                                    (audio_stream_->codec->sample_rate / audio_stream_->time_base.den);
  // generally 48000 / 1000 for the denominator portion, at least for opus
  // Adjust for our start time offset

  // in practice, our timebase den is 1000, so this operation is a no-op.
  timestamp_to_write += audio_offset_ms_ / (1000 / audio_stream_->time_base.den);

  AVPacket av_packet;
  av_init_packet(&av_packet);
  av_packet.data = reinterpret_cast<uint8_t*>(buf) + head->getHeaderLength();
  av_packet.size = len - head->getHeaderLength();
  av_packet.pts = timestamp_to_write;
  av_packet.stream_index = 1;
  av_interleaved_write_frame(context_, &av_packet);   // takes ownership of the packet
}
Example #29
0
void ExternalOutput::queueData(char* buffer, int length, packetType type) {
  if (!recording_) {
    return;
  }

  RtcpHeader *head = reinterpret_cast<RtcpHeader*>(buffer);
  if (head->isRtcp()) {
    return;
  }

  if (first_data_received_ == time_point()) {
    first_data_received_ = clock::now();
    if (getAudioSinkSSRC() == 0) {
      ELOG_DEBUG("No audio detected");
      audio_map_ = RtpMap{0, "PCMU", 8000, AUDIO_TYPE, 1};
      audio_codec_ = AV_CODEC_ID_PCM_MULAW;
    }
  }
  if (need_to_send_fir_ && video_source_ssrc_) {
    sendFirPacket();
    need_to_send_fir_ = false;
  }

  if (type == VIDEO_PACKET) {
    RtpHeader* h = reinterpret_cast<RtpHeader*>(buffer);
    uint8_t payloadtype = h->getPayloadType();
    if (video_offset_ms_ == -1) {
      video_offset_ms_ = ClockUtils::durationToMs(clock::now() - first_data_received_);
      ELOG_DEBUG("File %s, video offset msec: %llu", context_->filename, video_offset_ms_);
      video_queue_.setTimebase(video_maps_[payloadtype].clock_rate);
    }

    // If this is a red header, let's push it to our fec_receiver_, which will spit out frames in one
    // of our other callbacks.
    // Otherwise, just stick it straight into the video queue.
    if (payloadtype == RED_90000_PT) {
      // The only things AddReceivedRedPacket uses are headerLength and sequenceNumber.
      // Unfortunately the amount of crap
      // we would have to pull in from the WebRtc project to fully construct
      // a webrtc::RTPHeader object is obscene.  So
      // let's just do this hacky fix.
      webrtc::RTPHeader hacky_header;
      hacky_header.headerLength = h->getHeaderLength();
      hacky_header.sequenceNumber = h->getSeqNumber();

      // AddReceivedRedPacket returns 0 if there's data to process
      if (0 == fec_receiver_->AddReceivedRedPacket(hacky_header, (const uint8_t*)buffer,
                                                   length, ULP_90000_PT)) {
        fec_receiver_->ProcessReceivedFec();
      }
    } else {
      video_queue_.pushPacket(buffer, length);
    }
  } else {
    if (audio_offset_ms_ == -1) {
      audio_offset_ms_ = ClockUtils::durationToMs(clock::now() - first_data_received_);
      ELOG_DEBUG("File %s, audio offset msec: %llu", context_->filename, audio_offset_ms_);

      // Let's also take a moment to set our audio queue timebase.
      RtpHeader* h = reinterpret_cast<RtpHeader*>(buffer);
      if (h->getPayloadType() == PCMU_8000_PT) {
        audio_queue_.setTimebase(8000);
      } else if (h->getPayloadType() == OPUS_48000_PT) {
        audio_queue_.setTimebase(48000);
      }
    }
    audio_queue_.pushPacket(buffer, length);
  }

  if (audio_queue_.hasData() || video_queue_.hasData()) {
    // One or both of our queues has enough data to write stuff out.  Notify our writer.
    cond_.notify_one();
  }
}
Example #30
0
void ExternalOutput::queueData(char* buffer, int length, packetType type){
    if (!recording_) {
        return;
    }

    RtcpHeader *head = reinterpret_cast<RtcpHeader*>(buffer);
    if (head->isRtcp()){
        return;
    }

    if (firstDataReceived_ == -1) {
        timeval time;
        gettimeofday(&time, NULL);
        firstDataReceived_ = (time.tv_sec * 1000) + (time.tv_usec / 1000);
        if (this->getAudioSinkSSRC() == 0){
          ELOG_DEBUG("No audio detected");
          context_->oformat->audio_codec = AV_CODEC_ID_PCM_MULAW;
        }
    }
    
    timeval time; 
    gettimeofday(&time, NULL);
    unsigned long long millis = (time.tv_sec * 1000) + (time.tv_usec / 1000);
    if (millis -lastFullIntraFrameRequest_ >FIR_INTERVAL_MS){
      this->sendFirPacket();
      lastFullIntraFrameRequest_ = millis;
    }

    if (type == VIDEO_PACKET){
        if(this->videoOffsetMsec_ == -1) {
            videoOffsetMsec_ = ((time.tv_sec * 1000) + (time.tv_usec / 1000)) - firstDataReceived_;
            ELOG_DEBUG("File %s, video offset msec: %llu", context_->filename, videoOffsetMsec_);
        }

        // If this is a red header, let's push it to our fec_receiver_, which will spit out frames in one of our other callbacks.
        // Otherwise, just stick it straight into the video queue.
        RtpHeader* h = reinterpret_cast<RtpHeader*>(buffer);
        if (h->getPayloadType() == RED_90000_PT) {
            // The only things AddReceivedRedPacket uses are headerLength and sequenceNumber.  Unfortunately the amount of crap
            // we would have to pull in from the WebRtc project to fully construct a webrtc::RTPHeader object is obscene.  So
            // let's just do this hacky fix.
            webrtc::RTPHeader hackyHeader;
            hackyHeader.headerLength = h->getHeaderLength();
            hackyHeader.sequenceNumber = h->getSeqNumber();
            fec_receiver_.AddReceivedRedPacket(hackyHeader, (const uint8_t*)buffer, length, ULP_90000_PT);
            fec_receiver_.ProcessReceivedFec();
        } else {
            videoQueue_.pushPacket(buffer, length);
        }
    }else{
        if(this->audioOffsetMsec_ == -1) {
            audioOffsetMsec_ = ((time.tv_sec * 1000) + (time.tv_usec / 1000)) - firstDataReceived_;
            ELOG_DEBUG("File %s, audio offset msec: %llu", context_->filename, audioOffsetMsec_);
        }
        audioQueue_.pushPacket(buffer, length);
    }

    if( audioQueue_.hasData() || videoQueue_.hasData()) {
        // One or both of our queues has enough data to write stuff out.  Notify our writer.
        cond_.notify_one();
    }
}