OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | |
3 * | |
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 | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/modules/audio_coding/main/acm2/acm_dump.h" | |
12 | |
13 #include <sstream> | |
14 | |
15 #include "webrtc/base/checks.h" | |
16 #include "webrtc/base/thread_annotations.h" | |
17 #include "webrtc/system_wrappers/interface/clock.h" | |
18 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" | |
19 #include "webrtc/system_wrappers/interface/file_wrapper.h" | |
20 | |
21 // Files generated at build-time by the protobuf compiler. | |
22 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD | |
23 #include "external/webrtc/webrtc/modules/audio_coding/dump.pb.h" | |
24 #else | |
25 #include "webrtc/audio_coding/dump.pb.h" | |
26 #endif | |
27 | |
28 namespace webrtc { | |
29 | |
30 // Noop implementation if flag is not set | |
31 #ifndef RTC_AUDIOCODING_DEBUG_DUMP | |
32 class AcmDumpImpl final : public AcmDump { | |
33 public: | |
34 void StartLogging(const std::string& file_name, int duration_ms) override{}; | |
35 void LogRtpPacket(bool incoming, | |
36 const uint8_t* packet, | |
37 size_t length) override{}; | |
38 void LogDebugEvent(DebugEvent event_type, | |
39 const std::string& event_message) override{}; | |
40 void LogDebugEvent(DebugEvent event_type) override{}; | |
41 }; | |
42 #else | |
43 | |
44 class AcmDumpImpl final : public AcmDump { | |
45 public: | |
46 AcmDumpImpl(); | |
47 | |
48 void StartLogging(const std::string& file_name, int duration_ms) override; | |
49 void LogRtpPacket(bool incoming, | |
50 const uint8_t* packet, | |
51 size_t length) override; | |
52 void LogDebugEvent(DebugEvent event_type, | |
53 const std::string& event_message) override; | |
54 void LogDebugEvent(DebugEvent event_type) override; | |
55 | |
56 private: | |
57 // Checks if the logging time has expired, and if so stops the logging. | |
58 void StopIfNecessary() EXCLUSIVE_LOCKS_REQUIRED(crit_); | |
59 // Stops logging and clears the stored data and buffers. | |
60 void Clear() EXCLUSIVE_LOCKS_REQUIRED(crit_); | |
61 // Returns true if the logging is currently active. | |
62 bool CurrentlyLogging() const EXCLUSIVE_LOCKS_REQUIRED(crit_) { | |
63 return active_ && | |
64 (clock_->TimeInMicroseconds() <= start_time_us_ + duration_us_); | |
65 } | |
66 // This function is identical to LogDebugEvent, but requires holding the lock. | |
67 void LogDebugEventLocked(DebugEvent event_type, | |
68 const std::string& event_message) | |
69 EXCLUSIVE_LOCKS_REQUIRED(crit_); | |
70 | |
71 rtc::scoped_ptr<webrtc::CriticalSectionWrapper> crit_; | |
72 rtc::scoped_ptr<webrtc::FileWrapper> file_ GUARDED_BY(crit_); | |
73 rtc::scoped_ptr<ACMDumpEventStream> stream_ GUARDED_BY(crit_); | |
74 bool active_ GUARDED_BY(crit_); | |
75 int64_t start_time_us_ GUARDED_BY(crit_); | |
76 int64_t duration_us_ GUARDED_BY(crit_); | |
77 const webrtc::Clock* clock_ GUARDED_BY(crit_); | |
78 }; | |
79 | |
80 namespace { | |
81 | |
82 // Convert from AcmDump's debug event enum (runtime format) to the corresponding | |
83 // protobuf enum (serialized format). | |
84 ACMDumpDebugEvent_EventType convertDebugEvent(AcmDump::DebugEvent event_type) { | |
85 switch (event_type) { | |
86 case AcmDump::DebugEvent::kLogStart: | |
87 return ACMDumpDebugEvent::LOG_START; | |
88 case AcmDump::DebugEvent::kLogEnd: | |
89 return ACMDumpDebugEvent::LOG_END; | |
90 case AcmDump::DebugEvent::kAudioPlayout: | |
91 return ACMDumpDebugEvent::AUDIO_PLAYOUT; | |
92 } | |
93 return ACMDumpDebugEvent::UNKNOWN_EVENT; | |
94 } | |
95 | |
96 } // Anonymous namespace. | |
97 | |
98 // AcmDumpImpl member functions. | |
99 AcmDumpImpl::AcmDumpImpl() | |
100 : crit_(webrtc::CriticalSectionWrapper::CreateCriticalSection()), | |
101 file_(webrtc::FileWrapper::Create()), | |
102 stream_(new webrtc::ACMDumpEventStream()), | |
103 active_(false), | |
104 start_time_us_(0), | |
105 duration_us_(0), | |
106 clock_(webrtc::Clock::GetRealTimeClock()) { | |
107 } | |
108 | |
109 void AcmDumpImpl::StartLogging(const std::string& file_name, int duration_ms) { | |
110 CriticalSectionScoped lock(crit_.get()); | |
111 Clear(); | |
112 if (file_->OpenFile(file_name.c_str(), false) != 0) { | |
113 return; | |
114 } | |
115 // Add a single object to the stream that is reused at every log event. | |
116 stream_->add_stream(); | |
117 active_ = true; | |
118 start_time_us_ = clock_->TimeInMicroseconds(); | |
119 duration_us_ = static_cast<int64_t>(duration_ms) * 1000; | |
120 // Log the start event. | |
121 std::stringstream log_msg; | |
122 log_msg << "Initial timestamp: " << start_time_us_; | |
123 LogDebugEventLocked(DebugEvent::kLogStart, log_msg.str()); | |
124 } | |
125 | |
126 void AcmDumpImpl::LogRtpPacket(bool incoming, | |
127 const uint8_t* packet, | |
128 size_t length) { | |
129 CriticalSectionScoped lock(crit_.get()); | |
130 if (!CurrentlyLogging()) { | |
131 StopIfNecessary(); | |
132 return; | |
133 } | |
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 } | |
148 | |
149 void AcmDumpImpl::LogDebugEvent(DebugEvent event_type, | |
150 const std::string& event_message) { | |
151 CriticalSectionScoped lock(crit_.get()); | |
152 LogDebugEventLocked(event_type, event_message); | |
153 } | |
154 | |
155 void AcmDumpImpl::LogDebugEvent(DebugEvent event_type) { | |
156 CriticalSectionScoped lock(crit_.get()); | |
157 LogDebugEventLocked(event_type, ""); | |
158 } | |
159 | |
160 void AcmDumpImpl::StopIfNecessary() { | |
161 if (active_) { | |
162 DCHECK_GT(clock_->TimeInMicroseconds(), start_time_us_ + duration_us_); | |
163 LogDebugEventLocked(DebugEvent::kLogEnd, ""); | |
164 Clear(); | |
165 } | |
166 } | |
167 | |
168 void AcmDumpImpl::Clear() { | |
169 if (active_ || file_->Open()) { | |
170 file_->CloseFile(); | |
171 } | |
172 active_ = false; | |
173 stream_->Clear(); | |
174 } | |
175 | |
176 void AcmDumpImpl::LogDebugEventLocked(DebugEvent event_type, | |
177 const std::string& event_message) { | |
178 if (!CurrentlyLogging()) { | |
179 StopIfNecessary(); | |
180 return; | |
181 } | |
182 | |
183 // Reuse the same object at every log 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)); | |
191 debug_event->set_message(event_message); | |
192 std::string dump_buffer; | |
193 stream_->SerializeToString(&dump_buffer); | |
194 file_->Write(dump_buffer.data(), dump_buffer.size()); | |
195 } | |
196 | |
197 #endif // RTC_AUDIOCODING_DEBUG_DUMP | |
198 | |
199 // AcmDump member functions. | |
200 rtc::scoped_ptr<AcmDump> AcmDump::Create() { | |
201 return rtc::scoped_ptr<AcmDump>(new AcmDumpImpl()); | |
202 } | |
203 | |
204 bool AcmDump::ParseAcmDump(const std::string& file_name, | |
205 ACMDumpEventStream* result) { | |
206 char tmp_buffer[1024]; | |
207 int bytes_read = 0; | |
208 rtc::scoped_ptr<FileWrapper> dump_file(FileWrapper::Create()); | |
209 if (dump_file->OpenFile(file_name.c_str(), true) != 0) { | |
210 return false; | |
211 } | |
212 std::string dump_buffer; | |
213 while ((bytes_read = dump_file->Read(tmp_buffer, sizeof(tmp_buffer))) > 0) { | |
214 dump_buffer.append(tmp_buffer, bytes_read); | |
215 } | |
216 dump_file->CloseFile(); | |
217 return result->ParseFromString(dump_buffer); | |
218 } | |
219 | |
220 } // namespace webrtc | |
OLD | NEW |