| 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 |