- add sources.
[platform/framework/web/crosswalk.git] / src / media / cast / rtp_sender / rtp_packetizer / rtp_packetizer.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/cast/rtp_sender/rtp_packetizer/rtp_packetizer.h"
6
7 #include "base/logging.h"
8 #include "media/cast/cast_defines.h"
9 #include "media/cast/pacing/paced_sender.h"
10 #include "net/base/big_endian.h"
11
12 namespace media {
13 namespace cast {
14
15 static const uint16 kCommonRtpHeaderLength = 12;
16 static const uint16 kCastRtpHeaderLength = 7;
17 static const uint8 kCastKeyFrameBitMask = 0x80;
18 static const uint8 kCastReferenceFrameIdBitMask = 0x40;
19
20 RtpPacketizer::RtpPacketizer(PacedPacketSender* transport,
21                              PacketStorage* packet_storage,
22                              RtpPacketizerConfig rtp_packetizer_config)
23     : config_(rtp_packetizer_config),
24       transport_(transport),
25       packet_storage_(packet_storage),
26       sequence_number_(config_.sequence_number),
27       rtp_timestamp_(config_.rtp_timestamp),
28       frame_id_(0),
29       packet_id_(0),
30       send_packets_count_(0),
31       send_octet_count_(0) {
32   DCHECK(transport) << "Invalid argument";
33 }
34
35 RtpPacketizer::~RtpPacketizer() {}
36
37 void RtpPacketizer::IncomingEncodedVideoFrame(
38     const EncodedVideoFrame* video_frame,
39     const base::TimeTicks& capture_time) {
40   DCHECK(!config_.audio) << "Invalid state";
41   if (config_.audio) return;
42
43   base::TimeTicks zero_time;
44   base::TimeDelta capture_delta = capture_time - zero_time;
45
46   // Timestamp is in 90 KHz for video.
47   rtp_timestamp_ = static_cast<uint32>(capture_delta.InMilliseconds() * 90);
48   time_last_sent_rtp_timestamp_ = capture_time;
49
50   Cast(video_frame->key_frame,
51        video_frame->last_referenced_frame_id,
52        rtp_timestamp_,
53        video_frame->data);
54 }
55
56 void RtpPacketizer::IncomingEncodedAudioFrame(
57     const EncodedAudioFrame* audio_frame,
58     const base::TimeTicks& recorded_time) {
59   DCHECK(config_.audio) << "Invalid state";
60   if (!config_.audio) return;
61
62   rtp_timestamp_ += audio_frame->samples;  // Timestamp is in samples for audio.
63   time_last_sent_rtp_timestamp_ = recorded_time;
64   Cast(true, 0, rtp_timestamp_, audio_frame->data);
65 }
66
67 uint16 RtpPacketizer::NextSequenceNumber() {
68   ++sequence_number_;
69   return sequence_number_ - 1;
70 }
71
72 bool RtpPacketizer::LastSentTimestamp(base::TimeTicks* time_sent,
73                                       uint32* rtp_timestamp) const {
74   if (time_last_sent_rtp_timestamp_.is_null()) return false;
75
76   *time_sent = time_last_sent_rtp_timestamp_;
77   *rtp_timestamp = rtp_timestamp_;
78   return true;
79 }
80
81 void RtpPacketizer::Cast(bool is_key,
82                          uint8 reference_frame_id,
83                          uint32 timestamp,
84                          Packet data) {
85   uint16 rtp_header_length = kCommonRtpHeaderLength + kCastRtpHeaderLength;
86   uint16 max_length = config_.max_payload_length - rtp_header_length - 1;
87
88   // Split the payload evenly (round number up).
89   size_t num_packets = (data.size() + max_length) / max_length;
90   size_t payload_length = (data.size() + num_packets) / num_packets;
91   DCHECK_LE(payload_length, max_length) << "Invalid argument";
92
93   PacketList packets;
94
95   size_t remaining_size = data.size();
96   Packet::iterator data_iter = data.begin();
97   while (remaining_size > 0) {
98     Packet packet;
99
100     if (remaining_size < payload_length) {
101       payload_length = remaining_size;
102     }
103     remaining_size -= payload_length;
104     BuildCommonRTPheader(&packet, remaining_size == 0, timestamp);
105
106     // Build Cast header.
107     packet.push_back(
108         (is_key ? kCastKeyFrameBitMask : 0) | kCastReferenceFrameIdBitMask);
109     packet.push_back(frame_id_);
110     size_t start_size = packet.size();
111     packet.resize(start_size + 4);
112     net::BigEndianWriter big_endian_writer(&(packet[start_size]), 4);
113     big_endian_writer.WriteU16(packet_id_);
114     big_endian_writer.WriteU16(static_cast<uint16>(num_packets - 1));
115     packet.push_back(reference_frame_id);
116
117     // Copy payload data.
118     packet.insert(packet.end(), data_iter, data_iter + payload_length);
119
120     // Store packet.
121     packet_storage_->StorePacket(frame_id_, packet_id_, &packet);
122     ++packet_id_;
123     data_iter += payload_length;
124
125     // Update stats.
126     ++send_packets_count_;
127     send_octet_count_ += payload_length;
128     packets.push_back(packet);
129   }
130   DCHECK(packet_id_ == num_packets) << "Invalid state";
131
132   // Send to network.
133   transport_->SendPackets(packets);
134
135   // Prepare for next frame.
136   packet_id_ = 0;
137   frame_id_ = static_cast<uint8>(frame_id_ + 1);
138 }
139
140 void RtpPacketizer::BuildCommonRTPheader(
141     Packet* packet, bool marker_bit, uint32 time_stamp) {
142   packet->push_back(0x80);
143   packet->push_back(static_cast<uint8>(config_.payload_type) |
144                     (marker_bit ? kRtpMarkerBitMask : 0));
145   size_t start_size = packet->size();
146   packet->resize(start_size + 10);
147   net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 10);
148   big_endian_writer.WriteU16(sequence_number_);
149   big_endian_writer.WriteU32(time_stamp);
150   big_endian_writer.WriteU32(config_.ssrc);
151   ++sequence_number_;
152 }
153
154 }  // namespace cast
155 }  // namespace media