diff options
author | Ricardo Garcia <rago@google.com> | 2015-04-08 18:59:29 -0700 |
---|---|---|
committer | Ricardo Garcia <rago@google.com> | 2015-04-08 18:59:29 -0700 |
commit | 698bcf06af8a983bf47b3a6bc1682690fe6db13c (patch) | |
tree | 7281a4793eb17e655b83b479297a10cfc08b98e7 /LoopbackApp/app/src/main/java/org | |
parent | 49721ce2ad40c9c4fecff30e755d5b09e415b4a1 (diff) | |
download | drrickorang-698bcf06af8a983bf47b3a6bc1682690fe6db13c.tar.gz |
New microphone selection capabilities.
Now it is possible to select the microphone source.
Some notification/error management refactoring.
Adding microphone source to the name of the wavefile.
Diffstat (limited to 'LoopbackApp/app/src/main/java/org')
5 files changed, 223 insertions, 67 deletions
diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java index 2ecc2e2..eac59e4 100644 --- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java +++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java @@ -80,6 +80,12 @@ public class LoopbackActivity extends Activity { showToast("Java Recording Started"); refreshState(); break; + case LoopbackAudioThread.FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_ERROR: + log("got message java rec can't start!!"); + showToast("Java Recording Error. Please try again"); + refreshState(); + stopAudioThread(); + break; case LoopbackAudioThread.FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_COMPLETE: if(audioThread != null) { mWaveData = audioThread.getWaveData(); @@ -243,22 +249,25 @@ public class LoopbackActivity extends Activity { int samplingRate = getApp().getSamplingRate(); int playbackBuffer = getApp().getPlayBufferSizeInBytes(); int recordBuffer = getApp().getRecordBufferSizeInBytes(); + int micSource = getApp().getMicSource(); log(" current sampling rate: " + samplingRate); stopAudioThread(); //select if java or native audio thread if (getApp().getAudioThreadType() == LoopbackApplication.AUDIO_THREAD_TYPE_JAVA ) { + int micSourceMapped = getApp().mapMicSource(LoopbackApplication.AUDIO_THREAD_TYPE_JAVA ,micSource); audioThread = new LoopbackAudioThread(); audioThread.setMessageHandler(mMessageHandler); audioThread.mSessionId = sessionId; - audioThread.setParams(samplingRate, playbackBuffer, recordBuffer); + audioThread.setParams(samplingRate, playbackBuffer, recordBuffer,micSourceMapped); audioThread.start(); } else { + int micSourceMapped = getApp().mapMicSource(LoopbackApplication.AUDIO_THREAD_TYPE_NATIVE ,micSource); nativeAudioThread = new NativeAudioThread(); nativeAudioThread.setMessageHandler(mMessageHandler); nativeAudioThread.mSessionId = sessionId; - nativeAudioThread.setParams(samplingRate, playbackBuffer, recordBuffer); + nativeAudioThread.setParams(samplingRate, playbackBuffer, recordBuffer,micSourceMapped); nativeAudioThread.start(); } mWavePlotView.setSamplingRate( samplingRate); @@ -302,7 +311,13 @@ public class LoopbackActivity extends Activity { //create filename with date String date = (String) DateFormat.format("yyyy_MM_dd_kk_mm", System.currentTimeMillis()); - String fileName = "loopback_"+date+".wav"; + String micSource = getApp().getMicSourceString( getApp().getMicSource()); + String fileName = "loopback_"+micSource+"_"+date+".wav"; + + //MIC + //VERSION? + //hardware? + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // browser. @@ -433,7 +448,14 @@ public class LoopbackActivity extends Activity { s.append(" Audio: NATIVE"); break; } - mTextInfo.setText(s.toString()); + + //mic source + int micSource = getApp().getMicSource(); + String micSourceName = getApp().getMicSourceString(micSource); + if(micSourceName != null) { + s.append(String.format(" Mic: %s", micSourceName)); + mTextInfo.setText(s.toString()); + } } private static void log(String msg) { diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackApplication.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackApplication.java index 736e64a..6af44a6 100644 --- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackApplication.java +++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackApplication.java @@ -23,6 +23,7 @@ import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.AudioTrack; +import android.media.MediaRecorder; import android.os.Build; public class LoopbackApplication extends Application { @@ -31,6 +32,7 @@ public class LoopbackApplication extends Application { private int mPlayBufferSizeInBytes = 0; private int mRecordBuffSizeInBytes = 0; private int mAudioThreadType = 0; //0:Java, 1:Native (JNI) + private int mMicSource = 3; //maps to MediaRecorder.AudioSource.VOICE_RECOGNITION; public static final int AUDIO_THREAD_TYPE_JAVA = 0; public static final int AUDIO_THREAD_TYPE_NATIVE = 1; @@ -64,6 +66,74 @@ public class LoopbackApplication extends Application { mAudioThreadType = audioThreadType; } + int getMicSource() { return mMicSource; } + int mapMicSource(int threadType, int source) { + int mappedSource = 0; +// <item>DEFAULT</item> +// <item>MIC</item> +// <item>CAMCORDER</item> +// <item>VOICE_RECOGNITION</item> +// <item>VOICE_COMMUNICATION</item> + + if(threadType == AUDIO_THREAD_TYPE_JAVA) { + + switch (source) { + default: + case 0: //DEFAULT + mappedSource = MediaRecorder.AudioSource.DEFAULT; + break; + case 1: //MIC + mappedSource = MediaRecorder.AudioSource.MIC; + break; + case 2: //CAMCORDER + mappedSource = MediaRecorder.AudioSource.CAMCORDER; + break; + case 3: //VOICE_RECOGNITION + mappedSource = MediaRecorder.AudioSource.VOICE_RECOGNITION; + break; + case 4: //VOICE_COMMUNICATION + mappedSource = MediaRecorder.AudioSource.VOICE_COMMUNICATION; + break; + } + } else if (threadType == AUDIO_THREAD_TYPE_NATIVE ) { + + //taken form OpenSLES_AndroidConfiguration.h + switch (source) { + default: + case 0: //DEFAULT + mappedSource = 0x00; //SL_ANDROID_RECORDING_PRESET_NONE + break; + case 1: //MIC + mappedSource = 0x01; //SL_ANDROID_RECORDING_PRESET_GENERIC + break; + case 2: //CAMCORDER + mappedSource = 0x02; //SL_ANDROID_RECORDING_PRESET_CAMCORDER + break; + case 3: //VOICE_RECOGNITION + mappedSource = 0x03; //SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION + break; + case 4: //VOICE_COMMUNICATION + mappedSource = 0x04; //SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION + break; + } + } + + return mappedSource; + } + + String getMicSourceString(int source) { + + String name = null; + + String[] myArray = getResources().getStringArray(R.array.mic_source_array); + if(myArray != null && source>=0 && source < myArray.length) { + name = myArray[source]; + } + return name; + } + + void setMicSource(int micSource) { mMicSource = micSource; } + int getPlayBufferSizeInBytes() { return mPlayBufferSizeInBytes; } diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java index ae2c0ca..e7ed9c2 100644 --- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java +++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java @@ -35,6 +35,7 @@ import android.os.Message; public class LoopbackAudioThread extends Thread { public boolean isRunning = false; + // private boolean isInitialized = false; double twoPi = 6.28318530718; public AudioTrack mAudioTrack; @@ -59,6 +60,7 @@ public class LoopbackAudioThread extends Thread { private short[] mAudioShortArrayOut; int mMinPlayBufferSizeSamples = 0; int mMinRecordBufferSizeSamples = 0; + int mMicSource = 0; boolean isPlaying = false; private Handler mMessageHandler; @@ -68,11 +70,12 @@ public class LoopbackAudioThread extends Thread { static final int FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_COMPLETE = 994; static final int FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERROR = 995; - public void setParams(int samplingRate, int playBufferInBytes, int recBufferInBytes) { + public void setParams(int samplingRate, int playBufferInBytes, int recBufferInBytes, int micSource) { mSamplingRate = samplingRate; mMinPlayBufferSizeInBytes = playBufferInBytes; mMinRecordBuffSizeInBytes = recBufferInBytes; + mMicSource = micSource; } @@ -96,7 +99,7 @@ public class LoopbackAudioThread extends Thread { mAudioShortArrayOut = new short[mMinPlayBufferSizeSamples]; recorderRunnable = new RecorderRunnable(mPipe, mSamplingRate, mChannelConfigIn, - mAudioFormat, mMinRecordBuffSizeInBytes); + mAudioFormat, mMinRecordBuffSizeInBytes, mMicSource); mRecorderThread = new Thread(recorderRunnable); mRecorderThread.start(); @@ -114,58 +117,66 @@ public class LoopbackAudioThread extends Thread { double fr = 440.0f; double phase = 0.0; - isPlaying = false; - isRunning = true; + if(recorderRunnable != null && mAudioTrack != null) { - while (isRunning) { - if (isPlaying) - { - //using PIPE - // int bytesAvailable = mPipe.availableToRead(); - int samplesAvailable = mPipe.availableToRead(); + + isPlaying = false; + isRunning = true; + + while (isRunning) { + if (isPlaying) { + //using PIPE + // int bytesAvailable = mPipe.availableToRead(); + int samplesAvailable = mPipe.availableToRead(); // if (bytesAvailable>0 ) { - if (samplesAvailable>0) { + if (samplesAvailable > 0) { // int bytesOfInterest = bytesAvailable; - int samplesOfInterest = samplesAvailable; + int samplesOfInterest = samplesAvailable; // if ( mMinPlayBufferSizeInBytes < bytesOfInterest ) // bytesOfInterest = mMinPlayBufferSizeInBytes; // - if (mMinPlayBufferSizeSamples < samplesOfInterest) - samplesOfInterest = mMinPlayBufferSizeSamples; + if (mMinPlayBufferSizeSamples < samplesOfInterest) + samplesOfInterest = mMinPlayBufferSizeSamples; // mPipe.read( mAudioByteArrayOut, 0 , bytesOfInterest); - int samplesRead = mPipe.read( mAudioShortArrayOut, 0, samplesOfInterest); + int samplesRead = mPipe.read(mAudioShortArrayOut, 0, samplesOfInterest); // int bytesAvailableAfter = mPipe.availableToRead(); // int samplesAvailableAfter = mPipe.availableToRead(); - //output + //output // mAudioTrack.write(mAudioByteArrayOut, 0, bytesOfInterest); - mAudioTrack.write(mAudioShortArrayOut, 0, samplesRead); + mAudioTrack.write(mAudioShortArrayOut, 0, samplesRead); - if ( !recorderRunnable.isStillRoomToRecord()) { - //stop - endTest(); + if (!recorderRunnable.isStillRoomToRecord()) { + //stop + endTest(); + } } - } - } - else - { - if (isRunning) - { - try { - sleep(1); - } catch (InterruptedException e) { - e.printStackTrace(); + } else { + if (isRunning) { + try { + sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } } - } + } + } //end is running + } else { + //something went wrong, didn't run + log("Loopback Audio Thread couldn't run!"); + if (mMessageHandler != null) { + Message msg = Message.obtain(); + msg.what = FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_ERROR; + mMessageHandler.sendMessage(msg); } - } //end is running + } } public void setMessageHandler(Handler messageHandler) { @@ -178,33 +189,36 @@ public class LoopbackAudioThread extends Thread { public void runTest() { - // start test - if (mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING ) - { - log("...run test, but still playing..."); - endTest(); - } - else - { - //erase output buffer - if (mvSamples != null) - mvSamples = null; + if(isRunning) { + // start test + if (mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) { + log("...run test, but still playing..."); + endTest(); + } else { + //erase output buffer + if (mvSamples != null) + mvSamples = null; - //resize - int nNewSize = mSamplingRate * 2; //5 seconds! - mvSamples = new double[nNewSize]; - mSamplesIndex = 0; //reset index + //resize + int nNewSize = mSamplingRate * 2; //5 seconds! + mvSamples = new double[nNewSize]; + mSamplesIndex = 0; //reset index - //start playing - isPlaying = true; - mAudioTrack.play(); - recorderRunnable.startRecording(mvSamples); + //start playing + isPlaying = true; + mAudioTrack.play(); + boolean status = recorderRunnable.startRecording(mvSamples); - log(" Started capture test"); - if (mMessageHandler != null) { - Message msg = Message.obtain(); - msg.what = FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_STARTED; - mMessageHandler.sendMessage(msg); + log(" Started capture test"); + if (mMessageHandler != null) { + Message msg = Message.obtain(); + msg.what = FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_STARTED; + + if(!status) + msg.what = FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_ERROR; + + mMessageHandler.sendMessage(msg); + } } } } @@ -277,6 +291,8 @@ public class LoopbackAudioThread extends Thread { private AudioRecord mRecorder; + + private int mSelectedRecordSource = MediaRecorder.AudioSource.MIC; public int mSamplingRate = 48000; private int mChannelConfig = AudioFormat.CHANNEL_IN_MONO; @@ -294,13 +310,14 @@ public class LoopbackAudioThread extends Thread { int mSamplesIndex; RecorderRunnable(PipeShort pipe, int samplingRate, int channelConfig, int audioFormat, - int recBufferInBytes) + int recBufferInBytes, int micSource) { mPipe = pipe; mSamplingRate = samplingRate; mChannelConfig = channelConfig; mAudioFormat = audioFormat; mMinRecordBuffSizeInBytes = recBufferInBytes; + mSelectedRecordSource = micSource; } //init the recording device @@ -331,6 +348,7 @@ public class LoopbackAudioThread extends Thread { mRecorder = new AudioRecord(mSelectedRecordSource, mSamplingRate, mChannelConfig, mAudioFormat, 2 * mMinRecordBuffSizeInBytes); } catch (IllegalArgumentException e) { + e.printStackTrace(); return false; } if (mRecorder.getState() != AudioRecord.STATE_INITIALIZED) { @@ -345,7 +363,7 @@ public class LoopbackAudioThread extends Thread { return true; } - void startRecording(double vCapture[]) { + boolean startRecording(double vCapture[]) { synchronized (sRecordingLock) { mIsRecording = true; } @@ -353,8 +371,8 @@ public class LoopbackAudioThread extends Thread { mvSamples = vCapture; mSamplesIndex = 0; - boolean successful = initRecord(); - if (successful) { + boolean status = initRecord(); + if (status) { log("Ready to go."); startRecordingForReal(); } else { @@ -363,6 +381,8 @@ public class LoopbackAudioThread extends Thread { mIsRecording = false; } } + + return status; } void startRecordingForReal() { diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java index f8760a3..da6610f 100644 --- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java +++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java @@ -51,6 +51,8 @@ public class NativeAudioThread extends Thread { int mMinRecordBuffSizeInBytes = 0; private int mChannelConfigOut = AudioFormat.CHANNEL_OUT_MONO; + int mMicSource = 0; + // private double [] samples = new double[50000]; boolean isPlaying = false; @@ -63,12 +65,14 @@ public class NativeAudioThread extends Thread { static final int FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE = 894; static final int FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS = 895; - public void setParams(int samplingRate, int playBufferInBytes, int recBufferInBytes) { + public void setParams(int samplingRate, int playBufferInBytes, int recBufferInBytes, int micSource) { mSamplingRate = samplingRate; mMinPlayBufferSizeInBytes = playBufferInBytes; mMinRecordBuffSizeInBytes = recBufferInBytes; + mMicSource = micSource; + } //JNI load @@ -84,7 +88,7 @@ public class NativeAudioThread extends Thread { } //jni calls - public native long slesInit(int samplingRate, int frameCount); + public native long slesInit(int samplingRate, int frameCount, int micSource); public native int slesProcessNext(long sles_data, double[] samples, long offset); public native int slesDestroy(long sles_data); @@ -122,7 +126,7 @@ public class NativeAudioThread extends Thread { log(String.format("about to init, sampling rate: %d, buffer:%d", mSamplingRate, mMinPlayBufferSizeInBytes/2 )); - long sles_data = slesInit(mSamplingRate, mMinPlayBufferSizeInBytes/2); + long sles_data = slesInit(mSamplingRate, mMinPlayBufferSizeInBytes/2, mMicSource); log(String.format("sles_data = 0x%X",sles_data)); if(sles_data == 0 ) { diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SettingsActivity.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SettingsActivity.java index 06d5299..f27361c 100644 --- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SettingsActivity.java +++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SettingsActivity.java @@ -19,6 +19,7 @@ package org.drrickorang.loopback; import android.app.Activity; import android.content.Intent; import android.content.Context; +import android.content.pm.PackageManager; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; @@ -34,17 +35,21 @@ import android.widget.AdapterView.OnItemSelectedListener; import android.widget.AdapterView; import android.widget.NumberPicker; import android.widget.NumberPicker.OnValueChangeListener; +import android.widget.TextView; public class SettingsActivity extends Activity implements OnItemSelectedListener, OnValueChangeListener { /** * Called with the activity is first created. */ + Spinner mSpinnerMicSource; Spinner mSpinnerSamplingRate; Spinner mSpinnerAudioThreadType; NumberPicker mNumberPickerPlaybackBuffer; NumberPicker mNumberPickerRecordBuffer; + TextView mTextSettingsInfo; + ArrayAdapter<CharSequence> adapterSamplingRate; int bytesPerFrame; @@ -55,6 +60,25 @@ OnValueChangeListener { View view = getLayoutInflater().inflate(R.layout.settings_activity, null); setContentView(view); + + mTextSettingsInfo = (TextView) findViewById(R.id.textSettingsInfo); + + + int micSource = getApp().getMicSource(); + mSpinnerMicSource = (Spinner) findViewById(R.id.spinnerMicSource); + ArrayAdapter<CharSequence> adapterMicSource = ArrayAdapter.createFromResource(this, + R.array.mic_source_array, android.R.layout.simple_spinner_item); + // Specify the layout to use when the list of choices appears + adapterMicSource.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + // Apply the adapter to the spinner + mSpinnerMicSource.setAdapter(adapterMicSource); + //set current value +// String currentValue = String.valueOf(samplingRate); +// int nPosition = adapter.getPosition(currentValue); + mSpinnerMicSource.setSelection(micSource, false); + mSpinnerMicSource.setOnItemSelectedListener(this); + + bytesPerFrame = getApp().BYTES_PER_FRAME; int samplingRate = getApp().getSamplingRate(); //init spinner, etc @@ -135,6 +159,15 @@ OnValueChangeListener { String currentValue = String.valueOf(samplingRate); int nPosition = adapterSamplingRate.getPosition(currentValue); mSpinnerSamplingRate.setSelection(nPosition); + + + try { + int versionCode = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0).versionCode; + String versionName = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0).versionName; + mTextSettingsInfo.setText("SETTINGS - Ver. " +versionCode +"."+ versionName + " | " +Build.MODEL + " | " + Build.FINGERPRINT); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } } public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { @@ -157,6 +190,13 @@ OnValueChangeListener { log("AudioThreadType:" + audioThreadType); refresh(); break; + case R.id.spinnerMicSource: + int micSource = mSpinnerMicSource.getSelectedItemPosition(); + getApp().setMicSource(micSource); + settingsChanged(); + log("mic Source:" + micSource); + refresh(); + break; } } |