Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Side by Side Diff: chrome/browser/media/webrtc_rtp_dump_writer.cc

Issue 264793017: Implements RTP header dumping. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add WebRtcRtpDumpWriter Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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 "chrome/browser/media/webrtc_rtp_dump_writer.h"
6
7 #include "base/files/file.h"
8 #include "base/logging.h"
9 #include "content/public/browser/browser_thread.h"
10
11 using content::BrowserThread;
12
13 namespace {
14
15 // The header of the dump file.
16 struct RtpDumpFileHeader {
17 static const unsigned char kFirstLine[];
18
19 explicit RtpDumpFileHeader(const base::TimeTicks& start)
20 : start_sec(0),
21 start_usec(0),
22 source(0),
23 port(0),
24 padding(0) {
25 base::TimeDelta interval(start - base::TimeTicks());
26 start_sec = interval.InSeconds();
27 start_usec =
28 interval.InMilliseconds() * base::Time::kMicrosecondsPerMillisecond;
29 }
30
31 uint32 start_sec; // start of recording, the seconds part.
32 uint32 start_usec; // start of recording, the microseconds part.
33 uint32 source; // network source (multicast address). Always 0.
34 uint16 port; // UDP port. Always 0.
35 uint16 padding; // 2 bytes padding.
36 };
37 const unsigned char RtpDumpFileHeader::kFirstLine[] =
38 "#!rtpplay1.0 0.0.0.0/0\n";
39
40 // The header for each packet dump.
41 struct PacketDumpHeader {
42 PacketDumpHeader(const base::TimeTicks& start,
43 uint16 dump_length,
44 uint16 packet_length)
45 : packet_dump_length(dump_length),
46 packet_length(packet_length),
47 offset_ms((base::TimeTicks::Now() - start).InMilliseconds()) {}
48
49 // Length of the packet dump including this header.
50 uint16 packet_dump_length;
51
52 // Length of header + payload of the RTP packet.
53 uint16 packet_length;
54
55 // Milliseconds since the start of recording.
56 uint32 offset_ms;
57 };
58
59 bool AppendToBuffer(
60 const uint8* src, size_t src_len, std::vector<uint8>* dest) {
61 if (dest->capacity() < dest->size() + src_len)
62 return false;
63
64 for (size_t i = 0; i < src_len; ++i) {
65 dest->push_back(src[i]);
66 }
67 return true;
68 }
69
70 uint16 GetBigEndian16(const uint8* memory) {
71 return static_cast<uint16>((memory[0] << 8) | (memory[1] << 0));
72 }
73
74 void GetRtpHeaderLen(const uint8* packet, size_t length, size_t* output) {
75 static const size_t kMinRtpPacketLen = 12;
76
77 DCHECK(packet && length >= kMinRtpPacketLen && output);
78
79 // Get base header size + length of CSRCs (not counting extension yet).
80 size_t header_size = kMinRtpPacketLen + (packet[0] & 0xF) * sizeof(uint32);
81 DCHECK(length >= header_size);
82
83 // If there's an extension, read and add the extension size.
84 if (packet[0] & 0x10) {
85 DCHECK(length >= header_size + sizeof(uint32));
86
87 header_size += ((GetBigEndian16(packet + header_size + 2) + 1) *
88 sizeof(uint32));
89 DCHECK(length >= header_size);
90 }
91 *output = header_size;
92 }
93
94 } // namespace
95
96 WebRtcRtpDumpWriter::WebRtcRtpDumpWriter(
97 const base::FilePath& dump_path,
98 size_t max_dump_size,
99 const base::Closure& max_dump_size_reached_callback)
100 : dump_path_(dump_path),
101 max_dump_size_(max_dump_size),
102 max_dump_size_reached_callback_(max_dump_size_reached_callback),
103 weak_ptr_factory_(this) {}
104
105 WebRtcRtpDumpWriter::~WebRtcRtpDumpWriter() {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
107 }
108
109 void WebRtcRtpDumpWriter::WriteRtpPacket(const uint8* packet, size_t length) {
110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
111
112 static const size_t kMaxInMemoryBufferSize = 65536; // 64KB
113
114 bool succeeded = true;
115 if (!buffer_.capacity()) {
116 buffer_.reserve(std::min(kMaxInMemoryBufferSize, max_dump_size_));
117
118 start_time_ = base::TimeTicks::Now();
119
120 // Writes the dump file header.
121 succeeded = AppendToBuffer(RtpDumpFileHeader::kFirstLine,
122 arraysize(RtpDumpFileHeader::kFirstLine) - 1,
123 &buffer_);
124 DCHECK(succeeded);
125
126 RtpDumpFileHeader header(start_time_);
127 succeeded = AppendToBuffer(reinterpret_cast<uint8*>(&header),
128 sizeof(header),
129 &buffer_);
130 DCHECK(succeeded);
131 }
132
133 size_t rtp_header_length = 0;
134 GetRtpHeaderLen(packet, length, &rtp_header_length);
135 if (!rtp_header_length)
136 return;
137
138 size_t packet_dump_length = sizeof(PacketDumpHeader) + rtp_header_length;
139
140 // Flushes the buffer to disk if the buffer is full.
141 if (buffer_.capacity() < buffer_.size() + packet_dump_length)
142 Flush(base::Callback<void(bool)>());
143
144 // Writes the packet dump header.
145 PacketDumpHeader packet_header(start_time_, packet_dump_length, length);
146
147 succeeded = AppendToBuffer(reinterpret_cast<uint8*>(&packet_header),
148 sizeof(packet_header),
149 &buffer_);
150 DCHECK(succeeded);
151
152 // Writes the actual RTP packet header.
153 succeeded = AppendToBuffer(packet, rtp_header_length, &buffer_);
154 DCHECK(succeeded);
155 }
156
157 void WebRtcRtpDumpWriter::Flush(
158 const base::Callback<void(bool)>& finished_callback) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
160
161 scoped_ptr<std::vector<uint8>> new_buffer(new std::vector<uint8>());
162 new_buffer->reserve(buffer_.capacity());
163
164 new_buffer->swap(buffer_);
165
166 scoped_ptr<bool> result(new bool(false));
167
168 // OnFlushDone is necessary to avoid running the callback after this object is
Henrik Grunell 2014/05/07 09:38:19 Will this object delete the file if this happens?
169 // gone.
170 BrowserThread::PostTaskAndReply(
171 BrowserThread::FILE,
172 FROM_HERE,
173 base::Bind(&WebRtcRtpDumpWriter::CompressAndWriteToFileOnFileThread,
174 Passed(&new_buffer),
175 dump_path_,
176 result.get()),
177 base::Bind(&WebRtcRtpDumpWriter::OnFlushDone,
178 weak_ptr_factory_.GetWeakPtr(),
179 finished_callback,
180 Passed(&result)));
181 }
182
183 // static
184 void WebRtcRtpDumpWriter::CompressAndWriteToFileOnFileThread(
185 const scoped_ptr<std::vector<uint8>>& buffer,
186 const base::FilePath& dump_path,
187 bool* result) {
188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
Henrik Grunell 2014/05/07 09:38:19 OK, I see you're doing it on the FILE thread.
189
190 // TODO: implement compressing file and writing file.
191 *result = true;
192 }
193
194 void WebRtcRtpDumpWriter::OnFlushDone(
195 const base::Callback<void(bool)>& callback,
196 const scoped_ptr<bool>& result) {
197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
198
199 if(!callback.is_null())
200 callback.Run(*result);
201 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698