rtp_packetizer.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// found in the LICENSE file.
4424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/net/rtp/rtp_packetizer.h"
6424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/big_endian.h"
8424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/logging.h"
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/net/pacing/paced_sender.h"
10424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace media {
12424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace cast {
13424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
14424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)static const uint16 kCommonRtpHeaderLength = 12;
15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)static const uint16 kCastRtpHeaderLength = 7;
16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)static const uint8 kCastKeyFrameBitMask = 0x80;
17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)static const uint8 kCastReferenceFrameIdBitMask = 0x40;
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static const uint8 kRtpMarkerBitMask = 0x80;
19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RtpPacketizerConfig::RtpPacketizerConfig()
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : payload_type(-1),
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      max_payload_length(kMaxIpPacketSize - 28),  // Default is IP-v4/UDP.
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sequence_number(0),
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ssrc(0) {}
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RtpPacketizerConfig::~RtpPacketizerConfig() {}
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RtpPacketizer::RtpPacketizer(PacedSender* const transport,
29424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                             PacketStorage* packet_storage,
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                             RtpPacketizerConfig rtp_packetizer_config)
31424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    : config_(rtp_packetizer_config),
32424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      transport_(transport),
33424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      packet_storage_(packet_storage),
34424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      sequence_number_(config_.sequence_number),
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      rtp_timestamp_(0),
36424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      packet_id_(0),
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      send_packet_count_(0),
38424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      send_octet_count_(0) {
39424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(transport) << "Invalid argument";
40424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
41424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
42424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)RtpPacketizer::~RtpPacketizer() {}
43424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
44424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)uint16 RtpPacketizer::NextSequenceNumber() {
45424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  ++sequence_number_;
46424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return sequence_number_ - 1;
47424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
48424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RtpPacketizer::SendFrameAsPackets(const EncodedFrame& frame) {
50424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  uint16 rtp_header_length = kCommonRtpHeaderLength + kCastRtpHeaderLength;
51424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  uint16 max_length = config_.max_payload_length - rtp_header_length - 1;
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  rtp_timestamp_ = frame.rtp_timestamp;
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
54424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Split the payload evenly (round number up).
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  size_t num_packets = (frame.data.size() + max_length) / max_length;
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  size_t payload_length = (frame.data.size() + num_packets) / num_packets;
57424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK_LE(payload_length, max_length) << "Invalid argument";
58424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SendPacketVector packets;
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  size_t remaining_size = frame.data.size();
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string::const_iterator data_iter = frame.data.begin();
63424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  while (remaining_size > 0) {
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    PacketRef packet(new base::RefCountedData<Packet>);
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
66424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (remaining_size < payload_length) {
67424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      payload_length = remaining_size;
68424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
69424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    remaining_size -= payload_length;
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    BuildCommonRTPheader(
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        &packet->data, remaining_size == 0, frame.rtp_timestamp);
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
73424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Build Cast header.
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // TODO(miu): Should we always set the ref frame bit and the ref_frame_id?
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK_NE(frame.dependency, EncodedFrame::UNKNOWN_DEPENDENCY);
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    packet->data.push_back(
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        ((frame.dependency == EncodedFrame::KEY) ? kCastKeyFrameBitMask : 0) |
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)             kCastReferenceFrameIdBitMask);
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    packet->data.push_back(static_cast<uint8>(frame.frame_id));
800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    size_t start_size = packet->data.size();
810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    packet->data.resize(start_size + 4);
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::BigEndianWriter big_endian_writer(
830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        reinterpret_cast<char*>(&(packet->data[start_size])), 4);
84424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    big_endian_writer.WriteU16(packet_id_);
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    big_endian_writer.WriteU16(static_cast<uint16>(num_packets - 1));
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    packet->data.push_back(static_cast<uint8>(frame.referenced_frame_id));
87424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
88424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Copy payload data.
890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    packet->data.insert(packet->data.end(),
900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                        data_iter,
910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                        data_iter + payload_length);
928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    data_iter += payload_length;
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const PacketKey key =
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        PacedPacketSender::MakePacketKey(frame.reference_time,
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                         config_.ssrc,
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                         packet_id_++);
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    packets.push_back(make_pair(key, packet));
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
100424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Update stats.
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ++send_packet_count_;
102424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    send_octet_count_ += payload_length;
103424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
104424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(packet_id_ == num_packets) << "Invalid state";
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  packet_storage_->StoreFrame(frame.frame_id, packets);
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Send to network.
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  transport_->SendPackets(packets);
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
111424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Prepare for next frame.
112424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  packet_id_ = 0;
113424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
114424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RtpPacketizer::BuildCommonRTPheader(Packet* packet,
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         bool marker_bit,
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         uint32 time_stamp) {
118424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  packet->push_back(0x80);
119424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  packet->push_back(static_cast<uint8>(config_.payload_type) |
120424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                    (marker_bit ? kRtpMarkerBitMask : 0));
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  size_t start_size = packet->size();
12268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  packet->resize(start_size + 10);
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::BigEndianWriter big_endian_writer(
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      reinterpret_cast<char*>(&((*packet)[start_size])), 10);
125424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  big_endian_writer.WriteU16(sequence_number_);
126424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  big_endian_writer.WriteU32(time_stamp);
127424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  big_endian_writer.WriteU32(config_.ssrc);
128424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  ++sequence_number_;
129424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
130424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
131424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}  // namespace cast
132424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}  // namespace media
133