Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop/start a Service that contains an infinite loop on creation

So for background, I am attempting to create an application that continuously records via the microphone and stores the data in a buffer. The goal of the program would be to perform some type of processing on the data in the buffer and act upon it. Currently, the app just reads the data into a buffer and writes it ASAP. When running the app, one would speak into the microphone and then hear what you just spoke come out the other end.

Now here is where my inexperience with Android begins to rear its head. I am conducting the reading and writing operation as an infinite loop. The service is below:

public class AudioService extends Service {

private final int MIC = AudioSource.MIC;
private final int SAMPLE = 44100;
private final int CHANNELI = AudioFormat.CHANNEL_IN_MONO;
private final int CHANNELO = AudioFormat.CHANNEL_OUT_MONO;
private final int FORMAT = AudioFormat.ENCODING_PCM_16BIT;
private final int BUFFERSIZE = AudioRecord.getMinBufferSize(SAMPLE,
        CHANNELI, FORMAT);
private final int STREAM = AudioManager.STREAM_MUSIC;
private final int MODE = AudioTrack.MODE_STREAM;
private boolean play = true;

AudioRecord recorder = null;
AudioTrack track = null;

short[] buffer = null;

public void OnCreate() {

}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    recorder = new AudioRecord(MIC, SAMPLE, CHANNELI, FORMAT, BUFFERSIZE);
    track = new AudioTrack(STREAM, SAMPLE, CHANNELO, FORMAT, BUFFERSIZE,
            MODE);
    buffer = new short[BUFFERSIZE];
    recorder.startRecording();
    track.play();

    while (play) {
        recorder.read(buffer, 0, buffer.length);
        track.write(buffer, 0, buffer.length);
    }
    return START_STICKY;
}

This service is called when a "Record" button is clicked in the activity. I want to be able to click record and have the option of clicking cancel to stop this loop. The listener below that implements this is:

private OnClickListener Recording = new OnClickListener() {
    public void onClick(View v) {

        serviceIntent = new Intent(getApplicationContext(),
                AudioService.class);
        serviceIntent.putExtra("extraData", "somedata");
        startService(serviceIntent);

        record.setEnabled(false);
        cancel.setEnabled(true);
        cancel.requestFocus();

};

And now the problem becomes obvious. The application is unable to complete execution when it reaches startService(serviceIntent) and just hangs around in the balance.

So what's my recourse? I was thinking of some way to control the service from inside the infinite loop but my inexperience with Android leaves me wondering how to do that. Inciting some way to break by maybe instantiating a new button inside the loop; so during startIntent I would be able to break out of the loop and "end the madness".

Any help would be appreciated. I'm also realizing this service should be started on a seperate thread from UI so as to avoid the "App is not responding..." issue but that's sort of another topic. My main goal for right now is breaking from the loop and I would appreciate any help or direction on how to do thisz.

like image 859
user1429581 Avatar asked May 31 '12 23:05

user1429581


1 Answers

The service is below

Problem #1: You have no way of breaking out of your loop.

Problem #2: Your loop is running on the main application thread.

This is bad.

So what's my recourse?

You put your infinite loop in a background thread, using something (e.g., an AtomicBoolean) to tell that thread to stop when needed (e.g., onDestroy()).

I'm also realizing this service should be started on a seperate thread from UI so as to avoid the "App is not responding..." issue but that's sort of another topic.

No, it is the same topic.

Inciting some way to break by maybe instantiating a new button inside the loop

Services do not have a UI.

Since you have a "record" button in that activity that triggers a call to startService(), then perhaps that activity should have a "stop" button that triggers a call to stopService().

Once you determine where and how to call stopService(), then all you need to do is get onDestroy() of your service to cause your background thread to stop running, as onDestroy() will be triggered by the call to stopService().

like image 131
CommonsWare Avatar answered Sep 22 '22 19:09

CommonsWare