1 /*
2  *  Copyright 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 package org.appspot.apprtc;
12 
13 import android.app.Fragment;
14 import android.os.Bundle;
15 import android.util.TypedValue;
16 import android.view.LayoutInflater;
17 import android.view.View;
18 import android.view.ViewGroup;
19 import android.widget.ImageButton;
20 import android.widget.TextView;
21 
22 import org.webrtc.StatsReport;
23 
24 import java.util.HashMap;
25 import java.util.Map;
26 
27 /**
28  * Fragment for HUD statistics display.
29  */
30 public class HudFragment extends Fragment {
31   private View controlView;
32   private TextView encoderStatView;
33   private TextView hudViewBwe;
34   private TextView hudViewConnection;
35   private TextView hudViewVideoSend;
36   private TextView hudViewVideoRecv;
37   private ImageButton toggleDebugButton;
38   private boolean videoCallEnabled;
39   private boolean displayHud;
40   private volatile boolean isRunning;
41   private final CpuMonitor cpuMonitor = new CpuMonitor();
42 
43   @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)44   public View onCreateView(LayoutInflater inflater, ViewGroup container,
45       Bundle savedInstanceState) {
46     controlView = inflater.inflate(R.layout.fragment_hud, container, false);
47 
48     // Create UI controls.
49     encoderStatView = (TextView) controlView.findViewById(R.id.encoder_stat_call);
50     hudViewBwe = (TextView) controlView.findViewById(R.id.hud_stat_bwe);
51     hudViewConnection = (TextView) controlView.findViewById(R.id.hud_stat_connection);
52     hudViewVideoSend = (TextView) controlView.findViewById(R.id.hud_stat_video_send);
53     hudViewVideoRecv = (TextView) controlView.findViewById(R.id.hud_stat_video_recv);
54     toggleDebugButton = (ImageButton) controlView.findViewById(R.id.button_toggle_debug);
55 
56     toggleDebugButton.setOnClickListener(new View.OnClickListener() {
57       @Override
58       public void onClick(View view) {
59         if (displayHud) {
60           int visibility = (hudViewBwe.getVisibility() == View.VISIBLE)
61               ? View.INVISIBLE : View.VISIBLE;
62           hudViewsSetProperties(visibility);
63         }
64       }
65     });
66 
67     return controlView;
68   }
69 
70   @Override
onStart()71   public void onStart() {
72     super.onStart();
73 
74     Bundle args = getArguments();
75     if (args != null) {
76       videoCallEnabled = args.getBoolean(CallActivity.EXTRA_VIDEO_CALL, true);
77       displayHud = args.getBoolean(CallActivity.EXTRA_DISPLAY_HUD, false);
78     }
79     int visibility = displayHud ? View.VISIBLE : View.INVISIBLE;
80     encoderStatView.setVisibility(visibility);
81     toggleDebugButton.setVisibility(visibility);
82     hudViewsSetProperties(View.INVISIBLE);
83     isRunning = true;
84   }
85 
86   @Override
onStop()87   public void onStop() {
88     isRunning = false;
89     super.onStop();
90   }
91 
hudViewsSetProperties(int visibility)92   private void hudViewsSetProperties(int visibility) {
93     hudViewBwe.setVisibility(visibility);
94     hudViewConnection.setVisibility(visibility);
95     hudViewVideoSend.setVisibility(visibility);
96     hudViewVideoRecv.setVisibility(visibility);
97     hudViewBwe.setTextSize(TypedValue.COMPLEX_UNIT_PT, 5);
98     hudViewConnection.setTextSize(TypedValue.COMPLEX_UNIT_PT, 5);
99     hudViewVideoSend.setTextSize(TypedValue.COMPLEX_UNIT_PT, 5);
100     hudViewVideoRecv.setTextSize(TypedValue.COMPLEX_UNIT_PT, 5);
101   }
102 
getReportMap(StatsReport report)103   private Map<String, String> getReportMap(StatsReport report) {
104     Map<String, String> reportMap = new HashMap<String, String>();
105     for (StatsReport.Value value : report.values) {
106       reportMap.put(value.name, value.value);
107     }
108     return reportMap;
109   }
110 
updateEncoderStatistics(final StatsReport[] reports)111   public void updateEncoderStatistics(final StatsReport[] reports) {
112     if (!isRunning || !displayHud) {
113       return;
114     }
115     StringBuilder encoderStat = new StringBuilder(128);
116     StringBuilder bweStat = new StringBuilder();
117     StringBuilder connectionStat = new StringBuilder();
118     StringBuilder videoSendStat = new StringBuilder();
119     StringBuilder videoRecvStat = new StringBuilder();
120     String fps = null;
121     String targetBitrate = null;
122     String actualBitrate = null;
123 
124     for (StatsReport report : reports) {
125       if (report.type.equals("ssrc") && report.id.contains("ssrc")
126           && report.id.contains("send")) {
127         // Send video statistics.
128         Map<String, String> reportMap = getReportMap(report);
129         String trackId = reportMap.get("googTrackId");
130         if (trackId != null && trackId.contains(PeerConnectionClient.VIDEO_TRACK_ID)) {
131           fps = reportMap.get("googFrameRateSent");
132           videoSendStat.append(report.id).append("\n");
133           for (StatsReport.Value value : report.values) {
134             String name = value.name.replace("goog", "");
135             videoSendStat.append(name).append("=").append(value.value).append("\n");
136           }
137         }
138       } else if (report.type.equals("ssrc") && report.id.contains("ssrc")
139           && report.id.contains("recv")) {
140         // Receive video statistics.
141         Map<String, String> reportMap = getReportMap(report);
142         // Check if this stat is for video track.
143         String frameWidth = reportMap.get("googFrameWidthReceived");
144         if (frameWidth != null) {
145           videoRecvStat.append(report.id).append("\n");
146           for (StatsReport.Value value : report.values) {
147             String name = value.name.replace("goog", "");
148             videoRecvStat.append(name).append("=").append(value.value).append("\n");
149           }
150         }
151       } else if (report.id.equals("bweforvideo")) {
152         // BWE statistics.
153         Map<String, String> reportMap = getReportMap(report);
154         targetBitrate = reportMap.get("googTargetEncBitrate");
155         actualBitrate = reportMap.get("googActualEncBitrate");
156 
157         bweStat.append(report.id).append("\n");
158         for (StatsReport.Value value : report.values) {
159           String name = value.name.replace("goog", "").replace("Available", "");
160           bweStat.append(name).append("=").append(value.value).append("\n");
161         }
162       } else if (report.type.equals("googCandidatePair")) {
163         // Connection statistics.
164         Map<String, String> reportMap = getReportMap(report);
165         String activeConnection = reportMap.get("googActiveConnection");
166         if (activeConnection != null && activeConnection.equals("true")) {
167           connectionStat.append(report.id).append("\n");
168           for (StatsReport.Value value : report.values) {
169             String name = value.name.replace("goog", "");
170             connectionStat.append(name).append("=").append(value.value).append("\n");
171           }
172         }
173       }
174     }
175     hudViewBwe.setText(bweStat.toString());
176     hudViewConnection.setText(connectionStat.toString());
177     hudViewVideoSend.setText(videoSendStat.toString());
178     hudViewVideoRecv.setText(videoRecvStat.toString());
179 
180     if (videoCallEnabled) {
181       if (fps != null) {
182         encoderStat.append("Fps:  ").append(fps).append("\n");
183       }
184       if (targetBitrate != null) {
185         encoderStat.append("Target BR: ").append(targetBitrate).append("\n");
186       }
187       if (actualBitrate != null) {
188         encoderStat.append("Actual BR: ").append(actualBitrate).append("\n");
189       }
190     }
191 
192     if (cpuMonitor.sampleCpuUtilization()) {
193       encoderStat.append("CPU%: ")
194           .append(cpuMonitor.getCpuCurrent()).append("/")
195           .append(cpuMonitor.getCpuAvg3()).append("/")
196           .append(cpuMonitor.getCpuAvgAll());
197     }
198     encoderStatView.setText(encoderStat.toString());
199   }
200 }
201