OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/media/webrtc_rtp_dump_writer.h" | 5 #include "chrome/browser/media/webrtc_rtp_dump_writer.h" |
6 | 6 |
| 7 #include <string.h> |
| 8 |
7 #include "base/big_endian.h" | 9 #include "base/big_endian.h" |
8 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
9 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/macros.h" |
10 #include "content/public/browser/browser_thread.h" | 13 #include "content/public/browser/browser_thread.h" |
11 #include "third_party/zlib/zlib.h" | 14 #include "third_party/zlib/zlib.h" |
12 | 15 |
13 using content::BrowserThread; | 16 using content::BrowserThread; |
14 | 17 |
15 namespace { | 18 namespace { |
16 | 19 |
17 static const size_t kMinimumGzipOutputBufferSize = 256; // In bytes. | 20 static const size_t kMinimumGzipOutputBufferSize = 256; // In bytes. |
18 | 21 |
19 const unsigned char kRtpDumpFileHeaderFirstLine[] = "#!rtpplay1.0 0.0.0.0/0\n"; | 22 const unsigned char kRtpDumpFileHeaderFirstLine[] = "#!rtpplay1.0 0.0.0.0/0\n"; |
20 static const size_t kRtpDumpFileHeaderSize = 16; // In bytes. | 23 static const size_t kRtpDumpFileHeaderSize = 16; // In bytes. |
21 | 24 |
22 // A helper for writing the header of the dump file. | 25 // A helper for writing the header of the dump file. |
23 void WriteRtpDumpFileHeaderBigEndian(base::TimeTicks start, | 26 void WriteRtpDumpFileHeaderBigEndian(base::TimeTicks start, |
24 std::vector<uint8>* output) { | 27 std::vector<uint8_t>* output) { |
25 size_t buffer_start_pos = output->size(); | 28 size_t buffer_start_pos = output->size(); |
26 output->resize(output->size() + kRtpDumpFileHeaderSize); | 29 output->resize(output->size() + kRtpDumpFileHeaderSize); |
27 | 30 |
28 char* buffer = reinterpret_cast<char*>(&(*output)[buffer_start_pos]); | 31 char* buffer = reinterpret_cast<char*>(&(*output)[buffer_start_pos]); |
29 | 32 |
30 base::TimeDelta delta = start - base::TimeTicks(); | 33 base::TimeDelta delta = start - base::TimeTicks(); |
31 uint32 start_sec = delta.InSeconds(); | 34 uint32_t start_sec = delta.InSeconds(); |
32 base::WriteBigEndian(buffer, start_sec); | 35 base::WriteBigEndian(buffer, start_sec); |
33 buffer += sizeof(start_sec); | 36 buffer += sizeof(start_sec); |
34 | 37 |
35 uint32 start_usec = | 38 uint32_t start_usec = |
36 delta.InMilliseconds() * base::Time::kMicrosecondsPerMillisecond; | 39 delta.InMilliseconds() * base::Time::kMicrosecondsPerMillisecond; |
37 base::WriteBigEndian(buffer, start_usec); | 40 base::WriteBigEndian(buffer, start_usec); |
38 buffer += sizeof(start_usec); | 41 buffer += sizeof(start_usec); |
39 | 42 |
40 // Network source, always 0. | 43 // Network source, always 0. |
41 base::WriteBigEndian(buffer, uint32(0)); | 44 base::WriteBigEndian(buffer, uint32_t(0)); |
42 buffer += sizeof(uint32); | 45 buffer += sizeof(uint32_t); |
43 | 46 |
44 // UDP port, always 0. | 47 // UDP port, always 0. |
45 base::WriteBigEndian(buffer, uint16(0)); | 48 base::WriteBigEndian(buffer, uint16_t(0)); |
46 buffer += sizeof(uint16); | 49 buffer += sizeof(uint16_t); |
47 | 50 |
48 // 2 bytes padding. | 51 // 2 bytes padding. |
49 base::WriteBigEndian(buffer, uint16(0)); | 52 base::WriteBigEndian(buffer, uint16_t(0)); |
50 } | 53 } |
51 | 54 |
52 // The header size for each packet dump. | 55 // The header size for each packet dump. |
53 static const size_t kPacketDumpHeaderSize = 8; // In bytes. | 56 static const size_t kPacketDumpHeaderSize = 8; // In bytes. |
54 | 57 |
55 // A helper for writing the header for each packet dump. | 58 // A helper for writing the header for each packet dump. |
56 // |start| is the time when the recording is started. | 59 // |start| is the time when the recording is started. |
57 // |dump_length| is the length of the packet dump including this header. | 60 // |dump_length| is the length of the packet dump including this header. |
58 // |packet_length| is the length of the RTP packet header. | 61 // |packet_length| is the length of the RTP packet header. |
59 void WritePacketDumpHeaderBigEndian(const base::TimeTicks& start, | 62 void WritePacketDumpHeaderBigEndian(const base::TimeTicks& start, |
60 uint16 dump_length, | 63 uint16_t dump_length, |
61 uint16 packet_length, | 64 uint16_t packet_length, |
62 std::vector<uint8>* output) { | 65 std::vector<uint8_t>* output) { |
63 size_t buffer_start_pos = output->size(); | 66 size_t buffer_start_pos = output->size(); |
64 output->resize(output->size() + kPacketDumpHeaderSize); | 67 output->resize(output->size() + kPacketDumpHeaderSize); |
65 | 68 |
66 char* buffer = reinterpret_cast<char*>(&(*output)[buffer_start_pos]); | 69 char* buffer = reinterpret_cast<char*>(&(*output)[buffer_start_pos]); |
67 | 70 |
68 base::WriteBigEndian(buffer, dump_length); | 71 base::WriteBigEndian(buffer, dump_length); |
69 buffer += sizeof(dump_length); | 72 buffer += sizeof(dump_length); |
70 | 73 |
71 base::WriteBigEndian(buffer, packet_length); | 74 base::WriteBigEndian(buffer, packet_length); |
72 buffer += sizeof(packet_length); | 75 buffer += sizeof(packet_length); |
73 | 76 |
74 uint32 elapsed = | 77 uint32_t elapsed = |
75 static_cast<uint32>((base::TimeTicks::Now() - start).InMilliseconds()); | 78 static_cast<uint32_t>((base::TimeTicks::Now() - start).InMilliseconds()); |
76 base::WriteBigEndian(buffer, elapsed); | 79 base::WriteBigEndian(buffer, elapsed); |
77 } | 80 } |
78 | 81 |
79 // Append |src_len| bytes from |src| to |dest|. | 82 // Append |src_len| bytes from |src| to |dest|. |
80 void AppendToBuffer(const uint8* src, | 83 void AppendToBuffer(const uint8_t* src, |
81 size_t src_len, | 84 size_t src_len, |
82 std::vector<uint8>* dest) { | 85 std::vector<uint8_t>* dest) { |
83 size_t old_dest_size = dest->size(); | 86 size_t old_dest_size = dest->size(); |
84 dest->resize(old_dest_size + src_len); | 87 dest->resize(old_dest_size + src_len); |
85 memcpy(&(*dest)[old_dest_size], src, src_len); | 88 memcpy(&(*dest)[old_dest_size], src, src_len); |
86 } | 89 } |
87 | 90 |
88 } // namespace | 91 } // namespace |
89 | 92 |
90 // This class is running on the FILE thread for compressing and writing the | 93 // This class is running on the FILE thread for compressing and writing the |
91 // dump buffer to disk. | 94 // dump buffer to disk. |
92 class WebRtcRtpDumpWriter::FileThreadWorker { | 95 class WebRtcRtpDumpWriter::FileThreadWorker { |
(...skipping 18 matching lines...) Expand all Loading... |
111 DCHECK(thread_checker_.CalledOnValidThread()); | 114 DCHECK(thread_checker_.CalledOnValidThread()); |
112 | 115 |
113 // Makes sure all allocations are freed. | 116 // Makes sure all allocations are freed. |
114 deflateEnd(&stream_); | 117 deflateEnd(&stream_); |
115 } | 118 } |
116 | 119 |
117 // Compresses the data in |buffer| and write to the dump file. If |end_stream| | 120 // Compresses the data in |buffer| and write to the dump file. If |end_stream| |
118 // is true, the compression stream will be ended and the dump file cannot be | 121 // is true, the compression stream will be ended and the dump file cannot be |
119 // written to any more. | 122 // written to any more. |
120 void CompressAndWriteToFileOnFileThread( | 123 void CompressAndWriteToFileOnFileThread( |
121 scoped_ptr<std::vector<uint8> > buffer, | 124 scoped_ptr<std::vector<uint8_t>> buffer, |
122 bool end_stream, | 125 bool end_stream, |
123 FlushResult* result, | 126 FlushResult* result, |
124 size_t* bytes_written) { | 127 size_t* bytes_written) { |
125 DCHECK(thread_checker_.CalledOnValidThread()); | 128 DCHECK(thread_checker_.CalledOnValidThread()); |
126 | 129 |
127 // This is called either when the in-memory buffer is full or the dump | 130 // This is called either when the in-memory buffer is full or the dump |
128 // should be ended. | 131 // should be ended. |
129 DCHECK(!buffer->empty() || end_stream); | 132 DCHECK(!buffer->empty() || end_stream); |
130 | 133 |
131 *result = FLUSH_RESULT_SUCCESS; | 134 *result = FLUSH_RESULT_SUCCESS; |
132 *bytes_written = 0; | 135 *bytes_written = 0; |
133 | 136 |
134 // There may be nothing to compress/write if there is no RTP packet since | 137 // There may be nothing to compress/write if there is no RTP packet since |
135 // the last flush. | 138 // the last flush. |
136 if (!buffer->empty()) { | 139 if (!buffer->empty()) { |
137 *bytes_written = CompressAndWriteBufferToFile(buffer.get(), result); | 140 *bytes_written = CompressAndWriteBufferToFile(buffer.get(), result); |
138 } else if (!base::PathExists(dump_path_)) { | 141 } else if (!base::PathExists(dump_path_)) { |
139 // If the dump does not exist, it means there is no RTP packet recorded. | 142 // If the dump does not exist, it means there is no RTP packet recorded. |
140 // Return FLUSH_RESULT_NO_DATA to indicate no dump file created. | 143 // Return FLUSH_RESULT_NO_DATA to indicate no dump file created. |
141 *result = FLUSH_RESULT_NO_DATA; | 144 *result = FLUSH_RESULT_NO_DATA; |
142 } | 145 } |
143 | 146 |
144 if (end_stream && !EndDumpFile()) | 147 if (end_stream && !EndDumpFile()) |
145 *result = FLUSH_RESULT_FAILURE; | 148 *result = FLUSH_RESULT_FAILURE; |
146 } | 149 } |
147 | 150 |
148 private: | 151 private: |
149 // Helper for CompressAndWriteToFileOnFileThread to compress and write one | 152 // Helper for CompressAndWriteToFileOnFileThread to compress and write one |
150 // dump. | 153 // dump. |
151 size_t CompressAndWriteBufferToFile(std::vector<uint8>* buffer, | 154 size_t CompressAndWriteBufferToFile(std::vector<uint8_t>* buffer, |
152 FlushResult* result) { | 155 FlushResult* result) { |
153 DCHECK(thread_checker_.CalledOnValidThread()); | 156 DCHECK(thread_checker_.CalledOnValidThread()); |
154 DCHECK(buffer->size()); | 157 DCHECK(buffer->size()); |
155 | 158 |
156 *result = FLUSH_RESULT_SUCCESS; | 159 *result = FLUSH_RESULT_SUCCESS; |
157 | 160 |
158 std::vector<uint8> compressed_buffer; | 161 std::vector<uint8_t> compressed_buffer; |
159 if (!Compress(buffer, &compressed_buffer)) { | 162 if (!Compress(buffer, &compressed_buffer)) { |
160 DVLOG(2) << "Compressing buffer failed."; | 163 DVLOG(2) << "Compressing buffer failed."; |
161 *result = FLUSH_RESULT_FAILURE; | 164 *result = FLUSH_RESULT_FAILURE; |
162 return 0; | 165 return 0; |
163 } | 166 } |
164 | 167 |
165 int bytes_written = -1; | 168 int bytes_written = -1; |
166 | 169 |
167 if (base::PathExists(dump_path_)) { | 170 if (base::PathExists(dump_path_)) { |
168 bytes_written = | 171 bytes_written = |
(...skipping 13 matching lines...) Expand all Loading... |
182 DVLOG(2) << "Writing file failed: " << dump_path_.value(); | 185 DVLOG(2) << "Writing file failed: " << dump_path_.value(); |
183 *result = FLUSH_RESULT_FAILURE; | 186 *result = FLUSH_RESULT_FAILURE; |
184 return 0; | 187 return 0; |
185 } | 188 } |
186 | 189 |
187 DCHECK_EQ(static_cast<size_t>(bytes_written), compressed_buffer.size()); | 190 DCHECK_EQ(static_cast<size_t>(bytes_written), compressed_buffer.size()); |
188 return bytes_written; | 191 return bytes_written; |
189 } | 192 } |
190 | 193 |
191 // Compresses |input| into |output|. | 194 // Compresses |input| into |output|. |
192 bool Compress(std::vector<uint8>* input, std::vector<uint8>* output) { | 195 bool Compress(std::vector<uint8_t>* input, std::vector<uint8_t>* output) { |
193 DCHECK(thread_checker_.CalledOnValidThread()); | 196 DCHECK(thread_checker_.CalledOnValidThread()); |
194 int result = Z_OK; | 197 int result = Z_OK; |
195 | 198 |
196 output->resize(std::max(kMinimumGzipOutputBufferSize, input->size())); | 199 output->resize(std::max(kMinimumGzipOutputBufferSize, input->size())); |
197 | 200 |
198 stream_.next_in = &(*input)[0]; | 201 stream_.next_in = &(*input)[0]; |
199 stream_.avail_in = input->size(); | 202 stream_.avail_in = input->size(); |
200 stream_.next_out = &(*output)[0]; | 203 stream_.next_out = &(*output)[0]; |
201 stream_.avail_out = output->size(); | 204 stream_.avail_out = output->size(); |
202 | 205 |
203 result = deflate(&stream_, Z_SYNC_FLUSH); | 206 result = deflate(&stream_, Z_SYNC_FLUSH); |
204 DCHECK_EQ(Z_OK, result); | 207 DCHECK_EQ(Z_OK, result); |
205 DCHECK_EQ(0U, stream_.avail_in); | 208 DCHECK_EQ(0U, stream_.avail_in); |
206 | 209 |
207 output->resize(output->size() - stream_.avail_out); | 210 output->resize(output->size() - stream_.avail_out); |
208 | 211 |
209 stream_.next_in = NULL; | 212 stream_.next_in = NULL; |
210 stream_.next_out = NULL; | 213 stream_.next_out = NULL; |
211 stream_.avail_out = 0; | 214 stream_.avail_out = 0; |
212 return true; | 215 return true; |
213 } | 216 } |
214 | 217 |
215 // Ends the compression stream and completes the dump file. | 218 // Ends the compression stream and completes the dump file. |
216 bool EndDumpFile() { | 219 bool EndDumpFile() { |
217 DCHECK(thread_checker_.CalledOnValidThread()); | 220 DCHECK(thread_checker_.CalledOnValidThread()); |
218 | 221 |
219 std::vector<uint8> output_buffer; | 222 std::vector<uint8_t> output_buffer; |
220 output_buffer.resize(kMinimumGzipOutputBufferSize); | 223 output_buffer.resize(kMinimumGzipOutputBufferSize); |
221 | 224 |
222 stream_.next_in = NULL; | 225 stream_.next_in = NULL; |
223 stream_.avail_in = 0; | 226 stream_.avail_in = 0; |
224 stream_.next_out = &output_buffer[0]; | 227 stream_.next_out = &output_buffer[0]; |
225 stream_.avail_out = output_buffer.size(); | 228 stream_.avail_out = output_buffer.size(); |
226 | 229 |
227 int result = deflate(&stream_, Z_FINISH); | 230 int result = deflate(&stream_, Z_FINISH); |
228 DCHECK_EQ(Z_STREAM_END, result); | 231 DCHECK_EQ(Z_STREAM_END, result); |
229 | 232 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 | 270 |
268 bool success = BrowserThread::DeleteSoon( | 271 bool success = BrowserThread::DeleteSoon( |
269 BrowserThread::FILE, FROM_HERE, incoming_file_thread_worker_.release()); | 272 BrowserThread::FILE, FROM_HERE, incoming_file_thread_worker_.release()); |
270 DCHECK(success); | 273 DCHECK(success); |
271 | 274 |
272 success = BrowserThread::DeleteSoon( | 275 success = BrowserThread::DeleteSoon( |
273 BrowserThread::FILE, FROM_HERE, outgoing_file_thread_worker_.release()); | 276 BrowserThread::FILE, FROM_HERE, outgoing_file_thread_worker_.release()); |
274 DCHECK(success); | 277 DCHECK(success); |
275 } | 278 } |
276 | 279 |
277 void WebRtcRtpDumpWriter::WriteRtpPacket(const uint8* packet_header, | 280 void WebRtcRtpDumpWriter::WriteRtpPacket(const uint8_t* packet_header, |
278 size_t header_length, | 281 size_t header_length, |
279 size_t packet_length, | 282 size_t packet_length, |
280 bool incoming) { | 283 bool incoming) { |
281 DCHECK(thread_checker_.CalledOnValidThread()); | 284 DCHECK(thread_checker_.CalledOnValidThread()); |
282 | 285 |
283 static const size_t kMaxInMemoryBufferSize = 65536; | 286 static const size_t kMaxInMemoryBufferSize = 65536; |
284 | 287 |
285 std::vector<uint8>* dest_buffer = | 288 std::vector<uint8_t>* dest_buffer = |
286 incoming ? &incoming_buffer_ : &outgoing_buffer_; | 289 incoming ? &incoming_buffer_ : &outgoing_buffer_; |
287 | 290 |
288 // We use the capacity of the buffer to indicate if the buffer has been | 291 // We use the capacity of the buffer to indicate if the buffer has been |
289 // initialized and if the dump file header has been created. | 292 // initialized and if the dump file header has been created. |
290 if (!dest_buffer->capacity()) { | 293 if (!dest_buffer->capacity()) { |
291 dest_buffer->reserve(std::min(kMaxInMemoryBufferSize, max_dump_size_)); | 294 dest_buffer->reserve(std::min(kMaxInMemoryBufferSize, max_dump_size_)); |
292 | 295 |
293 start_time_ = base::TimeTicks::Now(); | 296 start_time_ = base::TimeTicks::Now(); |
294 | 297 |
295 // Writes the dump file header. | 298 // Writes the dump file header. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 } | 349 } |
347 | 350 |
348 WebRtcRtpDumpWriter::EndDumpContext::~EndDumpContext() { | 351 WebRtcRtpDumpWriter::EndDumpContext::~EndDumpContext() { |
349 } | 352 } |
350 | 353 |
351 void WebRtcRtpDumpWriter::FlushBuffer(bool incoming, | 354 void WebRtcRtpDumpWriter::FlushBuffer(bool incoming, |
352 bool end_stream, | 355 bool end_stream, |
353 const FlushDoneCallback& callback) { | 356 const FlushDoneCallback& callback) { |
354 DCHECK(thread_checker_.CalledOnValidThread()); | 357 DCHECK(thread_checker_.CalledOnValidThread()); |
355 | 358 |
356 scoped_ptr<std::vector<uint8> > new_buffer(new std::vector<uint8>()); | 359 scoped_ptr<std::vector<uint8_t>> new_buffer(new std::vector<uint8_t>()); |
357 | 360 |
358 if (incoming) { | 361 if (incoming) { |
359 new_buffer->reserve(incoming_buffer_.capacity()); | 362 new_buffer->reserve(incoming_buffer_.capacity()); |
360 new_buffer->swap(incoming_buffer_); | 363 new_buffer->swap(incoming_buffer_); |
361 } else { | 364 } else { |
362 new_buffer->reserve(outgoing_buffer_.capacity()); | 365 new_buffer->reserve(outgoing_buffer_.capacity()); |
363 new_buffer->swap(outgoing_buffer_); | 366 new_buffer->swap(outgoing_buffer_); |
364 } | 367 } |
365 | 368 |
366 scoped_ptr<FlushResult> result(new FlushResult(FLUSH_RESULT_FAILURE)); | 369 scoped_ptr<FlushResult> result(new FlushResult(FLUSH_RESULT_FAILURE)); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 base::Bind(&WebRtcRtpDumpWriter::OnDumpEnded, | 440 base::Bind(&WebRtcRtpDumpWriter::OnDumpEnded, |
438 weak_ptr_factory_.GetWeakPtr(), | 441 weak_ptr_factory_.GetWeakPtr(), |
439 context, | 442 context, |
440 false)); | 443 false)); |
441 return; | 444 return; |
442 } | 445 } |
443 | 446 |
444 // This object might be deleted after running the callback. | 447 // This object might be deleted after running the callback. |
445 context.callback.Run(context.incoming_succeeded, context.outgoing_succeeded); | 448 context.callback.Run(context.incoming_succeeded, context.outgoing_succeeded); |
446 } | 449 } |
OLD | NEW |