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.media.AudioDeviceInfo;
23 import android.media.AudioManager;
24 import android.media.AudioTrack;
25 import android.os.Bundle;
26 import android.os.Handler;
27 import android.util.Log;
28 import android.widget.TextView;
29 
30 import com.android.cts.verifier.R;
31 import com.android.cts.verifier.audio.audiolib.AudioDeviceUtils;
32 
33 import org.hyphonate.megaaudio.common.BuilderBase;
34 import org.hyphonate.megaaudio.common.StreamBase;
35 import org.hyphonate.megaaudio.player.JavaPlayer;
36 import org.hyphonate.megaaudio.player.PlayerBuilder;
37 import org.hyphonate.megaaudio.player.sources.SilenceAudioSourceProvider;
38 
39 /**
40  * Tests AudioTrack and AudioRecord (re)Routing messages.
41  */
42 public class AudioOutputRoutingNotificationsActivity extends AudioNotificationsBaseActivity {
43     private static final String TAG = "AudioOutputRoutingNotificationsActivity";
44 
45     static final int NUM_CHANNELS = 2;
46     static final int SAMPLE_RATE = 48000;
47 
48     int mNumRoutingNotifications;
49 
50     // ignore messages sent as a consequence of starting the player
51     private static final int NUM_IGNORE_MESSAGES = 1;
52 
53     // Mega Player
54     private JavaPlayer mAudioPlayer;
55     private AudioTrackRoutingChangeListener mRoutingChangeListener;
56     private boolean mIsPlaying;
57 
58     private boolean mInitialRoutingMessageHandled;
59 
60     // ReportLog schema
61     private static final String SECTION_OUTPUT_ROUTING = "audio_out_routing_notifications";
62 
AudioOutputRoutingNotificationsActivity()63     public AudioOutputRoutingNotificationsActivity() {
64         super(AudioManager.GET_DEVICES_OUTPUTS);
65     }
66 
67     @Override
onCreate(Bundle savedInstanceState)68     protected void onCreate(Bundle savedInstanceState) {
69         setContentView(R.layout.audio_routingnotifications_test);
70         super.onCreate(savedInstanceState);
71 
72         ((TextView) findViewById(R.id.audio_routingnotification_instructions))
73                 .setText(getText(R.string.audio_output_routingnotification_instructions));
74 
75         // Setup Player
76         //
77         // Allocate the source provider for the sort of signal we want to play
78         //
79         int numExchangeFrames = StreamBase.getNumBurstFrames(BuilderBase.TYPE_NONE);
80         try {
81             PlayerBuilder builder = new PlayerBuilder();
82             builder.setSourceProvider(new SilenceAudioSourceProvider())
83                     .setPlayerType(PlayerBuilder.TYPE_JAVA)
84                     .setChannelCount(NUM_CHANNELS)
85                     .setSampleRate(SAMPLE_RATE)
86                     .setNumExchangeFrames(numExchangeFrames);
87             mAudioPlayer = (JavaPlayer) builder.build();
88         } catch (PlayerBuilder.BadStateException ex) {
89             Log.e(TAG, "Failed MegaPlayer build.");
90         }
91 
92         setInfoResources(R.string.audio_output_routingnotifications_test,
93                 R.string.audio_output_routingnotification_instructions, -1);
94 
95         mRoutingChangeListener = new AudioTrackRoutingChangeListener();
96 
97         startAudio();
98     }
99 
100     @Override
startAudio()101     void startAudio() {
102         if (mAudioPlayer == null) {
103             return; // failed to create the player
104         }
105         if (!mIsPlaying) {
106             mNumRoutingNotifications = 0;
107 
108             mAudioPlayer.startStream();
109 
110             AudioTrack audioTrack = mAudioPlayer.getAudioTrack();
111             audioTrack.addOnRoutingChangedListener(mRoutingChangeListener,
112                     new Handler());
113 
114             mIsPlaying = true;
115         }
116     }
117 
118     @Override
stopAudio()119     void stopAudio() {
120         if (mAudioPlayer == null) {
121             return; // failed to create the player
122         }
123         if (mIsPlaying) {
124             mAudioPlayer.stopStream();
125 
126             AudioTrack audioTrack = mAudioPlayer.getAudioTrack();
127             audioTrack.removeOnRoutingChangedListener(mRoutingChangeListener);
128 
129             mIsPlaying = false;
130         }
131     }
132 
133     private class AudioTrackRoutingChangeListener implements AudioTrack.OnRoutingChangedListener {
onRoutingChanged(AudioTrack audioTrack)134         public void onRoutingChanged(AudioTrack audioTrack) {
135             // Starting playback triggers a message, so ignore the first one.
136             mNumRoutingNotifications++;
137             if (mNumRoutingNotifications <= NUM_IGNORE_MESSAGES) {
138                 return;
139             }
140 
141             TextView textView =
142                     (TextView) findViewById(R.id.audio_routingnotification_change);
143             String msg = mContext.getString(
144                     R.string.audio_routingnotification_trackRoutingMsg);
145             AudioDeviceInfo routedDevice = audioTrack.getRoutedDevice();
146             mConnectedPeripheralName = AudioDeviceUtils.formatDeviceName(routedDevice);
147             textView.setText(msg + ": " + mConnectedPeripheralName);
148             mRoutingNotificationReceived = true;
149             stopAudio();
150             calculatePass();
151         }
152     }
153 
154     @Override
getReportSectionName()155     public final String getReportSectionName() {
156         return setTestNameSuffix(sCurrentDisplayMode, SECTION_OUTPUT_ROUTING);
157     }
158 }
159