Skip to content

Commit

Permalink
Merge pull request #2 from ragomusic/master
Browse files Browse the repository at this point in the history
Improvement on life management of Java and Native audio threads
  • Loading branch information
gkasten committed Mar 26, 2015
2 parents 1b84ecf + 6c27b11 commit 9fa073a
Show file tree
Hide file tree
Showing 12 changed files with 551 additions and 169 deletions.
3 changes: 3 additions & 0 deletions LoopbackApp/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion LoopbackApp/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := samples

# Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES := $(call all-java-files-under, app/src/main/java)

LOCAL_SHARED_LIBRARIES := libloopback
LOCAL_JNI_SHARED_LIBRARIES := libloopback
Expand All @@ -18,6 +18,7 @@ LOCAL_SDK_VERSION := 21
include $(BUILD_PACKAGE)

# Use the following include to make our test apk.
include $(call all-makefiles-under, app/src/main/jni)
include $(call all-makefiles-under,$(LOCAL_PATH))


2 changes: 1 addition & 1 deletion LoopbackApp/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ android {

defaultConfig {
applicationId "org.drrickorang.loopback"
minSdkVersion 8
minSdkVersion 11
targetSdkVersion 21

ndk {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import android.os.Bundle;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
Expand All @@ -59,50 +60,62 @@ public class LoopbackActivity extends Activity {

private static final int SAVE_TO_WAVE_REQUEST = 42;
private static final int SETTINGS_ACTIVITY_REQUEST_CODE = 44;
LoopbackAudioThread audioThread;
NativeAudioThread nativeAudioThread;
LoopbackAudioThread audioThread = null;
NativeAudioThread nativeAudioThread = null;
private WavePlotView mWavePlotView;

SeekBar mBarMasterLevel;
TextView mTextInfo;
private double [] mWaveData;
int mSamplingRate;

Toast toast;

private Handler mMessageHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what) {
case LoopbackAudioThread.FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_STARTED:
log("got message java rec complete!!");
Toast.makeText(getApplicationContext(), "Java Recording Started",
Toast.LENGTH_SHORT).show();
log("got message java rec started!!");
showToast("Java Recording Started");
// Toast.makeText(getApplicationContext(), "Java Recording Started",
// Toast.LENGTH_SHORT).show();
refreshState();
break;
case LoopbackAudioThread.FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_COMPLETE:
mWaveData = audioThread.getWaveData();
mSamplingRate = audioThread.mSamplingRate;
log("got message java rec complete!!");
refreshPlots();
refreshState();
Toast.makeText(getApplicationContext(), "Java Recording Completed",
Toast.LENGTH_SHORT).show();
stopAudioThread();
if(audioThread != null) {
mWaveData = audioThread.getWaveData();
mSamplingRate = audioThread.mSamplingRate;
log("got message java rec complete!!");
refreshPlots();
refreshState();
showToast("Java Recording Completed");
// Toast.makeText(getApplicationContext(), "Java Recording Completed",
// Toast.LENGTH_SHORT).show();
stopAudioThread();
}
break;
case NativeAudioThread.FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED:
log("got message native rec complete!!");
Toast.makeText(getApplicationContext(), "Native Recording Started",
Toast.LENGTH_SHORT).show();
log("got message native rec started!!");
showToast("Native Recording Started");
// Toast.makeText(getApplicationContext(), "Native Recording Started",
// Toast.LENGTH_SHORT).show();
refreshState();
break;
case NativeAudioThread.FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE:
mWaveData = nativeAudioThread.getWaveData();
mSamplingRate = nativeAudioThread.mSamplingRate;
log("got message native rec complete!!");
refreshPlots();
refreshState();
Toast.makeText(getApplicationContext(), "Native Recording Completed",
Toast.LENGTH_SHORT).show();
stopAudioThread();
case NativeAudioThread.FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS:
if(nativeAudioThread != null) {
mWaveData = nativeAudioThread.getWaveData();
mSamplingRate = nativeAudioThread.mSamplingRate;
log("got message native rec complete!!");
refreshPlots();
refreshState();
if(msg.what == NativeAudioThread.FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS)
showToast("Native Recording Completed with ERRORS");
else
showToast("Native Recording Completed");
stopAudioThread();
}
break;
default:
log("Got message:"+msg.what);
Expand Down Expand Up @@ -179,6 +192,7 @@ private void stopAudioThread() {
}
nativeAudioThread = null;
}
System.gc();
}

public void onDestroy() {
Expand All @@ -203,6 +217,23 @@ protected void onPause () {
stopAudioThread();
}

public boolean isBusy() {

boolean busy = false;

if( audioThread != null) {
if(audioThread.isRunning)
busy = true;
}

if( nativeAudioThread != null) {
if(nativeAudioThread.isRunning)
busy = true;
}

return busy;
}

private void restartAudioSystem() {

log("restart audio system...");
Expand Down Expand Up @@ -240,22 +271,31 @@ private void restartAudioSystem() {

/** Called when the user clicks the button */
public void onButtonTest(View view) {
restartAudioSystem();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (getApp().getAudioThreadType() == LoopbackApplication.AUDIO_THREAD_TYPE_JAVA ) {
if (audioThread != null) {
audioThread.runTest();

if( !isBusy()) {
restartAudioSystem();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else {
if (nativeAudioThread != null) {
nativeAudioThread.runTest();
if (getApp().getAudioThreadType() == LoopbackApplication.AUDIO_THREAD_TYPE_JAVA) {
if (audioThread != null) {
audioThread.runTest();
}
} else {
if (nativeAudioThread != null) {
nativeAudioThread.runTest();
}
}
} else {
//please wait, or restart application.
// Toast.makeText(getApplicationContext(), "Test in progress... please wait",
// Toast.LENGTH_SHORT).show();

showToast("Test in progress... please wait");
}

}

/** Called when the user clicks the button */
Expand All @@ -275,8 +315,10 @@ public void onButtonSave(View view) {
startActivityForResult(intent, SAVE_TO_WAVE_REQUEST);
}
else {
Toast.makeText(getApplicationContext(), "Saving Wave to: "+fileName,
Toast.LENGTH_SHORT).show();

showToast("Saving Wave to: "+fileName);
// Toast.makeText(getApplicationContext(), "Saving Wave to: "+fileName,
// Toast.LENGTH_SHORT).show();

//save to a given uri... local file?
Uri uri = Uri.parse("file://mnt/sdcard/"+fileName);
Expand All @@ -299,6 +341,7 @@ public void onActivityResult(int requestCode, int resultCode,
resultCode == Activity.RESULT_OK) {
//new settings!
log("return from settings!");
refreshState();
}
}

Expand Down Expand Up @@ -342,9 +385,16 @@ public void onButtonZoomInFull(View view) {

/** Called when the user clicks the button */
public void onButtonSettings(View view) {
Intent mySettingsIntent = new Intent (this, SettingsActivity.class);
//send settings
startActivityForResult(mySettingsIntent, SETTINGS_ACTIVITY_REQUEST_CODE);

if(!isBusy()) {
Intent mySettingsIntent = new Intent(this, SettingsActivity.class);
//send settings
startActivityForResult(mySettingsIntent, SETTINGS_ACTIVITY_REQUEST_CODE);
} else {
showToast("Test in progress... please wait");
// Toast.makeText(getApplicationContext(), "Test in progress... please wait",
// Toast.LENGTH_SHORT).show();
}
}

void refreshPlots() {
Expand Down Expand Up @@ -391,6 +441,24 @@ private static void log(String msg) {
Log.v("Recorder", msg);
}

public void showToast(String msg) {

if(toast == null) {
toast = Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT);
} else {
toast.setText(msg);

}



{
// toast.setText(msg);
toast.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 10, 10);
toast.show();
}
}

private LoopbackApplication getApp() {
return (LoopbackApplication) this.getApplication();
}
Expand All @@ -404,11 +472,13 @@ void saveToWavefile(Uri uri) {
boolean status = audioFileOutput.writeData(mWaveData);

if (status) {
Toast.makeText(getApplicationContext(), "Finished exporting wave File",
Toast.LENGTH_SHORT).show();
showToast("Finished exporting wave File");
// Toast.makeText(getApplicationContext(), "Finished exporting wave File",
// Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Something failed saving wave file",
Toast.LENGTH_SHORT).show();
showToast("Something failed saving wave file");
// Toast.makeText(getApplicationContext(), "Something failed saving wave file",
// Toast.LENGTH_SHORT).show();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,37 @@ public class LoopbackApplication extends Application {
public static final int BYTES_PER_FRAME = 2;

public void setDefaults () {
mSamplingRate = 48000;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
String value = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
mSamplingRate = Integer.parseInt(value);
}
if (isSafeToUseSles()) {
// mSamplingRate = 48000;
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
// AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
// String value = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
// mSamplingRate = Integer.parseInt(value);
// }
// if (isSafeToUseSles()) {
//
// mAudioThreadType = AUDIO_THREAD_TYPE_NATIVE;
// mPlayBufferSizeInBytes = 480;
// mPlayBufferSizeInBytes = 480;
// }
// else {
//
// mAudioThreadType = AUDIO_THREAD_TYPE_JAVA;
// mPlayBufferSizeInBytes = AudioTrack.getMinBufferSize(mSamplingRate,
// AudioFormat.CHANNEL_OUT_MONO,
// AudioFormat.ENCODING_PCM_16BIT);
//
// mRecordBuffSizeInBytes = AudioRecord.getMinBufferSize(mSamplingRate,
// AudioFormat.CHANNEL_IN_MONO,
// AudioFormat.ENCODING_PCM_16BIT);
// }

if (isSafeToUseSles()) {
mAudioThreadType = AUDIO_THREAD_TYPE_NATIVE;
mPlayBufferSizeInBytes = 480;
mPlayBufferSizeInBytes = 480;
}
else {
} else {

mAudioThreadType = AUDIO_THREAD_TYPE_JAVA;
mPlayBufferSizeInBytes = AudioTrack.getMinBufferSize(mSamplingRate,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);

mRecordBuffSizeInBytes = AudioRecord.getMinBufferSize(mSamplingRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
}
computeDefaults();
}

int getSamplingRate() {
Expand Down Expand Up @@ -95,6 +103,31 @@ void setRecordBufferSizeInBytes(int recordBufferSizeInBytes) {
mRecordBuffSizeInBytes = recordBufferSizeInBytes;
}

public void computeDefaults() {

int samplingRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
setSamplingRate(samplingRate);
int minPlayBufferSizeInBytes = AudioTrack.getMinBufferSize(samplingRate,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
setPlayBufferSizeInBytes(minPlayBufferSizeInBytes);

int minRecBufferSizeInBytes = AudioRecord.getMinBufferSize(samplingRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
setRecordBufferSizeInBytes(minRecBufferSizeInBytes);


if( mAudioThreadType == AUDIO_THREAD_TYPE_NATIVE) {
setPlayBufferSizeInBytes(minPlayBufferSizeInBytes/10); //rule of thumb,
// the ideal would be to ask openSLES for these numbers
setRecordBufferSizeInBytes(minRecBufferSizeInBytes/10);
}

//log("computed defaults");

}

boolean isSafeToUseSles() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
}
Expand Down
Loading

0 comments on commit 9fa073a

Please sign in to comment.