5

I'm trying to make an app that records sound for a second and then reads the maximum amplitude from the recorded sound. This is what I have so far but my app crashes and I can't figure out why.

This is my second activity, which I'm calling from my first after I press a "Record" button. The app crashes on my emulator and on my phone.

package radu.soundSampler;

import java.io.IOException;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
import android.media.MediaRecorder;

public class DisplayMessageActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    //Intent intent = getIntent();
    //String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);

    MediaRecorder rec = new MediaRecorder();
    rec.setAudioSource(MediaRecorder.AudioSource.MIC);
    rec.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
    rec.setOutputFile("/newRecording");
    rec.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);

    try {
        rec.prepare();
    } catch (IllegalStateException e) {

    } catch (IOException o) {

    }
    rec.start();
            for(int i=0;i<100000;i++);
    rec.stop();
    int rezultat = rec.getMaxAmplitude();

    TextView textView = new TextView(this);
    textView.setTextSize(40);

    textView.setText(Integer.toString(rezultat));

    setContentView(textView);
}

}

The (updated) error log on my computer says:

08-18 13:30:07.968: E/MediaRecorder(687): start called in an invalid state: 4
08-18 13:30:07.968: D/AndroidRuntime(687): Shutting down VM
08-18 13:30:07.968: W/dalvikvm(687): threadid=1: thread exiting with uncaught exception (group=0x40015560)
08-18 13:30:07.978: E/AndroidRuntime(687): FATAL EXCEPTION: main
08-18 13:30:07.978: E/AndroidRuntime(687): java.lang.RuntimeException: Unable to start activity ComponentInfo{radu.soundSampler/radu.soundSampler.DisplayMessageActivity}: java.lang.IllegalStateException
08-18 13:30:07.978: E/AndroidRuntime(687):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
08-18 13:30:07.978: E/AndroidRuntime(687):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
08-18 13:30:07.978: E/AndroidRuntime(687):  at android.app.ActivityThread.access$1500(ActivityThread.java:117)
08-18 13:30:07.978: E/AndroidRuntime(687):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
08-18 13:30:07.978: E/AndroidRuntime(687):  at android.os.Handler.dispatchMessage(Handler.java:99)
08-18 13:30:07.978: E/AndroidRuntime(687):  at android.os.Looper.loop(Looper.java:123)
08-18 13:30:07.978: E/AndroidRuntime(687):  at android.app.ActivityThread.main(ActivityThread.java:3683)
08-18 13:30:07.978: E/AndroidRuntime(687):  at java.lang.reflect.Method.invokeNative(Native Method)
08-18 13:30:07.978: E/AndroidRuntime(687):  at java.lang.reflect.Method.invoke(Method.java:507)
08-18 13:30:07.978: E/AndroidRuntime(687):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
08-18 13:30:07.978: E/AndroidRuntime(687):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
08-18 13:30:07.978: E/AndroidRuntime(687):  at dalvik.system.NativeStart.main(Native Method)
08-18 13:30:07.978: E/AndroidRuntime(687): Caused by: java.lang.IllegalStateException
08-18 13:30:07.978: E/AndroidRuntime(687):  at android.media.MediaRecorder.start(Native Method)
08-18 13:30:07.978: E/AndroidRuntime(687):  at radu.soundSampler.DisplayMessageActivity.onCreate(DisplayMessageActivity.java:29)
08-18 13:30:07.978: E/AndroidRuntime(687):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
08-18 13:30:07.978: E/AndroidRuntime(687):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
08-18 13:30:07.978: E/AndroidRuntime(687):  ... 11 more

so I've thought maybe the emulator can't "run" a microphone, so I installed the .apk on my phone but it crashed there too. I don't know what could be the problem, so could you please help me, and/or give me any hints?

Thanks a lot in advance!

One more stack trace, the one you requested. I used in the catch statements o.printStackTrace() and e.printStackTrace(), I hope it's what you requested me to do:

08-18 14:06:11.908: W/System.err(811): java.io.FileNotFoundException: /newRecording (Read-only file system)
08-18 14:06:11.908: W/System.err(811):  at org.apache.harmony.luni.platform.OSFileSystem.open(Native Method)
08-18 14:06:11.908: W/System.err(811):  at dalvik.system.BlockGuard$WrappedFileSystem.open(BlockGuard.java:232)
08-18 14:06:11.918: W/System.err(811):  at java.io.FileOutputStream.<init>(FileOutputStream.java:94)
08-18 14:06:11.918: W/System.err(811):  at java.io.FileOutputStream.<init>(FileOutputStream.java:165)
08-18 14:06:11.918: W/System.err(811):  at java.io.FileOutputStream.<init>(FileOutputStream.java:144)
08-18 14:06:11.918: W/System.err(811):  at android.media.MediaRecorder.prepare(MediaRecorder.java:533)
08-18 14:06:11.918: W/System.err(811):  at radu.soundSampler.DisplayMessageActivity.onCreate(DisplayMessageActivity.java:23)
08-18 14:06:11.918: W/System.err(811):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
08-18 14:06:11.918: W/System.err(811):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
08-18 14:06:11.918: W/System.err(811):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
08-18 14:06:11.918: W/System.err(811):  at android.app.ActivityThread.access$1500(ActivityThread.java:117)
08-18 14:06:11.918: W/System.err(811):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
08-18 14:06:11.918: W/System.err(811):  at android.os.Handler.dispatchMessage(Handler.java:99)
08-18 14:06:11.918: W/System.err(811):  at android.os.Looper.loop(Looper.java:123)
08-18 14:06:11.918: W/System.err(811):  at android.app.ActivityThread.main(ActivityThread.java:3683)
08-18 14:06:11.918: W/System.err(811):  at java.lang.reflect.Method.invokeNative(Native Method)
08-18 14:06:11.928: W/System.err(811):  at java.lang.reflect.Method.invoke(Method.java:507)
08-18 14:06:11.928: W/System.err(811):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
08-18 14:06:11.928: W/System.err(811):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
08-18 14:06:11.928: W/System.err(811):  at dalvik.system.NativeStart.main(Native Method)
08-18 14:06:11.928: E/MediaRecorder(811): start called in an invalid state: 4
08-18 14:06:11.928: D/AndroidRuntime(811): Shutting down VM
08-18 14:06:11.928: W/dalvikvm(811): threadid=1: thread exiting with uncaught exception (group=0x40015560)
08-18 14:06:11.948: E/AndroidRuntime(811): FATAL EXCEPTION: main
08-18 14:06:11.948: E/AndroidRuntime(811): java.lang.RuntimeException: Unable to start activity ComponentInfo{radu.soundSampler/radu.soundSampler.DisplayMessageActivity}: java.lang.IllegalStateException
08-18 14:06:11.948: E/AndroidRuntime(811):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
08-18 14:06:11.948: E/AndroidRuntime(811):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
08-18 14:06:11.948: E/AndroidRuntime(811):  at android.app.ActivityThread.access$1500(ActivityThread.java:117)
08-18 14:06:11.948: E/AndroidRuntime(811):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
08-18 14:06:11.948: E/AndroidRuntime(811):  at android.os.Handler.dispatchMessage(Handler.java:99)
08-18 14:06:11.948: E/AndroidRuntime(811):  at android.os.Looper.loop(Looper.java:123)
08-18 14:06:11.948: E/AndroidRuntime(811):  at android.app.ActivityThread.main(ActivityThread.java:3683)
08-18 14:06:11.948: E/AndroidRuntime(811):  at java.lang.reflect.Method.invokeNative(Native Method)
08-18 14:06:11.948: E/AndroidRuntime(811):  at java.lang.reflect.Method.invoke(Method.java:507)
08-18 14:06:11.948: E/AndroidRuntime(811):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
08-18 14:06:11.948: E/AndroidRuntime(811):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
08-18 14:06:11.948: E/AndroidRuntime(811):  at dalvik.system.NativeStart.main(Native Method)
08-18 14:06:11.948: E/AndroidRuntime(811): Caused by: java.lang.IllegalStateException
08-18 14:06:11.948: E/AndroidRuntime(811):  at android.media.MediaRecorder.start(Native Method)
08-18 14:06:11.948: E/AndroidRuntime(811):  at radu.soundSampler.DisplayMessageActivity.onCreate(DisplayMessageActivity.java:30)
08-18 14:06:11.948: E/AndroidRuntime(811):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
08-18 14:06:11.948: E/AndroidRuntime(811):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
08-18 14:06:11.948: E/AndroidRuntime(811):  ... 11 more
08-18 14:06:14.181: I/Process(811): Sending signal. PID: 811 SIG: 9
Radu Gheorghiu
  • 20,049
  • 16
  • 72
  • 107
  • Do you have the `android.permission.RECORD_AUDIO` permission in your manifest? – Michael Aug 18 '12 at 13:05
  • No, where exactly do I put it? – Radu Gheorghiu Aug 18 '12 at 13:26
  • Nevermind, I found where to put permission :) Thanks, I hope it works now. – Radu Gheorghiu Aug 18 '12 at 13:27
  • It doesn't work, it still crashes, both on my phone and on my emulator after adding `` in the manifest file. – Radu Gheorghiu Aug 18 '12 at 13:39
  • You are catching the exception, but you're not doing anything with it? Why? Why wouldn't you just print the stack trace of the exception. – tolgap Aug 18 '12 at 13:50
  • Your new stacktrace suggests that `prepare` fails. Could you do `printStackTrace()` on the exceptions in the `catch` blocks? Does your app have the rights to write to the path you're using for the output file? – Michael Aug 18 '12 at 13:52
  • What permission is that? `WRITE_EXTERNAL_STORAGE` ? – Radu Gheorghiu Aug 18 '12 at 13:59
  • I would assume that "/" is the root partition, to which you're unlikely to have access unless you've rooted your device. You might want to look at http://stackoverflow.com/questions/5453708/android-how-to-use-environment-getexternalstoragedirectory for info on how to get a path to the external storage directory (and yes, you'll need the WRITE_EXTERNAL_STORAGE permission for that). – Michael Aug 18 '12 at 14:32
  • Does external storage mean SD card? Because I do not have an SD card on my phone. – Radu Gheorghiu Aug 18 '12 at 14:33
  • I used the commands in your link to get the absolute path and then change to a `temp` folder in which to save the recording, I ran the code on my phone and it created a `newRecording` file, but the app still crashes, both on the phone and emulator. – Radu Gheorghiu Aug 18 '12 at 14:42
  • Crashes how? The stack trace should give you a hint of what's going wrong (unsupported format, file writing problems, ...). – Michael Aug 20 '12 at 08:18

7 Answers7

2

Use setOutoutFile(getExternalFilesDir().getAbsolutePath() + "/newRecording")

Make sure you have this permission in your manifest

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Don't do the busy-wait loop. Use a timer.

Don't ignore exceptions in prepare.

yoah
  • 7,180
  • 2
  • 30
  • 30
  • I've added both of these in my last version of the code and it still won't work. I just didn't update the code in the question. I did set the output file with the exact line you used, tested the app on the phone and created the `newRecording` file, but without data. And the app still crashes, and it's the same error stack as the last one posted. – Radu Gheorghiu Aug 22 '12 at 19:51
  • Your problem is probably in the call to prepare, but you are hiding the exceptions. Print them and see what fails. Thy using MediaRecorder.OutputFormat.DEFAULT. – yoah Aug 24 '12 at 07:23
2

If you simply want to record the "volume" of the microphone, then you could redirect output to null, like this:

recorder = new MediaRecorder();
// following calls throw Illegal State Exceptions, but here we follow the proper order

recorder.setAudioSource(AudioSource.MIC);

// After set audio source
recorder.setOutputFormat(OutputFormat.THREE_GPP);

// After set output format
recorder.setAudioEncoder(AudioEncoder.AMR_NB);
recorder.setOutputFile("/dev/null");
// Before prepare

try {
    recorder.prepare();
} catch (IOException e) {
    System.err.println(e);
}
// After prepare
recorder.start();

// Call getMaxAmplitude() with a zero returned value, so you can recall later
recorder.getMaxAmplitude();

Also, you shouldn't make a fake delay inside onCreate. Use a handler, instead:

public void onCreate(Bundle savedInstanceState) {

    // ...

    handler = new Handler();
    handler.postDelayed(this, 1000);
}

public void run() {
    int value = recorder.getMaxAmplitude();
    recorder.stop();

    // etc
}
KitKat
  • 1,495
  • 14
  • 15
  • is this safe to do this way? do we have to flag this temp file for garbage collection or anything like that ? – jesses.co.tt Jun 07 '14 at 19:51
  • @jesses.co.tt We don't use a temp file; we [redirect output to "nothing"](http://stackoverflow.com/a/10508862/2626112), so as to concentrate on input. – KitKat Jun 10 '14 at 18:09
  • copy that... wasn't totally sure of the meaning but that link helps, thx! – jesses.co.tt Jun 10 '14 at 23:13
1

Try it this way.....

    int rezultat = 0;   

try {
        rec.prepare();

        rec.start();

        TimeUnit.SECONDS.sleep(1);  

        rec.stop();

    } catch (IllegalStateException e) {

    } catch (IOException o) {

    } catch (InterruptedException e) {      

    }

     rezultat = rec.getMaxAmplitude();
Kumar Vivek Mitra
  • 33,294
  • 6
  • 48
  • 75
1

First, you need to put your record in a place where you are allowed to write.

File parent = getContext().getFilesDir();
File recordFile = new File(parent, "newRecording");

is a correct start. (there are other)

njzk2
  • 38,969
  • 7
  • 69
  • 107
0

You can't create a file in the root file system as you are trying by using rec.setOutputFile("/newRecording"). Create a temporary file and write it there. You might want to check the methods to get the private file directory getFilesDir() and related.

The exception you got tells you exactly this: The FileNotFoundException occurs and shows you that the prepare() call has failed. And thus you the MediaRecoder is not prepared and you won't be able to start() as it is in the wrong state.

Another comment: To wait a second before stopping recording, use Thread.sleep() and not a for loop counting to whatever. Second, please do it in a background thread as blocking the UI thread in any way might make your UI sluggish, and in the worst case, Android might kill your application with an ANR exception.

Stephan
  • 7,360
  • 37
  • 46
0

Your activity crashes because an Exception is thrown in the onCreate() method. You should absolutely avoid this situation to happen. Call your prepare() method (or any method that is not purely related to the activity's initialization) from a separate thread, and always show debug message in catch blocks.

As a rule of the thumb : never write an empty catch {} block. You will always regret it afterwards (believe me)

Orabîg
  • 11,718
  • 6
  • 38
  • 58
0

Salut!

You're problem might be because you're not using the correct directory on Android. As I can see, you are using \ which is the root directory and it is of course read-only.

To solve this, you can add the external storage path to your file like this:

String externalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;

// Your code here

rec.setOutputFile(externalStoragePath + "newRecording");

This should solve the problem. Please leave a comment if it doesn't work.

P.S. Put a break point at the top of onCreate() and debug your app to see exactly where it fails.

dragostis
  • 2,574
  • 2
  • 20
  • 39