1 /* 2 * Copyright (C) 2015 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.cts.verifier.audio; 18 19 import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode; 20 import static com.android.cts.verifier.TestListAdapter.setTestNameSuffix; 21 22 import android.content.Context; 23 import android.media.AudioDeviceInfo; 24 import android.media.AudioTrack; 25 import android.os.Bundle; 26 import android.os.Handler; 27 import android.util.Log; 28 import android.view.View; 29 import android.view.View.OnClickListener; 30 import android.widget.Button; 31 import android.widget.TextView; 32 33 import com.android.compatibility.common.util.ResultType; 34 import com.android.compatibility.common.util.ResultUnit; 35 import com.android.cts.verifier.CtsVerifierReportLog; 36 import com.android.cts.verifier.R; 37 import com.android.cts.verifier.audio.audiolib.AudioDeviceUtils; 38 39 import org.hyphonate.megaaudio.common.BuilderBase; 40 import org.hyphonate.megaaudio.common.StreamBase; 41 import org.hyphonate.megaaudio.player.JavaPlayer; 42 import org.hyphonate.megaaudio.player.PlayerBuilder; 43 import org.hyphonate.megaaudio.player.sources.SinAudioSourceProvider; 44 45 /** 46 * Tests AudioTrack and AudioRecord (re)Routing messages. 47 */ 48 public class AudioOutputRoutingNotificationsActivity extends AudioWiredDeviceBaseActivity { 49 private static final String TAG = "AudioOutputRoutingNotificationsActivity"; 50 51 static final int NUM_CHANNELS = 2; 52 static final int SAMPLE_RATE = 48000; 53 54 Context mContext; 55 56 Button playBtn; 57 Button stopBtn; 58 TextView mInfoView; 59 60 int mNumRoutingNotifications; 61 62 private OnBtnClickListener mBtnClickListener = new OnBtnClickListener(); 63 64 // ignore messages sent as a consequence of starting the player 65 private static final int NUM_IGNORE_MESSAGES = 1; 66 67 // Mega Player 68 private JavaPlayer mAudioPlayer; 69 private AudioTrackRoutingChangeListener mRoutingChangeListener; 70 private boolean mIsPlaying; 71 72 private boolean mInitialRoutingMessageHandled; 73 74 boolean mRoutingNotificationReceived; 75 76 // ReportLog schema 77 private static final String SECTION_OUTPUT_ROUTING = "audio_out_routing_notifications"; 78 79 private class OnBtnClickListener implements OnClickListener { 80 @Override onClick(View v)81 public void onClick(View v) { 82 if (mAudioPlayer == null) { 83 return; // failed to create the player 84 } 85 int id = v.getId(); 86 if (id == R.id.audio_routingnotification_playBtn) { 87 startPlayback(); 88 } else if (id == R.id.audio_routingnotification_playStopBtn) { 89 stopPlayback(); 90 } 91 } 92 } 93 startPlayback()94 private void startPlayback() { 95 if (!mIsPlaying) { 96 mNumRoutingNotifications = 0; 97 98 mAudioPlayer.startStream(); 99 100 AudioTrack audioTrack = mAudioPlayer.getAudioTrack(); 101 audioTrack.addOnRoutingChangedListener(mRoutingChangeListener, 102 new Handler()); 103 104 mIsPlaying = true; 105 106 enableTestButtons(false); 107 } 108 } 109 stopPlayback()110 private void stopPlayback() { 111 if (mIsPlaying) { 112 mAudioPlayer.stopStream(); 113 114 AudioTrack audioTrack = mAudioPlayer.getAudioTrack(); 115 audioTrack.removeOnRoutingChangedListener(mRoutingChangeListener); 116 117 mIsPlaying = false; 118 119 enableTestButtons(true); 120 } 121 } 122 123 private class AudioTrackRoutingChangeListener implements AudioTrack.OnRoutingChangedListener { onRoutingChanged(AudioTrack audioTrack)124 public void onRoutingChanged(AudioTrack audioTrack) { 125 // Starting playback triggers a messages, so ignore the first one. 126 mNumRoutingNotifications++; 127 if (mNumRoutingNotifications <= NUM_IGNORE_MESSAGES) { 128 return; 129 } 130 131 TextView textView = 132 (TextView)findViewById(R.id.audio_routingnotification_audioTrack_change); 133 String msg = mContext.getResources().getString( 134 R.string.audio_routingnotification_trackRoutingMsg); 135 AudioDeviceInfo routedDevice = audioTrack.getRoutedDevice(); 136 mConnectedPeripheralName = AudioDeviceUtils.formatDeviceName(routedDevice); 137 textView.setText(msg + ": " + mConnectedPeripheralName); 138 mRoutingNotificationReceived = true; 139 calculatePass(); 140 } 141 } 142 143 @Override enableTestButtons(boolean enabled)144 protected void enableTestButtons(boolean enabled) { 145 playBtn.setEnabled(enabled); 146 stopBtn.setEnabled(!enabled); 147 } 148 149 @Override calculatePass()150 protected void calculatePass() { 151 getPassButton().setEnabled(isReportLogOkToPass() 152 && mRoutingNotificationReceived || !mSupportsWiredPeripheral); 153 TextView tv = ((TextView) findViewById(R.id.audio_routingnotification_testresult)); 154 if (!isReportLogOkToPass()) { 155 tv.setText(getResources().getString(R.string.audio_general_reportlogtest)); 156 } else if (mRoutingNotificationReceived) { 157 tv.setText("Test PASSES - Routing notification received"); 158 } else if (!mSupportsWiredPeripheral) { 159 tv.setText("Test PASSES - No peripheral support"); 160 } else { 161 tv.setText(""); 162 } 163 } 164 165 @Override getReportSectionName()166 public final String getReportSectionName() { 167 return setTestNameSuffix(sCurrentDisplayMode, SECTION_OUTPUT_ROUTING); 168 } 169 170 @Override recordTestResults()171 public void recordTestResults() { 172 super.recordTestResults(); 173 174 CtsVerifierReportLog reportLog = getReportLog(); 175 reportLog.addValue( 176 KEY_ROUTING_RECEIVED, 177 mRoutingNotificationReceived ? 1 : 0, 178 ResultType.NEUTRAL, 179 ResultUnit.NONE); 180 181 reportLog.submit(); 182 } 183 184 @Override onCreate(Bundle savedInstanceState)185 protected void onCreate(Bundle savedInstanceState) { 186 super.onCreate(savedInstanceState); 187 setContentView(R.layout.audio_output_routingnotifications_test); 188 189 mContext = this; 190 191 playBtn = (Button) findViewById(R.id.audio_routingnotification_playBtn); 192 playBtn.setOnClickListener(mBtnClickListener); 193 stopBtn = (Button) findViewById(R.id.audio_routingnotification_playStopBtn); 194 stopBtn.setOnClickListener(mBtnClickListener); 195 196 mInfoView = (TextView) findViewById(R.id.info_text); 197 198 enableTestButtons(false); 199 200 // Setup Player 201 // 202 // Allocate the source provider for the sort of signal we want to play 203 // 204 int numExchangeFrames = StreamBase.getNumBurstFrames(BuilderBase.TYPE_NONE); 205 try { 206 PlayerBuilder builder = new PlayerBuilder(); 207 builder.setSourceProvider(new SinAudioSourceProvider()) 208 .setPlayerType(PlayerBuilder.TYPE_JAVA) 209 .setChannelCount(NUM_CHANNELS) 210 .setSampleRate(SAMPLE_RATE) 211 .setNumExchangeFrames(numExchangeFrames); 212 mAudioPlayer = (JavaPlayer) builder.build(); 213 } catch (PlayerBuilder.BadStateException ex) { 214 Log.e(TAG, "Failed MegaPlayer build."); 215 } 216 217 mRoutingChangeListener = new AudioTrackRoutingChangeListener(); 218 219 // "Honor System" buttons 220 super.setup(); 221 setInfoResources(R.string.audio_output_routingnotifications_test, 222 R.string.audio_output_routingnotification_instructions, -1); 223 setPassFailButtonClickListeners(); 224 getPassButton().setEnabled(false); 225 } 226 227 @Override onBackPressed()228 public void onBackPressed () { 229 stopPlayback(); 230 super.onBackPressed(); 231 } 232 } 233