• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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.google.sample.oboe.manualtest;
18 
19 import android.content.Context;
20 import android.media.AudioManager;
21 import android.util.AttributeSet;
22 import android.view.LayoutInflater;
23 import android.view.View;
24 import android.widget.AdapterView;
25 import android.widget.CheckBox;
26 import android.widget.Spinner;
27 import android.widget.TableLayout;
28 import android.widget.TableRow;
29 import android.widget.TextView;
30 import android.widget.LinearLayout;
31 
32 import com.google.sample.audio_device.AudioDeviceListEntry;
33 import com.google.sample.audio_device.AudioDeviceSpinner;
34 
35 import java.text.BreakIterator;
36 
37 /**
38  * View for Editing a requested StreamConfiguration
39  * and displaying the actual StreamConfiguration.
40  */
41 
42 public class StreamConfigurationView extends LinearLayout {
43 
44     private StreamConfiguration  mRequestedConfiguration;
45     private StreamConfiguration  mActualConfiguration;
46 
47     protected Spinner mNativeApiSpinner;
48     private TextView mActualNativeApiView;
49 
50     private TextView mActualMMapView;
51     private CheckBox mRequestedMMapView;
52     private TextView mActualExclusiveView;
53     private TextView mActualPerformanceView;
54     private Spinner  mPerformanceSpinner;
55     private CheckBox mRequestedExclusiveView;
56     private CheckBox mChannelConversionBox;
57     private CheckBox mFormatConversionBox;
58     private Spinner  mChannelCountSpinner;
59     private TextView mActualChannelCountView;
60     private TextView mActualFormatView;
61 
62     private TextView mActualInputPresetView;
63     private Spinner  mInputPresetSpinner;
64     private TableRow mInputPresetTableRow;
65     private Spinner  mFormatSpinner;
66     private Spinner  mSampleRateSpinner;
67     private Spinner  mRateConversionQualitySpinner;
68     private TextView mActualSampleRateView;
69     private LinearLayout mHideableView;
70 
71     private AudioDeviceSpinner mDeviceSpinner;
72     private TextView mActualSessionIdView;
73     private CheckBox mRequestAudioEffect;
74 
75     private TextView mStreamInfoView;
76     private TextView mStreamStatusView;
77     private TextView mOptionExpander;
78     private String mHideSettingsText;
79     private String mShowSettingsText;
80 
81     // Create an anonymous implementation of OnClickListener
82     private View.OnClickListener mToggleListener = new View.OnClickListener() {
83         public void onClick(View v) {
84             if (mHideableView.isShown()) {
85                 hideSettingsView();
86             } else {
87                 showSettingsView();
88             }
89         }
90     };
91 
yesOrNo(boolean b)92     public static String yesOrNo(boolean b) {
93         return b ?  "YES" : "NO";
94     }
95 
updateSettingsViewText()96     private void updateSettingsViewText() {
97         if (mHideableView.isShown()) {
98             mOptionExpander.setText(mHideSettingsText);
99         } else {
100             mOptionExpander.setText(mShowSettingsText);
101         }
102     }
103 
showSettingsView()104     public void showSettingsView() {
105         mHideableView.setVisibility(View.VISIBLE);
106         updateSettingsViewText();
107     }
108 
hideSampleRateMenu()109     public void hideSampleRateMenu() {
110         if (mSampleRateSpinner != null) {
111             mSampleRateSpinner.setVisibility(View.GONE);
112         }
113     }
114 
hideSettingsView()115     public void hideSettingsView() {
116         mHideableView.setVisibility(View.GONE);
117         updateSettingsViewText();
118     }
119 
StreamConfigurationView(Context context)120     public StreamConfigurationView(Context context) {
121         super(context);
122         initializeViews(context);
123     }
124 
StreamConfigurationView(Context context, AttributeSet attrs)125     public StreamConfigurationView(Context context, AttributeSet attrs) {
126         super(context, attrs);
127         initializeViews(context);
128     }
129 
StreamConfigurationView(Context context, AttributeSet attrs, int defStyle)130     public StreamConfigurationView(Context context,
131                                    AttributeSet attrs,
132                                    int defStyle) {
133         super(context, attrs, defStyle);
134         initializeViews(context);
135     }
136 
137     /**
138      * Inflates the views in the layout.
139      *
140      * @param context
141      *           the current context for the view.
142      */
initializeViews(Context context)143     private void initializeViews(Context context) {
144         LayoutInflater inflater = (LayoutInflater) context
145                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
146         inflater.inflate(R.layout.stream_config, this);
147 
148         mHideSettingsText = getResources().getString(R.string.hint_hide_settings);
149         mShowSettingsText = getResources().getString(R.string.hint_show_settings);
150 
151         mHideableView = (LinearLayout) findViewById(R.id.hideableView);
152 
153         mOptionExpander = (TextView) findViewById(R.id.toggle_stream_config);
154         mOptionExpander.setOnClickListener(mToggleListener);
155 
156         mNativeApiSpinner = (Spinner) findViewById(R.id.spinnerNativeApi);
157         mNativeApiSpinner.setOnItemSelectedListener(new NativeApiSpinnerListener());
158         mNativeApiSpinner.setSelection(StreamConfiguration.NATIVE_API_UNSPECIFIED);
159 
160         mActualNativeApiView = (TextView) findViewById(R.id.actualNativeApi);
161 
162         mChannelConversionBox = (CheckBox) findViewById(R.id.checkChannelConversion);
163         mChannelConversionBox.setOnClickListener(new View.OnClickListener() {
164             @Override
165             public void onClick(View v) {
166                 mRequestedConfiguration.setChannelConversionAllowed(mChannelConversionBox.isChecked());
167             }
168         });
169 
170         mFormatConversionBox = (CheckBox) findViewById(R.id.checkFormatConversion);
171         mFormatConversionBox.setOnClickListener(new View.OnClickListener() {
172             @Override
173             public void onClick(View v) {
174                 mRequestedConfiguration.setFormatConversionAllowed(mFormatConversionBox.isChecked());
175             }
176         });
177 
178         mActualMMapView = (TextView) findViewById(R.id.actualMMap);
179         mRequestedMMapView = (CheckBox) findViewById(R.id.requestedMMapEnable);
180         mRequestedMMapView.setOnClickListener(new View.OnClickListener() {
181             @Override
182             public void onClick(View v) {
183                 mRequestedConfiguration.setMMap(mRequestedMMapView.isChecked());
184             }
185         });
186         boolean mmapSupported = NativeEngine.isMMapSupported();
187         mRequestedMMapView.setEnabled(mmapSupported);
188         mRequestedMMapView.setChecked(mmapSupported);
189 
190         mActualExclusiveView = (TextView) findViewById(R.id.actualExclusiveMode);
191         mRequestedExclusiveView = (CheckBox) findViewById(R.id.requestedExclusiveMode);
192         mRequestedExclusiveView.setOnClickListener(new View.OnClickListener() {
193             @Override
194             public void onClick(View v) {
195                 mRequestedConfiguration.setSharingMode(mRequestedExclusiveView.isChecked()
196                         ? StreamConfiguration.SHARING_MODE_EXCLUSIVE
197                         : StreamConfiguration.SHARING_MODE_SHARED);
198             }
199         });
200 
201         boolean mmapExclusiveSupported = NativeEngine.isMMapExclusiveSupported();
202         mRequestedExclusiveView.setEnabled(mmapExclusiveSupported);
203         mRequestedExclusiveView.setChecked(mmapExclusiveSupported);
204 
205         mActualSessionIdView = (TextView) findViewById(R.id.sessionId);
206         mRequestAudioEffect = (CheckBox) findViewById(R.id.requestAudioEffect);
207         mRequestAudioEffect.setOnClickListener(new View.OnClickListener() {
208             @Override
209             public void onClick(View v) {
210                 mRequestedConfiguration.setSessionId(mRequestAudioEffect.isChecked()
211                         ? StreamConfiguration.SESSION_ID_ALLOCATE
212                         : StreamConfiguration.SESSION_ID_NONE);
213             }
214         });
215 
216         mActualSampleRateView = (TextView) findViewById(R.id.actualSampleRate);
217         mSampleRateSpinner = (Spinner) findViewById(R.id.spinnerSampleRate);
218         mSampleRateSpinner.setOnItemSelectedListener(new SampleRateSpinnerListener());
219 
220         mActualChannelCountView = (TextView) findViewById(R.id.actualChannelCount);
221         mChannelCountSpinner = (Spinner) findViewById(R.id.spinnerChannelCount);
222         mChannelCountSpinner.setOnItemSelectedListener(new ChannelCountSpinnerListener());
223 
224         mActualFormatView = (TextView) findViewById(R.id.actualAudioFormat);
225         mFormatSpinner = (Spinner) findViewById(R.id.spinnerFormat);
226         mFormatSpinner.setOnItemSelectedListener(new FormatSpinnerListener());
227 
228         mRateConversionQualitySpinner = (Spinner) findViewById(R.id.spinnerSRCQuality);
229         mRateConversionQualitySpinner.setOnItemSelectedListener(new RateConversionQualitySpinnerListener());
230 
231         mActualPerformanceView = (TextView) findViewById(R.id.actualPerformanceMode);
232         mPerformanceSpinner = (Spinner) findViewById(R.id.spinnerPerformanceMode);
233         mPerformanceSpinner.setOnItemSelectedListener(new PerformanceModeSpinnerListener());
234         mPerformanceSpinner.setSelection(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY
235                 - StreamConfiguration.PERFORMANCE_MODE_NONE);
236 
237         mInputPresetTableRow = (TableRow) findViewById(R.id.rowInputPreset);
238         mActualInputPresetView = (TextView) findViewById(R.id.actualInputPreset);
239         mInputPresetSpinner = (Spinner) findViewById(R.id.spinnerInputPreset);
240         mInputPresetSpinner.setOnItemSelectedListener(new InputPresetSpinnerListener());
241         mInputPresetSpinner.setSelection(2); // TODO need better way to select voice recording default
242 
243         mStreamInfoView = (TextView) findViewById(R.id.streamInfo);
244 
245         mStreamStatusView = (TextView) findViewById(R.id.statusView);
246 
247         mDeviceSpinner = (AudioDeviceSpinner) findViewById(R.id.devices_spinner);
248         mDeviceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
249             @Override
250             public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
251                 int id =  ((AudioDeviceListEntry) mDeviceSpinner.getSelectedItem()).getId();
252                 mRequestedConfiguration.setDeviceId(id);
253             }
254 
255             @Override
256             public void onNothingSelected(AdapterView<?> adapterView) {
257                 mRequestedConfiguration.setDeviceId(StreamConfiguration.UNSPECIFIED);
258             }
259         });
260 
261         showSettingsView();
262     }
263 
setOutput(boolean output)264     public void setOutput(boolean output) {
265         String ioText;
266         if (output) {
267             mDeviceSpinner.setDirectionType(AudioManager.GET_DEVICES_OUTPUTS);
268             ioText = "OUTPUT";
269         } else {
270             mDeviceSpinner.setDirectionType(AudioManager.GET_DEVICES_INPUTS);
271             ioText = "INPUT";
272         }
273         mHideSettingsText = getResources().getString(R.string.hint_hide_settings) + " - " + ioText;
274         mShowSettingsText = getResources().getString(R.string.hint_show_settings) + " - " + ioText;
275         updateSettingsViewText();
276 
277         // Don't show InputPresets for output streams.
278         mInputPresetTableRow.setVisibility(output ? View.GONE : View.VISIBLE);
279     }
280 
281     private class NativeApiSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
282         @Override
onItemSelected(AdapterView<?> parent, View view, int pos, long id)283         public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
284             mRequestedConfiguration.setNativeApi(pos);
285         }
286 
287         @Override
onNothingSelected(AdapterView<?> parent)288         public void onNothingSelected(AdapterView<?> parent) {
289             mRequestedConfiguration.setNativeApi(StreamConfiguration.NATIVE_API_UNSPECIFIED);
290         }
291     }
292 
293     private class PerformanceModeSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
294         @Override
onItemSelected(AdapterView<?> parent, View view, int performanceMode, long id)295         public void onItemSelected(AdapterView<?> parent, View view, int performanceMode, long id) {
296             mRequestedConfiguration.setPerformanceMode(performanceMode
297                     + StreamConfiguration.PERFORMANCE_MODE_NONE);
298         }
299 
300         @Override
onNothingSelected(AdapterView<?> parent)301         public void onNothingSelected(AdapterView<?> parent) {
302             mRequestedConfiguration.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_NONE);
303         }
304     }
305 
306     private class ChannelCountSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
307         @Override
onItemSelected(AdapterView<?> parent, View view, int pos, long id)308         public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
309             mRequestedConfiguration.setChannelCount(pos);
310         }
311 
312         @Override
onNothingSelected(AdapterView<?> parent)313         public void onNothingSelected(AdapterView<?> parent) {
314             mRequestedConfiguration.setChannelCount(StreamConfiguration.UNSPECIFIED);
315         }
316     }
317 
318     private class SampleRateSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
319         @Override
onItemSelected(AdapterView<?> parent, View view, int pos, long id)320         public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
321             String text = parent.getItemAtPosition(pos).toString();
322             int sampleRate = Integer.parseInt(text);
323             mRequestedConfiguration.setSampleRate(sampleRate);
324         }
325 
326         @Override
onNothingSelected(AdapterView<?> parent)327         public void onNothingSelected(AdapterView<?> parent) {
328             mRequestedConfiguration.setSampleRate(StreamConfiguration.UNSPECIFIED);
329         }
330     }
331 
332     private class FormatSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
333         @Override
onItemSelected(AdapterView<?> parent, View view, int pos, long id)334         public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
335             // Menu position matches actual enum value!
336             mRequestedConfiguration.setFormat(pos);
337         }
338 
339         @Override
onNothingSelected(AdapterView<?> parent)340         public void onNothingSelected(AdapterView<?> parent) {
341             mRequestedConfiguration.setFormat(StreamConfiguration.UNSPECIFIED);
342         }
343     }
344 
345     private class InputPresetSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
346         @Override
onItemSelected(AdapterView<?> parent, View view, int pos, long id)347         public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
348             String text = parent.getItemAtPosition(pos).toString();
349             int inputPreset = StreamConfiguration.convertTextToInputPreset(text);
350             mRequestedConfiguration.setInputPreset(inputPreset);
351         }
352 
353         @Override
onNothingSelected(AdapterView<?> parent)354         public void onNothingSelected(AdapterView<?> parent) {
355             mRequestedConfiguration.setInputPreset(StreamConfiguration.INPUT_PRESET_GENERIC);
356         }
357     }
358 
359     private class RateConversionQualitySpinnerListener
360             implements android.widget.AdapterView.OnItemSelectedListener {
361         @Override
onItemSelected(AdapterView<?> parent, View view, int pos, long id)362         public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
363             // Menu position matches actual enum value!
364             mRequestedConfiguration.setRateConversionQuality(pos);
365         }
366 
367         @Override
onNothingSelected(AdapterView<?> parent)368         public void onNothingSelected(AdapterView<?> parent) {
369             mRequestedConfiguration.setRateConversionQuality(StreamConfiguration.RATE_CONVERSION_QUALITY_HIGH);
370         }
371     }
372 
setChildrenEnabled(boolean enabled)373     public void setChildrenEnabled(boolean enabled) {
374         mNativeApiSpinner.setEnabled(enabled);
375         mPerformanceSpinner.setEnabled(enabled);
376         mRequestedExclusiveView.setEnabled(enabled);
377         mSampleRateSpinner.setEnabled(enabled);
378         mChannelCountSpinner.setEnabled(enabled);
379         mFormatSpinner.setEnabled(enabled);
380         mDeviceSpinner.setEnabled(enabled);
381         mRequestAudioEffect.setEnabled(enabled);
382     }
383 
384     // This must be called on the UI thread.
updateDisplay()385     void updateDisplay() {
386         int value;
387 
388         value = mActualConfiguration.getNativeApi();
389         mActualNativeApiView.setText(StreamConfiguration.convertNativeApiToText(value));
390 
391         mActualMMapView.setText(yesOrNo(mActualConfiguration.isMMap()));
392         int sharingMode = mActualConfiguration.getSharingMode();
393         boolean isExclusive = (sharingMode == StreamConfiguration.SHARING_MODE_EXCLUSIVE);
394         mActualExclusiveView.setText(yesOrNo(isExclusive));
395 
396         value = mActualConfiguration.getPerformanceMode();
397         mActualPerformanceView.setText(StreamConfiguration.convertPerformanceModeToText(value));
398         mActualPerformanceView.requestLayout();
399 
400         value = mActualConfiguration.getFormat();
401         mActualFormatView.setText(StreamConfiguration.convertFormatToText(value));
402         mActualFormatView.requestLayout();
403 
404         value = mActualConfiguration.getInputPreset();
405         mActualInputPresetView.setText(StreamConfiguration.convertInputPresetToText(value));
406         mActualInputPresetView.requestLayout();
407 
408         mActualChannelCountView.setText(mActualConfiguration.getChannelCount() + "");
409         mActualSampleRateView.setText(mActualConfiguration.getSampleRate() + "");
410         mActualSessionIdView.setText("S#: " + mActualConfiguration.getSessionId());
411 
412         boolean isMMap = mActualConfiguration.isMMap();
413         mStreamInfoView.setText("burst = " + mActualConfiguration.getFramesPerBurst()
414                 + ", capacity = " + mActualConfiguration.getBufferCapacityInFrames()
415                 + ", devID = " + mActualConfiguration.getDeviceId()
416                 + ", " + (mActualConfiguration.isMMap() ? "MMAP" : "Legacy")
417                 + (isMMap ? ", " + StreamConfiguration.convertSharingModeToText(sharingMode) : "")
418         );
419 
420         mHideableView.requestLayout();
421     }
422 
423     // This must be called on the UI thread.
setStatusText(String msg)424     public void setStatusText(String msg) {
425         mStreamStatusView.setText(msg);
426     }
427 
getRequestedConfiguration()428     protected StreamConfiguration getRequestedConfiguration() {
429         return mRequestedConfiguration;
430     }
431 
setRequestedConfiguration(StreamConfiguration configuration)432     public void setRequestedConfiguration(StreamConfiguration configuration) {
433         mRequestedConfiguration = configuration;
434         if (configuration != null) {
435             mRateConversionQualitySpinner.setSelection(configuration.getRateConversionQuality());
436             mChannelConversionBox.setChecked(configuration.getChannelConversionAllowed());
437             mFormatConversionBox.setChecked(configuration.getFormatConversionAllowed());
438         }
439     }
440 
getActualConfiguration()441     protected StreamConfiguration getActualConfiguration() {
442         return mActualConfiguration;
443     }
setActualConfiguration(StreamConfiguration configuration)444     public void setActualConfiguration(StreamConfiguration configuration) {
445         mActualConfiguration = configuration;
446     }
447 
setExclusiveMode(boolean b)448     public void setExclusiveMode(boolean b) {
449         mRequestedExclusiveView.setChecked(b);
450         mRequestedConfiguration.setSharingMode(b
451                 ? StreamConfiguration.SHARING_MODE_EXCLUSIVE
452                 : StreamConfiguration.SHARING_MODE_SHARED);
453     }
454 
setFormat(int format)455     public void setFormat(int format) {
456         mFormatSpinner.setSelection(format); // position matches format
457         mRequestedConfiguration.setFormat(format);
458     }
459 
setFormatConversionAllowed(boolean allowed)460     public void setFormatConversionAllowed(boolean allowed) {
461         mFormatConversionBox.setChecked(allowed);
462         mRequestedConfiguration.setFormatConversionAllowed(allowed);
463     }
464 }
465