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