1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.media.tests; 18 19 import com.android.ddmlib.CollectingOutputReceiver; 20 import com.android.ddmlib.testrunner.TestIdentifier; 21 import com.android.tradefed.device.DeviceNotAvailableException; 22 import com.android.tradefed.device.ITestDevice; 23 import com.android.tradefed.log.LogUtil.CLog; 24 import com.android.tradefed.result.ITestInvocationListener; 25 import com.android.tradefed.testtype.IDeviceTest; 26 import com.android.tradefed.testtype.IRemoteTest; 27 28 import java.util.Collections; 29 import java.util.HashMap; 30 import java.util.Map; 31 import java.util.concurrent.TimeUnit; 32 33 /** 34 * A harness that launches AudioJitter tool and reports result. 35 */ 36 public class AudioJitterTest implements IDeviceTest, IRemoteTest { 37 38 private static final String RUN_KEY = "audiojitter"; 39 private static final long TIMEOUT_MS = 5 * 60 * 1000; // 5 min 40 private static final int MAX_ATTEMPTS = 3; 41 private static final Map<String, String> METRICS_KEY_MAP = createMetricsKeyMap(); 42 43 private ITestDevice mDevice; 44 45 private static final String DEVICE_TEMPORARY_DIR_PATH = "/data/local/tmp/"; 46 private static final String JITTER_BINARY_FILENAME = "sljitter"; 47 private static final String JITTER_BINARY_DEVICE_PATH = 48 DEVICE_TEMPORARY_DIR_PATH + JITTER_BINARY_FILENAME; 49 50 private static Map<String, String> createMetricsKeyMap() { 51 Map<String, String> result = new HashMap<String, String>(); 52 result.put("min_jitter_ticks", "min_jitter_ticks"); 53 result.put("min_jitter_ms", "min_jitter_ms"); 54 result.put("min_jitter_period_id", "min_jitter_period_id"); 55 result.put("max_jitter_ticks", "max_jitter_ticks"); 56 result.put("max_jitter_ms", "max_jitter_ms"); 57 result.put("max_jitter_period_id", "max_jitter_period_id"); 58 result.put("mark_jitter_ticks", "mark_jitter_ticks"); 59 result.put("mark_jitter_ms", "mark_jitter_ms"); 60 result.put("max_cb_done_delay_ms", "max_cb_done_delay_ms"); 61 result.put("max_thread_delay_ms", "max_thread_delay_ms"); 62 result.put("max_render_delay_ms", "max_render_delay_ms"); 63 result.put("drift_rate", "drift_rate"); 64 result.put("error_ms", "error_ms"); 65 result.put("min_error_ms", "min_error_ms"); 66 result.put("max_error_ms", "max_error_ms"); 67 return Collections.unmodifiableMap(result); 68 } 69 70 /** 71 * {@inheritDoc} 72 */ 73 @Override 74 public void setDevice(ITestDevice device) { 75 mDevice = device; 76 } 77 78 /** 79 * {@inheritDoc} 80 */ 81 @Override 82 public ITestDevice getDevice() { 83 return mDevice; 84 } 85 86 /** 87 * {@inheritDoc} 88 */ 89 @Override 90 public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { 91 TestIdentifier testId = new TestIdentifier(getClass().getCanonicalName(), RUN_KEY); 92 ITestDevice device = getDevice(); 93 94 listener.testRunStarted(RUN_KEY, 0); 95 listener.testStarted(testId); 96 97 long testStartTime = System.currentTimeMillis(); 98 Map<String, String> metrics = new HashMap<String, String>(); 99 String errMsg = null; 100 101 // start jitter and wait for process to complete 102 CollectingOutputReceiver receiver = new CollectingOutputReceiver(); 103 device.executeShellCommand(JITTER_BINARY_DEVICE_PATH, receiver, 104 TIMEOUT_MS, TimeUnit.MILLISECONDS, MAX_ATTEMPTS); 105 String resultStr = receiver.getOutput(); 106 107 if (resultStr != null) { 108 // parse result 109 CLog.i("== Jitter result =="); 110 Map<String, String> jitterResult = parseResult(resultStr); 111 if (jitterResult == null) { 112 errMsg = "Failed to parse Jitter result."; 113 } else { 114 metrics = jitterResult; 115 } 116 } else { 117 errMsg = "Jitter result not found."; 118 } 119 120 if (errMsg != null) { 121 CLog.e(errMsg); 122 listener.testFailed(testId, errMsg); 123 listener.testEnded(testId, metrics); 124 listener.testRunFailed(errMsg); 125 } else { 126 long durationMs = System.currentTimeMillis() - testStartTime; 127 listener.testEnded(testId, metrics); 128 listener.testRunEnded(durationMs, metrics); 129 } 130 } 131 132 /** 133 * Parse Jitter result. 134 * 135 * @param result Jitter result output 136 * @return a {@link HashMap} that contains metrics keys and results 137 */ 138 private Map<String, String> parseResult(String result) { 139 Map<String, String> resultMap = new HashMap<String, String>(); 140 String lines[] = result.split("\\r?\\n"); 141 for (String line: lines) { 142 line = line.trim().replaceAll(" +", " "); 143 String[] tokens = line.split(" "); 144 if (tokens.length >= 2) { 145 String metricName = tokens[0]; 146 String metricValue = tokens[1]; 147 if (METRICS_KEY_MAP.containsKey(metricName)) { 148 CLog.i(String.format("%s: %s", metricName, metricValue)); 149 resultMap.put(METRICS_KEY_MAP.get(metricName), metricValue); 150 } 151 } 152 } 153 return resultMap; 154 } 155 } 156