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

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

Issue 264793017: Implements RTP header dumping. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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_handler.h"
6
7 #include "base/file_util.h"
8 #include "base/logging.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/time/time.h"
11 #include "chrome/browser/media/webrtc_rtp_dump_writer.h"
12 #include "content/public/browser/browser_thread.h"
13
14 using content::BrowserThread;
15
16 namespace {
17
18 // |path| must be a copy of FilePath, not a reference.
19 void DeleteFileHelper(base::FilePath path) {
20 base::DeleteFile(path, false);
21 }
22
23 static const size_t kMaxOngoingRtpDumpsAllowed = 5;
24
25 // The browser process wide total number of ongoing (i.e. started and not
26 // released) RTP dumps. Incoming and outgoing in one WebRtcDumpHandler are
27 // counted as one dump.
28 // Must be accessed on the browser IO thread.
29 static size_t g_ongoing_rtp_dumps = 0;
30
31 void FireGenericDoneCallback(
32 const WebRtcRtpDumpHandler::GenericDoneCallback& callback,
33 bool success,
34 const std::string& error_message) {
35 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
36 DCHECK(!callback.is_null());
37
38 content::BrowserThread::PostTask(
39 content::BrowserThread::UI,
40 FROM_HERE,
41 base::Bind(callback, success, error_message));
42 }
43
44 } // namespace
45
46 WebRtcRtpDumpHandler::WebRtcRtpDumpHandler(const base::FilePath& dump_dir)
47 : dump_dir_(dump_dir),
48 incoming_state_(STATE_NONE),
49 outgoing_state_(STATE_NONE) {
50 }
51
52 WebRtcRtpDumpHandler::~WebRtcRtpDumpHandler() {
53 if (incoming_state_ != STATE_NONE && !incoming_dump_path_.empty()) {
54 BrowserThread::PostTask(BrowserThread::FILE,
55 FROM_HERE,
56 base::Bind(&DeleteFileHelper, incoming_dump_path_));
57 }
58
59 if (outgoing_state_ != STATE_NONE && !outgoing_dump_path_.empty()) {
60 BrowserThread::PostTask(BrowserThread::FILE,
61 FROM_HERE,
62 base::Bind(&DeleteFileHelper, outgoing_dump_path_));
63 }
64
65 if (dump_writer_)
66 g_ongoing_rtp_dumps--;
Henrik Grunell 2014/05/14 12:14:12 nit: --g_ongoing_rtp_dumps;
jiayl 2014/05/14 18:59:12 Done.
67 }
68
69 bool WebRtcRtpDumpHandler::StartDump(const PacketType& type,
70 std::string* error_message) {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
72
73 bool succeeded = false;
74
75 if (type.incoming && incoming_state_ == STATE_NONE) {
76 incoming_state_ = STATE_STARTED;
77 succeeded = true;
78 }
79 if (type.outgoing && outgoing_state_ == STATE_NONE) {
80 outgoing_state_ = STATE_STARTED;
81 succeeded = true;
82 }
83
84 if (!dump_writer_ && g_ongoing_rtp_dumps >= kMaxOngoingRtpDumpsAllowed) {
85 *error_message = "Max RTP dump limit reached.";
86 DVLOG(2) << *error_message;
87 return false;
88 }
89
90 if (!succeeded) {
91 *error_message = "RTP dump already started.";
92 return false;
93 }
94
95 DVLOG(2) << "Start RTP dumping: incoming = " << type.incoming
96 << ", outgoing = " << type.outgoing;
97
98 if (!dump_writer_) {
99 g_ongoing_rtp_dumps++;
100
101 static const char kRecvDumpFilePrefix[] = "rtpdump_recv_";
102 static const char kSendDumpFilePrefix[] = "rtpdump_send_";
103 static const char kDumpFileExtension[] = ".gz";
104 static const size_t kMaxDumpSize = 5 * 1024 * 1024; // 5MB
105
106 std::string dump_id = base::DoubleToString(base::Time::Now().ToDoubleT());
107 incoming_dump_path_ =
108 dump_dir_.AppendASCII(std::string(kRecvDumpFilePrefix) + dump_id)
109 .AddExtension(FILE_PATH_LITERAL(kDumpFileExtension));
110
111 outgoing_dump_path_ =
112 dump_dir_.AppendASCII(std::string(kSendDumpFilePrefix) + dump_id)
113 .AddExtension(FILE_PATH_LITERAL(kDumpFileExtension));
114
115 // WebRtcRtpDumpWriter does not support changing the dump path after it's
116 // created. So we assign both incoming and outgoing dump path even if only
117 // one type of dumping has been started.
118 dump_writer_.reset(new WebRtcRtpDumpWriter(
119 incoming_dump_path_,
120 outgoing_dump_path_,
121 kMaxDumpSize,
122 base::Bind(&WebRtcRtpDumpHandler::OnMaxDumpSizeReached,
123 base::Unretained(this))));
124 }
125
126 return true;
127 }
128
129 void WebRtcRtpDumpHandler::StopDump(const PacketType& type,
130 const GenericDoneCallback& callback) {
131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
132
133 PacketType valid_type;
134 if (type.incoming && incoming_state_ == STATE_STARTED) {
135 incoming_state_ = STATE_STOPPING;
136 valid_type.incoming = true;
137 }
138
139 if (type.outgoing && outgoing_state_ == STATE_STARTED) {
140 outgoing_state_ = STATE_STOPPING;
141 valid_type.outgoing = true;
142 }
143
144 if (!valid_type.incoming && !valid_type.outgoing) {
145 FireGenericDoneCallback(
146 callback, false, "RTP dump not started or already stopped.");
147 return;
148 }
149
150 DVLOG(2) << "Stopping RTP dumping: incoming = " << type.incoming
151 << ", outgoing = " << type.outgoing;
152
153 if (valid_type.incoming) {
154 dump_writer_->EndDump(
155 true,
156 base::Bind(&WebRtcRtpDumpHandler::OnDumpEnded,
157 base::Unretained(this),
158 valid_type.outgoing ? GenericDoneCallback() : callback,
159 true));
160 }
161
162 if (valid_type.outgoing) {
163 dump_writer_->EndDump(false,
164 base::Bind(&WebRtcRtpDumpHandler::OnDumpEnded,
165 base::Unretained(this),
166 callback,
167 false));
168 }
169
170 return;
171 }
172
173 WebRtcRtpDumpHandler::ReleasedDumps WebRtcRtpDumpHandler::ReleaseDumps() {
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
175
176 ReleasedDumps result;
177
178 // All types of dumps must have been stopped, or one stopped and the other not
179 // started.
180 if (incoming_state_ == STATE_STARTED || incoming_state_ == STATE_STOPPING ||
181 outgoing_state_ == STATE_STARTED || outgoing_state_ == STATE_STOPPING ||
182 (incoming_state_ == STATE_NONE && outgoing_state_ == STATE_NONE)) {
183 DVLOG(2) << "ReleaseDumps called in invalid state: incoming_state = "
184 << incoming_state_ << ", outgoing_state = " << outgoing_state_;
185 return result;
186 }
187
188 if (incoming_state_ == STATE_STOPPED) {
189 DVLOG(2) << "Incoming RTP dumps released: " << incoming_dump_path_.value();
190
191 incoming_state_ = STATE_NONE;
192 result.incoming_dump_path = incoming_dump_path_;
193 }
194
195 if (outgoing_state_ == STATE_STOPPED) {
196 DVLOG(2) << "Outgoing RTP dumps released: " << outgoing_dump_path_.value();
197
198 outgoing_state_ = STATE_NONE;
199 result.outgoing_dump_path = outgoing_dump_path_;
200 }
201 return result;
202 }
203
204 void WebRtcRtpDumpHandler::OnRtpPacket(const uint8* packet_header,
205 size_t header_length,
206 size_t packet_length,
207 bool incoming) {
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
209
210 if ((incoming && incoming_state_ != STATE_STARTED) ||
211 (!incoming && outgoing_state_ != STATE_STARTED))
212 return;
213
214 dump_writer_->WriteRtpPacket(
215 packet_header, header_length, packet_length, incoming);
216 }
217
218 void WebRtcRtpDumpHandler::OnMaxDumpSizeReached() {
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
220
221 PacketType type(true, true);
222 StopDump(type, GenericDoneCallback());
223 }
224
225 void WebRtcRtpDumpHandler::OnDumpEnded(const GenericDoneCallback& callback,
226 bool incoming,
227 bool succeeded) {
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
229
230 if (incoming) {
231 DCHECK_EQ(STATE_STOPPING, incoming_state_);
232 incoming_state_ = STATE_STOPPED;
233 } else {
234 DCHECK_EQ(STATE_STOPPING, outgoing_state_);
235 outgoing_state_ = STATE_STOPPED;
236 }
237
238 if (!succeeded) {
239 base::FilePath* dump =
240 incoming ? &incoming_dump_path_ : &outgoing_dump_path_;
241
242 BrowserThread::PostTask(
243 BrowserThread::FILE, FROM_HERE, base::Bind(&DeleteFileHelper, *dump));
244
245 DVLOG(2) << "Deleted invalid dump " << dump->value();
246 dump->clear();
247 }
248
249 if (!callback.is_null())
250 callback.Run(true, "");
251
252 // Release the writer when it's no longer needed.
253 if (incoming_state_ != STATE_STOPPING && outgoing_state_ != STATE_STOPPING &&
254 incoming_state_ != STATE_STARTED && outgoing_state_ != STATE_STARTED) {
255 dump_writer_.reset();
256 g_ongoing_rtp_dumps--;
257 }
258 }
259
260 void WebRtcRtpDumpHandler::SetDumpWriterForTesting(
261 scoped_ptr<WebRtcRtpDumpWriter> writer) {
262 DCHECK(!dump_writer_.get());
263 dump_writer_ = writer.Pass();
264 g_ongoing_rtp_dumps++;
265
266 incoming_dump_path_ = dump_dir_.AppendASCII("recv");
267 outgoing_dump_path_ = dump_dir_.AppendASCII("send");
268 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698