OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/call/rtc_event_log.h" | 11 #include "webrtc/call/rtc_event_log.h" |
12 | 12 |
13 #include <deque> | 13 #include <deque> |
| 14 #include <vector> |
14 | 15 |
15 #include "webrtc/base/checks.h" | 16 #include "webrtc/base/checks.h" |
16 #include "webrtc/base/criticalsection.h" | 17 #include "webrtc/base/criticalsection.h" |
17 #include "webrtc/base/thread_annotations.h" | 18 #include "webrtc/base/thread_annotations.h" |
18 #include "webrtc/call.h" | 19 #include "webrtc/call.h" |
19 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | 20 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
20 #include "webrtc/system_wrappers/interface/clock.h" | 21 #include "webrtc/system_wrappers/interface/clock.h" |
21 #include "webrtc/system_wrappers/interface/file_wrapper.h" | 22 #include "webrtc/system_wrappers/interface/file_wrapper.h" |
22 | 23 |
23 #ifdef ENABLE_RTC_EVENT_LOG | 24 #ifdef ENABLE_RTC_EVENT_LOG |
24 // Files generated at build-time by the protobuf compiler. | 25 // Files generated at build-time by the protobuf compiler. |
25 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD | 26 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD |
26 #include "external/webrtc/webrtc/call/rtc_event_log.pb.h" | 27 #include "external/webrtc/webrtc/call/rtc_event_log.pb.h" |
27 #else | 28 #else |
28 #include "webrtc/call/rtc_event_log.pb.h" | 29 #include "webrtc/call/rtc_event_log.pb.h" |
29 #endif | 30 #endif |
30 #endif | 31 #endif |
31 | 32 |
32 namespace webrtc { | 33 namespace webrtc { |
33 | 34 |
34 #ifndef ENABLE_RTC_EVENT_LOG | 35 #ifndef ENABLE_RTC_EVENT_LOG |
35 | 36 |
36 // No-op implementation if flag is not set. | 37 // No-op implementation if flag is not set. |
37 class RtcEventLogImpl final : public RtcEventLog { | 38 class RtcEventLogImpl final : public RtcEventLog { |
38 public: | 39 public: |
| 40 void SetBufferDuration(int64_t buffer_duration_us) override {} |
39 void StartLogging(const std::string& file_name, int duration_ms) override {} | 41 void StartLogging(const std::string& file_name, int duration_ms) override {} |
40 bool StartLogging(rtc::PlatformFile log_file) override { return false; } | 42 bool StartLogging(rtc::PlatformFile log_file) override { return false; } |
41 void StopLogging(void) override {} | 43 void StopLogging(void) override {} |
42 void LogVideoReceiveStreamConfig( | 44 void LogVideoReceiveStreamConfig( |
43 const VideoReceiveStream::Config& config) override {} | 45 const VideoReceiveStream::Config& config) override {} |
44 void LogVideoSendStreamConfig( | 46 void LogVideoSendStreamConfig( |
45 const VideoSendStream::Config& config) override {} | 47 const VideoSendStream::Config& config) override {} |
46 void LogRtpHeader(bool incoming, | 48 void LogRtpHeader(bool incoming, |
47 MediaType media_type, | 49 MediaType media_type, |
48 const uint8_t* header, | 50 const uint8_t* header, |
49 size_t packet_length) override {} | 51 size_t packet_length) override {} |
50 void LogRtcpPacket(bool incoming, | 52 void LogRtcpPacket(bool incoming, |
51 MediaType media_type, | 53 MediaType media_type, |
52 const uint8_t* packet, | 54 const uint8_t* packet, |
53 size_t length) override {} | 55 size_t length) override {} |
54 void LogAudioPlayout(uint32_t ssrc) override {} | 56 void LogAudioPlayout(uint32_t ssrc) override {} |
55 }; | 57 }; |
56 | 58 |
57 #else // ENABLE_RTC_EVENT_LOG is defined | 59 #else // ENABLE_RTC_EVENT_LOG is defined |
58 | 60 |
59 class RtcEventLogImpl final : public RtcEventLog { | 61 class RtcEventLogImpl final : public RtcEventLog { |
60 public: | 62 public: |
| 63 RtcEventLogImpl(); |
| 64 |
| 65 void SetBufferDuration(int64_t buffer_duration_us) override; |
61 void StartLogging(const std::string& file_name, int duration_ms) override; | 66 void StartLogging(const std::string& file_name, int duration_ms) override; |
62 bool StartLogging(rtc::PlatformFile log_file) override; | 67 bool StartLogging(rtc::PlatformFile log_file) override; |
63 void StopLogging() override; | 68 void StopLogging() override; |
64 void LogVideoReceiveStreamConfig( | 69 void LogVideoReceiveStreamConfig( |
65 const VideoReceiveStream::Config& config) override; | 70 const VideoReceiveStream::Config& config) override; |
66 void LogVideoSendStreamConfig(const VideoSendStream::Config& config) override; | 71 void LogVideoSendStreamConfig(const VideoSendStream::Config& config) override; |
67 void LogRtpHeader(bool incoming, | 72 void LogRtpHeader(bool incoming, |
68 MediaType media_type, | 73 MediaType media_type, |
69 const uint8_t* header, | 74 const uint8_t* header, |
70 size_t packet_length) override; | 75 size_t packet_length) override; |
(...skipping 13 matching lines...) Expand all Loading... |
84 // list of recent log events otherwise. | 89 // list of recent log events otherwise. |
85 void HandleEvent(rtclog::Event* event) EXCLUSIVE_LOCKS_REQUIRED(crit_); | 90 void HandleEvent(rtclog::Event* event) EXCLUSIVE_LOCKS_REQUIRED(crit_); |
86 // Writes the event to the file. Note that this will destroy the state of the | 91 // Writes the event to the file. Note that this will destroy the state of the |
87 // input argument. | 92 // input argument. |
88 void StoreToFile(rtclog::Event* event) EXCLUSIVE_LOCKS_REQUIRED(crit_); | 93 void StoreToFile(rtclog::Event* event) EXCLUSIVE_LOCKS_REQUIRED(crit_); |
89 // Adds the event to the list of recent events, and removes any events that | 94 // Adds the event to the list of recent events, and removes any events that |
90 // are too old and no longer fall in the time window. | 95 // are too old and no longer fall in the time window. |
91 void AddRecentEvent(const rtclog::Event& event) | 96 void AddRecentEvent(const rtclog::Event& event) |
92 EXCLUSIVE_LOCKS_REQUIRED(crit_); | 97 EXCLUSIVE_LOCKS_REQUIRED(crit_); |
93 | 98 |
94 // Amount of time in microseconds to record log events, before starting the | |
95 // actual log. | |
96 const int recent_log_duration_us = 10000000; | |
97 | |
98 rtc::CriticalSection crit_; | 99 rtc::CriticalSection crit_; |
99 rtc::scoped_ptr<FileWrapper> file_ GUARDED_BY(crit_) = | 100 rtc::scoped_ptr<FileWrapper> file_ GUARDED_BY(crit_) = |
100 rtc::scoped_ptr<FileWrapper>(FileWrapper::Create()); | 101 rtc::scoped_ptr<FileWrapper>(FileWrapper::Create()); |
101 rtc::PlatformFile platform_file_ GUARDED_BY(crit_) = | 102 rtc::PlatformFile platform_file_ GUARDED_BY(crit_) = |
102 rtc::kInvalidPlatformFileValue; | 103 rtc::kInvalidPlatformFileValue; |
103 rtclog::EventStream stream_ GUARDED_BY(crit_); | 104 rtclog::EventStream stream_ GUARDED_BY(crit_); |
104 std::deque<rtclog::Event> recent_log_events_ GUARDED_BY(crit_); | 105 std::deque<rtclog::Event> recent_log_events_ GUARDED_BY(crit_); |
105 bool currently_logging_ GUARDED_BY(crit_) = false; | 106 std::vector<rtclog::Event> config_events_ GUARDED_BY(crit_); |
106 int64_t start_time_us_ GUARDED_BY(crit_) = 0; | 107 |
107 int64_t duration_us_ GUARDED_BY(crit_) = 0; | 108 // Microseconds to record log events, before starting the actual log. |
108 const Clock* const clock_ = Clock::GetRealTimeClock(); | 109 int64_t buffer_duration_us_ GUARDED_BY(crit_); |
| 110 bool currently_logging_ GUARDED_BY(crit_); |
| 111 int64_t start_time_us_ GUARDED_BY(crit_); |
| 112 int64_t duration_us_ GUARDED_BY(crit_); |
| 113 const Clock* const clock_; |
109 }; | 114 }; |
110 | 115 |
111 namespace { | 116 namespace { |
112 // The functions in this namespace convert enums from the runtime format | 117 // The functions in this namespace convert enums from the runtime format |
113 // that the rest of the WebRtc project can use, to the corresponding | 118 // that the rest of the WebRtc project can use, to the corresponding |
114 // serialized enum which is defined by the protobuf. | 119 // serialized enum which is defined by the protobuf. |
115 | 120 |
116 // Do not add default return values to the conversion functions in this | 121 // Do not add default return values to the conversion functions in this |
117 // unnamed namespace. The intention is to make the compiler warn if anyone | 122 // unnamed namespace. The intention is to make the compiler warn if anyone |
118 // adds unhandled new events/modes/etc. | 123 // adds unhandled new events/modes/etc. |
(...skipping 22 matching lines...) Expand all Loading... |
141 return rtclog::MediaType::VIDEO; | 146 return rtclog::MediaType::VIDEO; |
142 case MediaType::DATA: | 147 case MediaType::DATA: |
143 return rtclog::MediaType::DATA; | 148 return rtclog::MediaType::DATA; |
144 } | 149 } |
145 RTC_NOTREACHED(); | 150 RTC_NOTREACHED(); |
146 return rtclog::ANY; | 151 return rtclog::ANY; |
147 } | 152 } |
148 | 153 |
149 } // namespace | 154 } // namespace |
150 | 155 |
| 156 namespace { |
| 157 bool IsConfigEvent(const rtclog::Event& event) { |
| 158 rtclog::Event_EventType event_type = event.type(); |
| 159 return event_type == rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT || |
| 160 event_type == rtclog::Event::VIDEO_SENDER_CONFIG_EVENT || |
| 161 event_type == rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT || |
| 162 event_type == rtclog::Event::AUDIO_SENDER_CONFIG_EVENT; |
| 163 } |
| 164 } // namespace |
| 165 |
151 // RtcEventLogImpl member functions. | 166 // RtcEventLogImpl member functions. |
| 167 RtcEventLogImpl::RtcEventLogImpl() |
| 168 : file_(FileWrapper::Create()), |
| 169 stream_(), |
| 170 buffer_duration_us_(10000000), |
| 171 currently_logging_(false), |
| 172 start_time_us_(0), |
| 173 duration_us_(0), |
| 174 clock_(Clock::GetRealTimeClock()) { |
| 175 } |
| 176 |
| 177 void RtcEventLogImpl::SetBufferDuration(int64_t buffer_duration_us) { |
| 178 rtc::CritScope lock(&crit_); |
| 179 buffer_duration_us_ = buffer_duration_us; |
| 180 } |
152 | 181 |
153 void RtcEventLogImpl::StartLogging(const std::string& file_name, | 182 void RtcEventLogImpl::StartLogging(const std::string& file_name, |
154 int duration_ms) { | 183 int duration_ms) { |
155 rtc::CritScope lock(&crit_); | 184 rtc::CritScope lock(&crit_); |
156 if (currently_logging_) { | 185 if (currently_logging_) { |
157 StopLoggingLocked(); | 186 StopLoggingLocked(); |
158 } | 187 } |
159 if (file_->OpenFile(file_name.c_str(), false) != 0) { | 188 if (file_->OpenFile(file_name.c_str(), false) != 0) { |
160 return; | 189 return; |
161 } | 190 } |
(...skipping 23 matching lines...) Expand all Loading... |
185 platform_file_ = log_file; | 214 platform_file_ = log_file; |
186 // Set the start time and duration to keep logging for 10 minutes. | 215 // Set the start time and duration to keep logging for 10 minutes. |
187 start_time_us_ = clock_->TimeInMicroseconds(); | 216 start_time_us_ = clock_->TimeInMicroseconds(); |
188 duration_us_ = 10 * 60 * 1000000; | 217 duration_us_ = 10 * 60 * 1000000; |
189 StartLoggingLocked(); | 218 StartLoggingLocked(); |
190 return true; | 219 return true; |
191 } | 220 } |
192 | 221 |
193 void RtcEventLogImpl::StartLoggingLocked() { | 222 void RtcEventLogImpl::StartLoggingLocked() { |
194 currently_logging_ = true; | 223 currently_logging_ = true; |
195 // Write all the recent events to the log file, ignoring any old events. | 224 |
| 225 // Write all old configuration events to the log file. |
| 226 for (auto& event : config_events_) { |
| 227 StoreToFile(&event); |
| 228 } |
| 229 // Write all recent configuration events to the log file, and |
| 230 // write all other recent events to the log file, ignoring any old events. |
196 for (auto& event : recent_log_events_) { | 231 for (auto& event : recent_log_events_) { |
197 if (event.timestamp_us() >= start_time_us_ - recent_log_duration_us) { | 232 if (IsConfigEvent(event)) { |
| 233 StoreToFile(&event); |
| 234 config_events_.push_back(event); |
| 235 } else if (event.timestamp_us() >= start_time_us_ - buffer_duration_us_) { |
198 StoreToFile(&event); | 236 StoreToFile(&event); |
199 } | 237 } |
200 } | 238 } |
201 recent_log_events_.clear(); | 239 recent_log_events_.clear(); |
202 // Write a LOG_START event to the file. | 240 // Write a LOG_START event to the file. |
203 rtclog::Event start_event; | 241 rtclog::Event start_event; |
204 start_event.set_timestamp_us(start_time_us_); | 242 start_event.set_timestamp_us(start_time_us_); |
205 start_event.set_type(rtclog::Event::LOG_START); | 243 start_event.set_type(rtclog::Event::LOG_START); |
206 StoreToFile(&start_event); | 244 StoreToFile(&start_event); |
207 } | 245 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 receiver_config->add_header_extensions(); | 281 receiver_config->add_header_extensions(); |
244 extension->set_name(e.name); | 282 extension->set_name(e.name); |
245 extension->set_id(e.id); | 283 extension->set_id(e.id); |
246 } | 284 } |
247 | 285 |
248 for (const auto& d : config.decoders) { | 286 for (const auto& d : config.decoders) { |
249 rtclog::DecoderConfig* decoder = receiver_config->add_decoders(); | 287 rtclog::DecoderConfig* decoder = receiver_config->add_decoders(); |
250 decoder->set_name(d.payload_name); | 288 decoder->set_name(d.payload_name); |
251 decoder->set_payload_type(d.payload_type); | 289 decoder->set_payload_type(d.payload_type); |
252 } | 290 } |
253 // TODO(terelius): We should use a separate event queue for config events. | |
254 // The current approach of storing the configuration together with the | |
255 // RTP events causes the configuration information to be removed 10s | |
256 // after the ReceiveStream is created. | |
257 HandleEvent(&event); | 291 HandleEvent(&event); |
258 } | 292 } |
259 | 293 |
260 void RtcEventLogImpl::LogVideoSendStreamConfig( | 294 void RtcEventLogImpl::LogVideoSendStreamConfig( |
261 const VideoSendStream::Config& config) { | 295 const VideoSendStream::Config& config) { |
262 rtc::CritScope lock(&crit_); | 296 rtc::CritScope lock(&crit_); |
263 | 297 |
264 rtclog::Event event; | 298 rtclog::Event event; |
265 const int64_t timestamp = clock_->TimeInMicroseconds(); | 299 const int64_t timestamp = clock_->TimeInMicroseconds(); |
266 event.set_timestamp_us(timestamp); | 300 event.set_timestamp_us(timestamp); |
(...skipping 15 matching lines...) Expand all Loading... |
282 for (const auto& rtx_ssrc : config.rtp.rtx.ssrcs) { | 316 for (const auto& rtx_ssrc : config.rtp.rtx.ssrcs) { |
283 sender_config->add_rtx_ssrcs(rtx_ssrc); | 317 sender_config->add_rtx_ssrcs(rtx_ssrc); |
284 } | 318 } |
285 sender_config->set_rtx_payload_type(config.rtp.rtx.payload_type); | 319 sender_config->set_rtx_payload_type(config.rtp.rtx.payload_type); |
286 | 320 |
287 sender_config->set_c_name(config.rtp.c_name); | 321 sender_config->set_c_name(config.rtp.c_name); |
288 | 322 |
289 rtclog::EncoderConfig* encoder = sender_config->mutable_encoder(); | 323 rtclog::EncoderConfig* encoder = sender_config->mutable_encoder(); |
290 encoder->set_name(config.encoder_settings.payload_name); | 324 encoder->set_name(config.encoder_settings.payload_name); |
291 encoder->set_payload_type(config.encoder_settings.payload_type); | 325 encoder->set_payload_type(config.encoder_settings.payload_type); |
292 | |
293 // TODO(terelius): We should use a separate event queue for config events. | |
294 // The current approach of storing the configuration together with the | |
295 // RTP events causes the configuration information to be removed 10s | |
296 // after the ReceiveStream is created. | |
297 HandleEvent(&event); | 326 HandleEvent(&event); |
298 } | 327 } |
299 | 328 |
300 void RtcEventLogImpl::LogRtpHeader(bool incoming, | 329 void RtcEventLogImpl::LogRtpHeader(bool incoming, |
301 MediaType media_type, | 330 MediaType media_type, |
302 const uint8_t* header, | 331 const uint8_t* header, |
303 size_t packet_length) { | 332 size_t packet_length) { |
304 // Read header length (in bytes) from packet data. | 333 // Read header length (in bytes) from packet data. |
305 if (packet_length < 12u) { | 334 if (packet_length < 12u) { |
306 return; // Don't read outside the packet. | 335 return; // Don't read outside the packet. |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 // TODO(terelius): Doesn't this create a new EventStream per event? | 426 // TODO(terelius): Doesn't this create a new EventStream per event? |
398 // Is this guaranteed to work e.g. in future versions of protobuf? | 427 // Is this guaranteed to work e.g. in future versions of protobuf? |
399 std::string dump_buffer; | 428 std::string dump_buffer; |
400 stream_.SerializeToString(&dump_buffer); | 429 stream_.SerializeToString(&dump_buffer); |
401 file_->Write(dump_buffer.data(), dump_buffer.size()); | 430 file_->Write(dump_buffer.data(), dump_buffer.size()); |
402 } | 431 } |
403 | 432 |
404 void RtcEventLogImpl::AddRecentEvent(const rtclog::Event& event) { | 433 void RtcEventLogImpl::AddRecentEvent(const rtclog::Event& event) { |
405 recent_log_events_.push_back(event); | 434 recent_log_events_.push_back(event); |
406 while (recent_log_events_.front().timestamp_us() < | 435 while (recent_log_events_.front().timestamp_us() < |
407 event.timestamp_us() - recent_log_duration_us) { | 436 event.timestamp_us() - buffer_duration_us_) { |
| 437 if (IsConfigEvent(recent_log_events_.front())) { |
| 438 config_events_.push_back(recent_log_events_.front()); |
| 439 } |
408 recent_log_events_.pop_front(); | 440 recent_log_events_.pop_front(); |
409 } | 441 } |
410 } | 442 } |
411 | 443 |
412 bool RtcEventLog::ParseRtcEventLog(const std::string& file_name, | 444 bool RtcEventLog::ParseRtcEventLog(const std::string& file_name, |
413 rtclog::EventStream* result) { | 445 rtclog::EventStream* result) { |
414 char tmp_buffer[1024]; | 446 char tmp_buffer[1024]; |
415 int bytes_read = 0; | 447 int bytes_read = 0; |
416 rtc::scoped_ptr<FileWrapper> dump_file(FileWrapper::Create()); | 448 rtc::scoped_ptr<FileWrapper> dump_file(FileWrapper::Create()); |
417 if (dump_file->OpenFile(file_name.c_str(), true) != 0) { | 449 if (dump_file->OpenFile(file_name.c_str(), true) != 0) { |
418 return false; | 450 return false; |
419 } | 451 } |
420 std::string dump_buffer; | 452 std::string dump_buffer; |
421 while ((bytes_read = dump_file->Read(tmp_buffer, sizeof(tmp_buffer))) > 0) { | 453 while ((bytes_read = dump_file->Read(tmp_buffer, sizeof(tmp_buffer))) > 0) { |
422 dump_buffer.append(tmp_buffer, bytes_read); | 454 dump_buffer.append(tmp_buffer, bytes_read); |
423 } | 455 } |
424 dump_file->CloseFile(); | 456 dump_file->CloseFile(); |
425 return result->ParseFromString(dump_buffer); | 457 return result->ParseFromString(dump_buffer); |
426 } | 458 } |
427 | 459 |
428 #endif // ENABLE_RTC_EVENT_LOG | 460 #endif // ENABLE_RTC_EVENT_LOG |
429 | 461 |
430 // RtcEventLog member functions. | 462 // RtcEventLog member functions. |
431 rtc::scoped_ptr<RtcEventLog> RtcEventLog::Create() { | 463 rtc::scoped_ptr<RtcEventLog> RtcEventLog::Create() { |
432 return rtc::scoped_ptr<RtcEventLog>(new RtcEventLogImpl()); | 464 return rtc::scoped_ptr<RtcEventLog>(new RtcEventLogImpl()); |
433 } | 465 } |
| 466 |
434 } // namespace webrtc | 467 } // namespace webrtc |
OLD | NEW |