blob: 778cb816bf406603581fb4be789cc1482a984d8d [file] [log] [blame]
andrew@webrtc.orga7b57da2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 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 "voe_call_report_impl.h"
12
13#include "audio_processing.h"
14#include "channel.h"
15#include "critical_section_wrapper.h"
16#include "file_wrapper.h"
17#include "trace.h"
18#include "voe_errors.h"
19#include "voice_engine_impl.h"
20
21namespace webrtc
22{
23
24VoECallReport* VoECallReport::GetInterface(VoiceEngine* voiceEngine)
25{
26#ifndef WEBRTC_VOICE_ENGINE_CALL_REPORT_API
27 return NULL;
28#else
29 if (NULL == voiceEngine)
30 {
31 return NULL;
32 }
33 VoiceEngineImpl* s = reinterpret_cast<VoiceEngineImpl*>(voiceEngine);
34 s->AddRef();
35 return s;
36#endif
37}
38
39#ifdef WEBRTC_VOICE_ENGINE_CALL_REPORT_API
40
41VoECallReportImpl::VoECallReportImpl(voe::SharedData* shared) :
42 _file(*FileWrapper::Create()), _shared(shared)
43{
44 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
45 "VoECallReportImpl() - ctor");
46}
47
48VoECallReportImpl::~VoECallReportImpl()
49{
50 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
51 "~VoECallReportImpl() - dtor");
52 delete &_file;
53}
54
55int VoECallReportImpl::ResetCallReportStatistics(int channel)
56{
57 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
58 "ResetCallReportStatistics(channel=%d)", channel);
59 ANDROID_NOT_SUPPORTED(_shared->statistics());
60 IPHONE_NOT_SUPPORTED(_shared->statistics());
61
62 if (!_shared->statistics().Initialized())
63 {
64 _shared->SetLastError(VE_NOT_INITED, kTraceError);
65 return -1;
66 }
67 assert(_shared->audio_processing() != NULL);
68
69 bool echoMode =
70 _shared->audio_processing()->echo_cancellation()->are_metrics_enabled();
71
72 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
73 " current AudioProcessingModule echo metric state %d)",
74 echoMode);
75 // Reset the APM statistics
76 if (_shared->audio_processing()->echo_cancellation()->enable_metrics(true)
77 != 0)
78 {
79 _shared->SetLastError(VE_APM_ERROR, kTraceError,
80 "ResetCallReportStatistics() unable to "
81 "set the AudioProcessingModule echo metrics state");
82 return -1;
83 }
84 // Restore metric states
85 _shared->audio_processing()->echo_cancellation()->enable_metrics(echoMode);
86
87 // Reset channel dependent statistics
88 if (channel != -1)
89 {
90 voe::ScopedChannel sc(_shared->channel_manager(), channel);
91 voe::Channel* channelPtr = sc.ChannelPtr();
92 if (channelPtr == NULL)
93 {
94 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
95 "ResetCallReportStatistics() failed to locate channel");
96 return -1;
97 }
98 channelPtr->ResetDeadOrAliveCounters();
99 channelPtr->ResetRTCPStatistics();
100 }
101 else
102 {
103 WebRtc_Word32 numOfChannels =
104 _shared->channel_manager().NumOfChannels();
105 if (numOfChannels <= 0)
106 {
107 return 0;
108 }
109 WebRtc_Word32* channelsArray = new WebRtc_Word32[numOfChannels];
110 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
111 for (int i = 0; i < numOfChannels; i++)
112 {
113 voe::ScopedChannel sc(_shared->channel_manager(), channelsArray[i]);
114 voe::Channel* channelPtr = sc.ChannelPtr();
115 if (channelPtr)
116 {
117 channelPtr->ResetDeadOrAliveCounters();
118 channelPtr->ResetRTCPStatistics();
119 }
120 }
121 delete[] channelsArray;
122 }
123
124 return 0;
125}
126
127int VoECallReportImpl::GetEchoMetricSummary(EchoStatistics& stats)
128{
129 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
130 "GetEchoMetricSummary()");
131 ANDROID_NOT_SUPPORTED(_shared->statistics());
132 IPHONE_NOT_SUPPORTED(_shared->statistics());
133
134 if (!_shared->statistics().Initialized())
135 {
136 _shared->SetLastError(VE_NOT_INITED, kTraceError);
137 return -1;
138 }
139 assert(_shared->audio_processing() != NULL);
140
141 return (GetEchoMetricSummaryInternal(stats));
142}
143
144int VoECallReportImpl::GetEchoMetricSummaryInternal(EchoStatistics& stats)
145{
146 // Retrieve echo metrics from the AudioProcessingModule
147 int ret(0);
148 bool mode(false);
149 EchoCancellation::Metrics metrics;
150
151 // Ensure that echo metrics is enabled
152
153 mode =
154 _shared->audio_processing()->echo_cancellation()->are_metrics_enabled();
155 if (mode != false)
156 {
157 ret = _shared->audio_processing()->echo_cancellation()->
158 GetMetrics(&metrics);
159 if (ret != 0)
160 {
161 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
162 VoEId(_shared->instance_id(), -1),
163 " AudioProcessingModule GetMetrics() => error");
164 }
165 }
166 else
167 {
168 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
169 VoEId(_shared->instance_id(), -1),
170 " AudioProcessingModule echo metrics is not enabled");
171 }
172
173 if ((ret != 0) || (mode == false))
174 {
175 // Mark complete struct as invalid (-100 dB)
176 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
177 VoEId(_shared->instance_id(), -1),
178 " unable to retrieve echo metrics from the AudioProcessingModule");
179 stats.erl.min = -100;
180 stats.erl.max = -100;
181 stats.erl.average = -100;
182 stats.erle.min = -100;
183 stats.erle.max = -100;
184 stats.erle.average = -100;
185 stats.rerl.min = -100;
186 stats.rerl.max = -100;
187 stats.rerl.average = -100;
188 stats.a_nlp.min = -100;
189 stats.a_nlp.max = -100;
190 stats.a_nlp.average = -100;
191 }
192 else
193 {
194
195 // Deliver output results to user
196 stats.erl.min = metrics.echo_return_loss.minimum;
197 stats.erl.max = metrics.echo_return_loss.maximum;
198 stats.erl.average = metrics.echo_return_loss.average;
199 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
200 VoEId(_shared->instance_id(), -1), " erl: min=%d, max=%d, avg=%d",
201 stats.erl.min, stats.erl.max, stats.erl.average);
202
203 stats.erle.min = metrics.echo_return_loss_enhancement.minimum;
204 stats.erle.max = metrics.echo_return_loss_enhancement.maximum;
205 stats.erle.average = metrics.echo_return_loss_enhancement.average;
206 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
207 VoEId(_shared->instance_id(), -1), " erle: min=%d, max=%d, avg=%d",
208 stats.erle.min, stats.erle.max, stats.erle.average);
209
210 stats.rerl.min = metrics.residual_echo_return_loss.minimum;
211 stats.rerl.max = metrics.residual_echo_return_loss.maximum;
212 stats.rerl.average = metrics.residual_echo_return_loss.average;
213 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
214 VoEId(_shared->instance_id(), -1), " rerl: min=%d, max=%d, avg=%d",
215 stats.rerl.min, stats.rerl.max, stats.rerl.average);
216
217 stats.a_nlp.min = metrics.a_nlp.minimum;
218 stats.a_nlp.max = metrics.a_nlp.maximum;
219 stats.a_nlp.average = metrics.a_nlp.average;
220 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
221 VoEId(_shared->instance_id(), -1),
222 " a_nlp: min=%d, max=%d, avg=%d",
223 stats.a_nlp.min, stats.a_nlp.max, stats.a_nlp.average);
224 }
225 return 0;
226}
227
228int VoECallReportImpl::GetRoundTripTimeSummary(int channel, StatVal& delaysMs)
229{
230 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
231 "GetRoundTripTimeSummary()");
232 ANDROID_NOT_SUPPORTED(_shared->statistics());
233 IPHONE_NOT_SUPPORTED(_shared->statistics());
234
235 if (!_shared->statistics().Initialized())
236 {
237 _shared->SetLastError(VE_NOT_INITED, kTraceError);
238 return -1;
239 }
240 voe::ScopedChannel sc(_shared->channel_manager(), channel);
241 voe::Channel* channelPtr = sc.ChannelPtr();
242 if (channelPtr == NULL)
243 {
244 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
245 "GetRoundTripTimeSummary() failed to locate channel");
246 return -1;
247 }
248
249 return channelPtr->GetRoundTripTimeSummary(delaysMs);
250}
251
252int VoECallReportImpl::GetDeadOrAliveSummary(int channel,
253 int& numOfDeadDetections,
254 int& numOfAliveDetections)
255{
256 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
257 "GetDeadOrAliveSummary(channel=%d)", channel);
258 ANDROID_NOT_SUPPORTED(_shared->statistics());
259 IPHONE_NOT_SUPPORTED(_shared->statistics());
260
261 if (!_shared->statistics().Initialized())
262 {
263 _shared->SetLastError(VE_NOT_INITED, kTraceError);
264 return -1;
265 }
266
267 return (GetDeadOrAliveSummaryInternal(channel, numOfDeadDetections,
268 numOfAliveDetections));
269}
270
271int VoECallReportImpl::GetDeadOrAliveSummaryInternal(int channel,
272 int& numOfDeadDetections,
273 int& numOfAliveDetections)
274{
275 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
276 "GetDeadOrAliveSummary(channel=%d)", channel);
277
278 if (!_shared->statistics().Initialized())
279 {
280 _shared->SetLastError(VE_NOT_INITED, kTraceError);
281 return -1;
282 }
283 voe::ScopedChannel sc(_shared->channel_manager(), channel);
284 voe::Channel* channelPtr = sc.ChannelPtr();
285 if (channelPtr == NULL)
286 {
287 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
288 "GetRoundTripTimeSummary() failed to locate channel");
289 return -1;
290 }
291
292 return channelPtr->GetDeadOrAliveCounters(numOfDeadDetections,
293 numOfAliveDetections);
294}
295
296int VoECallReportImpl::WriteReportToFile(const char* fileNameUTF8)
297{
298 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
299 "WriteReportToFile(fileNameUTF8=%s)", fileNameUTF8);
300 ANDROID_NOT_SUPPORTED(_shared->statistics());
301 IPHONE_NOT_SUPPORTED(_shared->statistics());
302
303 if (!_shared->statistics().Initialized())
304 {
305 _shared->SetLastError(VE_NOT_INITED, kTraceError);
306 return -1;
307 }
308
309 if (NULL == fileNameUTF8)
310 {
311 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
312 "WriteReportToFile() invalid filename");
313 return -1;
314 }
315
316 if (_file.Open())
317 {
318 _file.CloseFile();
319 }
320
321 // Open text file in write mode
322 if (_file.OpenFile(fileNameUTF8, false, false, true) != 0)
323 {
324 _shared->SetLastError(VE_BAD_FILE, kTraceError,
325 "WriteReportToFile() unable to open the file");
326 return -1;
327 }
328
329 // Summarize information and add it to the open file
330 //
331 _file.WriteText("WebRtc VoiceEngine Call Report\n");
332 _file.WriteText("==============================\n");
333 _file.WriteText("\nNetwork Packet Round Trip Time (RTT)\n");
334 _file.WriteText("------------------------------------\n\n");
335
336 WebRtc_Word32 numOfChannels = _shared->channel_manager().NumOfChannels();
337 if (numOfChannels <= 0)
338 {
339 return 0;
340 }
341 WebRtc_Word32* channelsArray = new WebRtc_Word32[numOfChannels];
342 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
343 for (int ch = 0; ch < numOfChannels; ch++)
344 {
345 voe::ScopedChannel sc(_shared->channel_manager(), channelsArray[ch]);
346 voe::Channel* channelPtr = sc.ChannelPtr();
347 if (channelPtr)
348 {
349 StatVal delaysMs;
350 _file.WriteText("channel %d:\n", ch);
351 channelPtr->GetRoundTripTimeSummary(delaysMs);
352 _file.WriteText(" min:%5d [ms]\n", delaysMs.min);
353 _file.WriteText(" max:%5d [ms]\n", delaysMs.max);
354 _file.WriteText(" avg:%5d [ms]\n", delaysMs.average);
355 }
356 }
357
358 _file.WriteText("\nDead-or-Alive Connection Detections\n");
359 _file.WriteText("------------------------------------\n\n");
360
361 for (int ch = 0; ch < numOfChannels; ch++)
362 {
363 voe::ScopedChannel sc(_shared->channel_manager(), channelsArray[ch]);
364 voe::Channel* channelPtr = sc.ChannelPtr();
365 if (channelPtr)
366 {
367 int nDead(0);
368 int nAlive(0);
369 _file.WriteText("channel %d:\n", ch);
370 GetDeadOrAliveSummary(ch, nDead, nAlive);
371 _file.WriteText(" #dead :%6d\n", nDead);
372 _file.WriteText(" #alive:%6d\n", nAlive);
373 }
374 }
375
376 delete[] channelsArray;
377
378 EchoStatistics echo;
379 GetEchoMetricSummary(echo);
380
381 _file.WriteText("\nEcho Metrics\n");
382 _file.WriteText("------------\n\n");
383
384 _file.WriteText("erl:\n");
385 _file.WriteText(" min:%5d [dB]\n", echo.erl.min);
386 _file.WriteText(" max:%5d [dB]\n", echo.erl.max);
387 _file.WriteText(" avg:%5d [dB]\n", echo.erl.average);
388 _file.WriteText("\nerle:\n");
389 _file.WriteText(" min:%5d [dB]\n", echo.erle.min);
390 _file.WriteText(" max:%5d [dB]\n", echo.erle.max);
391 _file.WriteText(" avg:%5d [dB]\n", echo.erle.average);
392 _file.WriteText("rerl:\n");
393 _file.WriteText(" min:%5d [dB]\n", echo.rerl.min);
394 _file.WriteText(" max:%5d [dB]\n", echo.rerl.max);
395 _file.WriteText(" avg:%5d [dB]\n", echo.rerl.average);
396 _file.WriteText("a_nlp:\n");
397 _file.WriteText(" min:%5d [dB]\n", echo.a_nlp.min);
398 _file.WriteText(" max:%5d [dB]\n", echo.a_nlp.max);
399 _file.WriteText(" avg:%5d [dB]\n", echo.a_nlp.average);
400
401 _file.WriteText("\n<END>");
402
403 _file.Flush();
404 _file.CloseFile();
405
406 return 0;
407}
408
409#endif // WEBRTC_VOICE_ENGINE_CALL_REPORT_API
410
411} // namespace webrtc