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/modules/audio_coding/main/acm2/acm_dump.h" | 11 #include "webrtc/modules/audio_coding/main/acm2/acm_dump.h" |
12 | 12 |
13 #include <sstream> | 13 #include <deque> |
14 | 14 |
15 #include "webrtc/base/checks.h" | 15 #include "webrtc/base/checks.h" |
16 #include "webrtc/base/thread_annotations.h" | 16 #include "webrtc/base/thread_annotations.h" |
17 #include "webrtc/system_wrappers/interface/clock.h" | 17 #include "webrtc/system_wrappers/interface/clock.h" |
18 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" | 18 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" |
19 #include "webrtc/system_wrappers/interface/file_wrapper.h" | 19 #include "webrtc/system_wrappers/interface/file_wrapper.h" |
20 | 20 |
21 // Files generated at build-time by the protobuf compiler. | 21 // Files generated at build-time by the protobuf compiler. |
22 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD | 22 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD |
23 #include "external/webrtc/webrtc/modules/audio_coding/dump.pb.h" | 23 #include "external/webrtc/webrtc/modules/audio_coding/dump.pb.h" |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
60 void Clear() EXCLUSIVE_LOCKS_REQUIRED(crit_); | 60 void Clear() EXCLUSIVE_LOCKS_REQUIRED(crit_); |
61 // Returns true if the logging is currently active. | 61 // Returns true if the logging is currently active. |
62 bool CurrentlyLogging() const EXCLUSIVE_LOCKS_REQUIRED(crit_) { | 62 bool CurrentlyLogging() const EXCLUSIVE_LOCKS_REQUIRED(crit_) { |
63 return active_ && | 63 return active_ && |
64 (clock_->TimeInMicroseconds() <= start_time_us_ + duration_us_); | 64 (clock_->TimeInMicroseconds() <= start_time_us_ + duration_us_); |
65 } | 65 } |
66 // This function is identical to LogDebugEvent, but requires holding the lock. | 66 // This function is identical to LogDebugEvent, but requires holding the lock. |
67 void LogDebugEventLocked(DebugEvent event_type, | 67 void LogDebugEventLocked(DebugEvent event_type, |
68 const std::string& event_message) | 68 const std::string& event_message) |
69 EXCLUSIVE_LOCKS_REQUIRED(crit_); | 69 EXCLUSIVE_LOCKS_REQUIRED(crit_); |
70 // Writes the event to the file. Note that this will destroy the state of the | |
71 // input argument. | |
72 void StoreToFile(ACMDumpEvent* event) EXCLUSIVE_LOCKS_REQUIRED(crit_); | |
73 // Adds the event to the list of recent events, and removes any events that | |
74 // are too old and no longer fall in the time window. | |
75 void AddRecentEvent(const ACMDumpEvent& event) | |
76 EXCLUSIVE_LOCKS_REQUIRED(crit_); | |
77 | |
78 // Amount of time in microseconds to record log events, before starting the | |
79 // actual log. | |
80 const int recent_log_duration_us = 10000000; | |
70 | 81 |
71 rtc::scoped_ptr<webrtc::CriticalSectionWrapper> crit_; | 82 rtc::scoped_ptr<webrtc::CriticalSectionWrapper> crit_; |
72 rtc::scoped_ptr<webrtc::FileWrapper> file_ GUARDED_BY(crit_); | 83 rtc::scoped_ptr<webrtc::FileWrapper> file_ GUARDED_BY(crit_); |
73 rtc::scoped_ptr<ACMDumpEventStream> stream_ GUARDED_BY(crit_); | 84 rtc::scoped_ptr<ACMDumpEventStream> stream_ GUARDED_BY(crit_); |
85 std::deque<ACMDumpEvent> recent_log_events_ GUARDED_BY(crit_); | |
74 bool active_ GUARDED_BY(crit_); | 86 bool active_ GUARDED_BY(crit_); |
75 int64_t start_time_us_ GUARDED_BY(crit_); | 87 int64_t start_time_us_ GUARDED_BY(crit_); |
76 int64_t duration_us_ GUARDED_BY(crit_); | 88 int64_t duration_us_ GUARDED_BY(crit_); |
77 const webrtc::Clock* clock_ GUARDED_BY(crit_); | 89 const webrtc::Clock* clock_ GUARDED_BY(crit_); |
stefan-webrtc
2015/06/25 14:55:44
No need to guard this since it's const, right?
kwiberg-webrtc
2015/06/25 14:58:59
Sounds reasonable. But then the actual pointer pro
ivoc
2015/06/25 15:14:48
Okay, that makes sense, I made the pointer const a
| |
78 }; | 90 }; |
79 | 91 |
80 namespace { | 92 namespace { |
81 | 93 |
82 // Convert from AcmDump's debug event enum (runtime format) to the corresponding | 94 // Convert from AcmDump's debug event enum (runtime format) to the corresponding |
83 // protobuf enum (serialized format). | 95 // protobuf enum (serialized format). |
84 ACMDumpDebugEvent_EventType convertDebugEvent(AcmDump::DebugEvent event_type) { | 96 ACMDumpDebugEvent_EventType convertDebugEvent(AcmDump::DebugEvent event_type) { |
85 switch (event_type) { | 97 switch (event_type) { |
86 case AcmDump::DebugEvent::kLogStart: | 98 case AcmDump::DebugEvent::kLogStart: |
87 return ACMDumpDebugEvent::LOG_START; | 99 return ACMDumpDebugEvent::LOG_START; |
(...skipping 17 matching lines...) Expand all Loading... | |
105 duration_us_(0), | 117 duration_us_(0), |
106 clock_(webrtc::Clock::GetRealTimeClock()) { | 118 clock_(webrtc::Clock::GetRealTimeClock()) { |
107 } | 119 } |
108 | 120 |
109 void AcmDumpImpl::StartLogging(const std::string& file_name, int duration_ms) { | 121 void AcmDumpImpl::StartLogging(const std::string& file_name, int duration_ms) { |
110 CriticalSectionScoped lock(crit_.get()); | 122 CriticalSectionScoped lock(crit_.get()); |
111 Clear(); | 123 Clear(); |
112 if (file_->OpenFile(file_name.c_str(), false) != 0) { | 124 if (file_->OpenFile(file_name.c_str(), false) != 0) { |
113 return; | 125 return; |
114 } | 126 } |
115 // Add a single object to the stream that is reused at every log event. | 127 // Add LOG_START event to the recent event list. This call will also remove |
116 stream_->add_stream(); | 128 // any events that are too old from the recent event list. |
129 LogDebugEventLocked(DebugEvent::kLogStart, ""); | |
117 active_ = true; | 130 active_ = true; |
118 start_time_us_ = clock_->TimeInMicroseconds(); | 131 start_time_us_ = clock_->TimeInMicroseconds(); |
119 duration_us_ = static_cast<int64_t>(duration_ms) * 1000; | 132 duration_us_ = static_cast<int64_t>(duration_ms) * 1000; |
120 // Log the start event. | 133 // Write all the recent events to the log file. |
121 std::stringstream log_msg; | 134 for (auto&& event : recent_log_events_) { |
122 log_msg << "Initial timestamp: " << start_time_us_; | 135 StoreToFile(&event); |
123 LogDebugEventLocked(DebugEvent::kLogStart, log_msg.str()); | 136 } |
137 recent_log_events_.clear(); | |
124 } | 138 } |
125 | 139 |
126 void AcmDumpImpl::LogRtpPacket(bool incoming, | 140 void AcmDumpImpl::LogRtpPacket(bool incoming, |
127 const uint8_t* packet, | 141 const uint8_t* packet, |
128 size_t length) { | 142 size_t length) { |
129 CriticalSectionScoped lock(crit_.get()); | 143 CriticalSectionScoped lock(crit_.get()); |
130 if (!CurrentlyLogging()) { | 144 ACMDumpEvent rtp_event; |
145 rtp_event.clear_debug_event(); | |
stefan-webrtc
2015/06/25 14:55:44
Isn't the event clear when it is created?
ivoc
2015/06/25 15:14:48
You're right, this is an artifact from when we reu
| |
146 const int64_t timestamp = clock_->TimeInMicroseconds(); | |
147 rtp_event.set_timestamp_us(timestamp); | |
148 rtp_event.set_type(webrtc::ACMDumpEvent::RTP_EVENT); | |
stefan-webrtc
2015/06/25 14:55:44
Would it make sense to have these in the construct
ivoc
2015/06/25 15:14:48
That would make sense, but this class is automatic
stefan-webrtc
2015/06/25 15:18:22
Ah, that makes sense.
| |
149 rtp_event.mutable_packet()->set_direction( | |
150 incoming ? ACMDumpRTPPacket::INCOMING : ACMDumpRTPPacket::OUTGOING); | |
151 rtp_event.mutable_packet()->set_rtp_data(packet, length); | |
152 if (CurrentlyLogging()) { | |
153 StoreToFile(&rtp_event); | |
154 } else { | |
131 StopIfNecessary(); | 155 StopIfNecessary(); |
132 return; | 156 AddRecentEvent(rtp_event); |
133 } | 157 } |
134 // Reuse the same object at every log event. | |
135 auto rtp_event = stream_->mutable_stream(0); | |
136 rtp_event->clear_debug_event(); | |
137 const int64_t timestamp = clock_->TimeInMicroseconds() - start_time_us_; | |
138 rtp_event->set_timestamp_us(timestamp); | |
139 rtp_event->set_type(webrtc::ACMDumpEvent::RTP_EVENT); | |
140 rtp_event->mutable_packet()->set_direction( | |
141 incoming ? ACMDumpRTPPacket::INCOMING : ACMDumpRTPPacket::OUTGOING); | |
142 rtp_event->mutable_packet()->set_rtp_data(packet, length); | |
143 std::string dump_buffer; | |
144 stream_->SerializeToString(&dump_buffer); | |
145 file_->Write(dump_buffer.data(), dump_buffer.size()); | |
146 file_->Flush(); | |
147 } | 158 } |
148 | 159 |
149 void AcmDumpImpl::LogDebugEvent(DebugEvent event_type, | 160 void AcmDumpImpl::LogDebugEvent(DebugEvent event_type, |
150 const std::string& event_message) { | 161 const std::string& event_message) { |
151 CriticalSectionScoped lock(crit_.get()); | 162 CriticalSectionScoped lock(crit_.get()); |
152 LogDebugEventLocked(event_type, event_message); | 163 LogDebugEventLocked(event_type, event_message); |
153 } | 164 } |
154 | 165 |
155 void AcmDumpImpl::LogDebugEvent(DebugEvent event_type) { | 166 void AcmDumpImpl::LogDebugEvent(DebugEvent event_type) { |
156 CriticalSectionScoped lock(crit_.get()); | 167 CriticalSectionScoped lock(crit_.get()); |
(...skipping 11 matching lines...) Expand all Loading... | |
168 void AcmDumpImpl::Clear() { | 179 void AcmDumpImpl::Clear() { |
169 if (active_ || file_->Open()) { | 180 if (active_ || file_->Open()) { |
170 file_->CloseFile(); | 181 file_->CloseFile(); |
171 } | 182 } |
172 active_ = false; | 183 active_ = false; |
173 stream_->Clear(); | 184 stream_->Clear(); |
174 } | 185 } |
175 | 186 |
176 void AcmDumpImpl::LogDebugEventLocked(DebugEvent event_type, | 187 void AcmDumpImpl::LogDebugEventLocked(DebugEvent event_type, |
177 const std::string& event_message) { | 188 const std::string& event_message) { |
178 if (!CurrentlyLogging()) { | 189 ACMDumpEvent event; |
179 StopIfNecessary(); | 190 int64_t timestamp = clock_->TimeInMicroseconds(); |
180 return; | 191 event.set_timestamp_us(timestamp); |
181 } | 192 event.set_type(webrtc::ACMDumpEvent::DEBUG_EVENT); |
182 | 193 event.clear_packet(); |
183 // Reuse the same object at every log event. | 194 auto debug_event = event.mutable_debug_event(); |
184 auto event = stream_->mutable_stream(0); | |
185 int64_t timestamp = clock_->TimeInMicroseconds() - start_time_us_; | |
186 event->set_timestamp_us(timestamp); | |
187 event->set_type(webrtc::ACMDumpEvent::DEBUG_EVENT); | |
188 event->clear_packet(); | |
189 auto debug_event = event->mutable_debug_event(); | |
190 debug_event->set_type(convertDebugEvent(event_type)); | 195 debug_event->set_type(convertDebugEvent(event_type)); |
191 debug_event->set_message(event_message); | 196 debug_event->set_message(event_message); |
197 if (CurrentlyLogging()) { | |
198 StoreToFile(&event); | |
199 } else { | |
200 StopIfNecessary(); | |
201 AddRecentEvent(event); | |
202 } | |
203 } | |
204 | |
205 void AcmDumpImpl::StoreToFile(ACMDumpEvent* event) { | |
206 // Reuse the same object at every log event. | |
207 if (stream_->stream_size() < 1) { | |
208 stream_->add_stream(); | |
209 } | |
210 stream_->mutable_stream(0)->Swap(event); | |
terelius
2015/06/25 16:21:03
The stream must not contain more than one event, o
ivoc
2015/06/26 08:08:56
Done.
| |
211 | |
192 std::string dump_buffer; | 212 std::string dump_buffer; |
193 stream_->SerializeToString(&dump_buffer); | 213 stream_->SerializeToString(&dump_buffer); |
194 file_->Write(dump_buffer.data(), dump_buffer.size()); | 214 file_->Write(dump_buffer.data(), dump_buffer.size()); |
195 } | 215 } |
196 | 216 |
217 void AcmDumpImpl::AddRecentEvent(const ACMDumpEvent& event) { | |
218 recent_log_events_.push_back(event); | |
219 while (recent_log_events_.front().timestamp_us() < | |
220 event.timestamp_us() - recent_log_duration_us) { | |
221 recent_log_events_.pop_front(); | |
222 } | |
223 } | |
224 | |
197 #endif // RTC_AUDIOCODING_DEBUG_DUMP | 225 #endif // RTC_AUDIOCODING_DEBUG_DUMP |
198 | 226 |
199 // AcmDump member functions. | 227 // AcmDump member functions. |
200 rtc::scoped_ptr<AcmDump> AcmDump::Create() { | 228 rtc::scoped_ptr<AcmDump> AcmDump::Create() { |
201 return rtc::scoped_ptr<AcmDump>(new AcmDumpImpl()); | 229 return rtc::scoped_ptr<AcmDump>(new AcmDumpImpl()); |
202 } | 230 } |
203 | 231 |
204 bool AcmDump::ParseAcmDump(const std::string& file_name, | 232 bool AcmDump::ParseAcmDump(const std::string& file_name, |
205 ACMDumpEventStream* result) { | 233 ACMDumpEventStream* result) { |
206 char tmp_buffer[1024]; | 234 char tmp_buffer[1024]; |
207 int bytes_read = 0; | 235 int bytes_read = 0; |
208 rtc::scoped_ptr<FileWrapper> dump_file(FileWrapper::Create()); | 236 rtc::scoped_ptr<FileWrapper> dump_file(FileWrapper::Create()); |
209 if (dump_file->OpenFile(file_name.c_str(), true) != 0) { | 237 if (dump_file->OpenFile(file_name.c_str(), true) != 0) { |
210 return false; | 238 return false; |
211 } | 239 } |
212 std::string dump_buffer; | 240 std::string dump_buffer; |
213 while ((bytes_read = dump_file->Read(tmp_buffer, sizeof(tmp_buffer))) > 0) { | 241 while ((bytes_read = dump_file->Read(tmp_buffer, sizeof(tmp_buffer))) > 0) { |
214 dump_buffer.append(tmp_buffer, bytes_read); | 242 dump_buffer.append(tmp_buffer, bytes_read); |
215 } | 243 } |
216 dump_file->CloseFile(); | 244 dump_file->CloseFile(); |
217 return result->ParseFromString(dump_buffer); | 245 return result->ParseFromString(dump_buffer); |
218 } | 246 } |
219 | 247 |
220 } // namespace webrtc | 248 } // namespace webrtc |
OLD | NEW |