1 /* 2 * Copyright 2018 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.oboe.samples.liveEffect; 18 19 import android.Manifest; 20 import android.app.Activity; 21 import android.content.pm.PackageManager; 22 import android.media.AudioManager; 23 import android.os.Build; 24 import android.os.Bundle; 25 import androidx.annotation.NonNull; 26 import androidx.core.app.ActivityCompat; 27 import android.util.Log; 28 import android.view.View; 29 import android.widget.AdapterView; 30 import android.widget.Button; 31 import android.widget.RadioButton; 32 import android.widget.RadioGroup; 33 import android.widget.TextView; 34 import android.widget.Toast; 35 36 import com.google.oboe.samples.audio_device.AudioDeviceListEntry; 37 import com.google.oboe.samples.audio_device.AudioDeviceSpinner; 38 39 /** 40 * TODO: Update README.md and go through and comment sample 41 */ 42 public class MainActivity extends Activity 43 implements ActivityCompat.OnRequestPermissionsResultCallback { 44 45 private static final String TAG = MainActivity.class.getName(); 46 private static final int AUDIO_EFFECT_REQUEST = 0; 47 private static final int OBOE_API_AAUDIO = 0; 48 private static final int OBOE_API_OPENSL_ES=1; 49 50 private TextView statusText; 51 private Button toggleEffectButton; 52 private AudioDeviceSpinner recordingDeviceSpinner; 53 private AudioDeviceSpinner playbackDeviceSpinner; 54 private boolean isPlaying = false; 55 56 private int apiSelection = OBOE_API_AAUDIO; 57 private boolean mAAudioRecommended = true; 58 59 @Override onCreate(Bundle savedInstanceState)60 protected void onCreate(Bundle savedInstanceState) { 61 super.onCreate(savedInstanceState); 62 setContentView(R.layout.activity_main); 63 64 statusText = findViewById(R.id.status_view_text); 65 toggleEffectButton = findViewById(R.id.button_toggle_effect); 66 toggleEffectButton.setOnClickListener(new View.OnClickListener() { 67 @Override 68 public void onClick(View view) { 69 toggleEffect(); 70 } 71 }); 72 toggleEffectButton.setText(getString(R.string.start_effect)); 73 74 recordingDeviceSpinner = findViewById(R.id.recording_devices_spinner); 75 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 76 recordingDeviceSpinner.setDirectionType(AudioManager.GET_DEVICES_INPUTS); 77 recordingDeviceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 78 @Override 79 public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 80 LiveEffectEngine.setRecordingDeviceId(getRecordingDeviceId()); 81 } 82 83 @Override 84 public void onNothingSelected(AdapterView<?> adapterView) { 85 // Do nothing 86 } 87 }); 88 } 89 90 playbackDeviceSpinner = findViewById(R.id.playback_devices_spinner); 91 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 92 playbackDeviceSpinner.setDirectionType(AudioManager.GET_DEVICES_OUTPUTS); 93 playbackDeviceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 94 @Override 95 public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 96 LiveEffectEngine.setPlaybackDeviceId(getPlaybackDeviceId()); 97 } 98 99 @Override 100 public void onNothingSelected(AdapterView<?> adapterView) { 101 // Do nothing 102 } 103 }); 104 } 105 106 ((RadioGroup)findViewById(R.id.apiSelectionGroup)).check(R.id.aaudioButton); 107 findViewById(R.id.aaudioButton).setOnClickListener(new RadioButton.OnClickListener(){ 108 @Override 109 public void onClick(View v) { 110 if (((RadioButton)v).isChecked()) { 111 apiSelection = OBOE_API_AAUDIO; 112 setSpinnersEnabled(true); 113 } 114 } 115 }); 116 findViewById(R.id.slesButton).setOnClickListener(new RadioButton.OnClickListener(){ 117 @Override 118 public void onClick(View v) { 119 if (((RadioButton)v).isChecked()) { 120 apiSelection = OBOE_API_OPENSL_ES; 121 setSpinnersEnabled(false); 122 } 123 } 124 }); 125 126 LiveEffectEngine.setDefaultStreamValues(this); 127 } 128 EnableAudioApiUI(boolean enable)129 private void EnableAudioApiUI(boolean enable) { 130 if(apiSelection == OBOE_API_AAUDIO && !mAAudioRecommended) 131 { 132 apiSelection = OBOE_API_OPENSL_ES; 133 } 134 findViewById(R.id.slesButton).setEnabled(enable); 135 if(!mAAudioRecommended) { 136 findViewById(R.id.aaudioButton).setEnabled(false); 137 } else { 138 findViewById(R.id.aaudioButton).setEnabled(enable); 139 } 140 141 ((RadioGroup)findViewById(R.id.apiSelectionGroup)) 142 .check(apiSelection == OBOE_API_AAUDIO ? R.id.aaudioButton : R.id.slesButton); 143 setSpinnersEnabled(enable); 144 } 145 146 @Override onStart()147 protected void onStart() { 148 super.onStart(); 149 setVolumeControlStream(AudioManager.STREAM_MUSIC); 150 } 151 152 @Override onResume()153 protected void onResume() { 154 super.onResume(); 155 LiveEffectEngine.create(); 156 mAAudioRecommended = LiveEffectEngine.isAAudioRecommended(); 157 EnableAudioApiUI(true); 158 LiveEffectEngine.setAPI(apiSelection); 159 } 160 @Override onPause()161 protected void onPause() { 162 stopEffect(); 163 LiveEffectEngine.delete(); 164 super.onPause(); 165 } 166 toggleEffect()167 public void toggleEffect() { 168 if (isPlaying) { 169 stopEffect(); 170 } else { 171 LiveEffectEngine.setAPI(apiSelection); 172 startEffect(); 173 } 174 } 175 startEffect()176 private void startEffect() { 177 Log.d(TAG, "Attempting to start"); 178 179 if (!isRecordPermissionGranted()){ 180 requestRecordPermission(); 181 return; 182 } 183 184 boolean success = LiveEffectEngine.setEffectOn(true); 185 if (success) { 186 statusText.setText(R.string.status_playing); 187 toggleEffectButton.setText(R.string.stop_effect); 188 isPlaying = true; 189 EnableAudioApiUI(false); 190 } else { 191 statusText.setText(R.string.status_open_failed); 192 isPlaying = false; 193 } 194 } 195 stopEffect()196 private void stopEffect() { 197 Log.d(TAG, "Playing, attempting to stop"); 198 LiveEffectEngine.setEffectOn(false); 199 resetStatusView(); 200 toggleEffectButton.setText(R.string.start_effect); 201 isPlaying = false; 202 EnableAudioApiUI(true); 203 } 204 setSpinnersEnabled(boolean isEnabled)205 private void setSpinnersEnabled(boolean isEnabled){ 206 if (((RadioButton)findViewById(R.id.slesButton)).isChecked()) 207 { 208 isEnabled = false; 209 playbackDeviceSpinner.setSelection(0); 210 recordingDeviceSpinner.setSelection(0); 211 } 212 recordingDeviceSpinner.setEnabled(isEnabled); 213 playbackDeviceSpinner.setEnabled(isEnabled); 214 } 215 getRecordingDeviceId()216 private int getRecordingDeviceId(){ 217 return ((AudioDeviceListEntry)recordingDeviceSpinner.getSelectedItem()).getId(); 218 } 219 getPlaybackDeviceId()220 private int getPlaybackDeviceId(){ 221 return ((AudioDeviceListEntry)playbackDeviceSpinner.getSelectedItem()).getId(); 222 } 223 isRecordPermissionGranted()224 private boolean isRecordPermissionGranted() { 225 return (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == 226 PackageManager.PERMISSION_GRANTED); 227 } 228 requestRecordPermission()229 private void requestRecordPermission(){ 230 ActivityCompat.requestPermissions( 231 this, 232 new String[]{Manifest.permission.RECORD_AUDIO}, 233 AUDIO_EFFECT_REQUEST); 234 } 235 resetStatusView()236 private void resetStatusView() { 237 statusText.setText(R.string.status_warning); 238 } 239 240 @Override onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)241 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 242 @NonNull int[] grantResults) { 243 244 if (AUDIO_EFFECT_REQUEST != requestCode) { 245 super.onRequestPermissionsResult(requestCode, permissions, grantResults); 246 return; 247 } 248 249 if (grantResults.length != 1 || 250 grantResults[0] != PackageManager.PERMISSION_GRANTED) { 251 252 // User denied the permission, without this we cannot record audio 253 // Show a toast and update the status accordingly 254 statusText.setText(R.string.status_record_audio_denied); 255 Toast.makeText(getApplicationContext(), 256 getString(R.string.need_record_audio_permission), 257 Toast.LENGTH_SHORT) 258 .show(); 259 } else { 260 // Permission was granted, start live effect 261 toggleEffect(); 262 } 263 } 264 } 265