Android声音播放延迟到循环结束时

时间:2015-03-09 00:22:43

标签: android multithreading soundpool

我有这个Android问题一直给我带来困难。

我正在开发一款应用程序,只要手机通过麦克风感应到噪音,我就会播放声音。逻辑的核心是一个while循环,它从另一个类调用声音播放方法。

当设置方法将循环的条件切换为false时,此循环终止。问题出现在播放延迟直到循环条件设置为false的情况下。一旦循环结束,它会在混乱的爆炸中一次性播放声音播放方法的调用,而不是在循环的每次传递中调用它。

尽管在runOnUiThread内进行了线程化并将声音播放方法调用粘在一起,但仍然会发生这种情况。 MediaPlayer和SoundPool也会发生这种情况。我只想让playFart()方法在调用时完全播放。

NoiseActivatedFart

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageButton;
import android.widget.TextView;

public class NoiseActivatedFart extends Activity {

    public static int raw = 0; //For debugging. Will be removed
    public static int trigger = 0; //For debugging. Will be removed
    private Animation press;
    private boolean activate_button_state = true;
    private EvaluateAmbientNoise evaluateAmbientNoise = new EvaluateAmbientNoise(this);

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.noise_activated_fart);

        final TextView debugTextView = (TextView) findViewById(R.id.debug);
        press = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.press);
        final ImageButton activateButton = (ImageButton) findViewById(R.id.activateButton);

        activateButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (activate_button_state) {
                    activateButton.startAnimation(press);
                    activate_button_state = false;

                    //The Android.MediaRecorder documentation recommends that objects
                    //be used in their own threads, as it can really drag the main thread down

                    new Thread() {
                        public void run(){
                            evaluateAmbientNoise.startListening();
                        }
                    }.start();
                }
                else {
                    activateButton.startAnimation(press);
                    debugTextView.setText(raw + " " + trigger);
                    activate_button_state = true;
                    evaluateAmbientNoise.stopListening();
                    System.out.println("stop listening");
                }
            }
        });
    }
}

评估环境噪音

import android.content.Context;
import android.media.MediaRecorder;
import android.app.Activity;

class EvaluateAmbientNoise implements Runnable {

    Activity activity = new Activity();
    int[] average = new int[10];
    int averageNoiseLevel = 1;
    int noiseTriggerLevel = 1;
    Context context;
    FartPlayer fartplayer = new FartPlayer();
    MediaRecorder recorder = null;
    boolean recorder_state = false;
    boolean keepGoing = false;

    /**
     * Constructor
     * The SoundPool object that is utilized by "fartPlayer"
     * requires a context object to function, and gets it from here
     */
    EvaluateAmbientNoise(Context input_context) {
        context = input_context;
    }

    public void run() {
        startListening();
    }

    /**
     * startListening prepares and starts an Android.MediaRecorder object that is
     * used for it's getMaxAmplitude() function. It checks the level of
     * noise several times, averages them, and uses the average to determine a trigger level.
     * It continues to check the levels and play a fart whenever the levels exceed the trigger.
     * It continues until stopListening is called.
     */

    public void startListening() {
        prepareMediaRecorder();
        startMediaRecorder();
        fartplayer.initSounds(context);

        //Gather sound levels, average them, and use it to make a trigger
        averageNoiseLevel = 0;

        for (int counter = 0; counter < 10; counter++) {
            average[counter] = recorder.getMaxAmplitude();
            System.out.println("getting values: " + average[counter]);
        }
        for (int i:average){
            averageNoiseLevel += i;
            System.out.println("averaging array: " + averageNoiseLevel);
        }
        averageNoiseLevel = averageNoiseLevel / average.length;
        noiseTriggerLevel = (int)(averageNoiseLevel * 1.5);

        System.out.println("average total : " + averageNoiseLevel);
        System.out.println("trigger: " + noiseTriggerLevel);

        //Listen for noise, and play a fart when the noise exceeds the trigger
        keepGoing = true;

        int currentLevel = 0;
        while (keepGoing) {
            currentLevel = recorder.getMaxAmplitude();
            if (currentLevel > (noiseTriggerLevel)) {
                activity.runOnUiThread(new Runnable() {
                    public void run() {
                        fartplayer.playFart();
                    }
                });
            }
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                System.err.println("Caught Exception: " + e.getMessage());
            }

            System.out.println("tick");
        }
    }

    public static void sleep() {
        System.out.println("sleeping 1000ms");
    }

    // Stops "startListening()"
    public void stopListening() {
        keepGoing = false;
        stopMediaRecorder();
    }

    /**
     * start and stopMediaRecorder essentially staples a crude state flag to an
     * Android.MediaRecorder object. This is needed because of the object's different states,
     * and its simultaneous lack of state-checking functions.
     */
    private void startMediaRecorder() {
        if (recorder_state == false) {
            recorder.start();
            recorder_state = true;
        }
    }

    private void stopMediaRecorder() {
        if (recorder_state == true) {
            recorder.stop();
            recorder.release();
            recorder = null;
            recorder_state = false;
        }
    }

    /**
     * prepareMediaRecorder initializes the Android.MediaRecorder object before use.
     * Any calls to MediaRecorder throw an exception otherwise
     */
    public void prepareMediaRecorder() {
        recorder = new MediaRecorder();
        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
        recorder.setOutputFile("/dev/null/");

        try {
            recorder.prepare();
        }
        catch (Exception e){
            System.out.println("Caught IOException: " + e.getMessage());
        }
    }
}

放屁球员

import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class FartPlayer extends Activity {

    private final Random fartSelector = new Random();
    private List<Integer> fartList = new ArrayList<Integer>();
    SoundPool sp;

    //Initializes the SoundPool object and loads some fart mp3s into it
    public void initSounds(Context c) {
        sp = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
        fartList.add(sp.load(c, R.raw.fart1, 1));
        fartList.add(sp.load(c, R.raw.fart2, 1));
        fartList.add(sp.load(c, R.raw.fart3, 1));
        fartList.add(sp.load(c, R.raw.fart4, 1));
        fartList.add(sp.load(c, R.raw.fart5, 1));
        fartList.add(sp.load(c, R.raw.fart6, 1));
    }

    //Plays a random fart from the SoundPool when called
    public void playFart() {
        sp.play(fartList.get(fartSelector.nextInt(fartList.size())),1f,1f,1,0,1f);
        System.out.println("farting");
    }
}

1 个答案:

答案 0 :(得分:0)

问题在于:

public void initSounds(Context c) {
    sp = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
    fartList.add(sp.load(c, R.raw.fart1, 1));
    fartList.add(sp.load(c, R.raw.fart2, 1));
    fartList.add(sp.load(c, R.raw.fart3, 1));
    fartList.add(sp.load(c, R.raw.fart4, 1));
    fartList.add(sp.load(c, R.raw.fart5, 1));
    fartList.add(sp.load(c, R.raw.fart6, 1));
}

一次加载所有声音,一旦播放,每次声音都会立即播放,因为每个声音都会被加载并立即播放。您可以尝试使用MediaPlayer:

import android.content.Context;
import android.media.MediaPlayer;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class FartPlayer {

    private Random fartSelector = new Random();
    private List<Integer> songs;
    Context c;
    MediaPlayer mp;
    //Initializes the SoundPool object and loads some fart mp3s into it
    public void initSounds(Context c) {
        this.c = c;
        mp = new MediaPlayer();
        songs = new ArrayList<Integer>();
        songs.add(0, fart1);//starts at 0 so random isnt messed up
        songs.add(1, fart2);
        songs.add(2, fart3);
        songs.add(3, fart4);
        songs.add(4, fart5);
        songs.add(5, fart6);
    }

    //Plays a random fart from the SoundPool when called
    public void playFart(){
        int song;
        song = songs.get(fartSelector.nextInt(songs.size()));//selects a random number from 0-5(up to 6)
        mp = MediaPlayer.create(c, song);//sets up the output
        mp.start();//plays
        System.out.println("farting");
    }


}

然而,它可以通过加载一个声音来解决:

Random r = new Random();
public void initSounds(Context c) {
    this.c = c;
    sp = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
    songs = new ArrayList<Integer>();
    songs.add(0, fart1);//starts at 0 so random isnt messed up
    songs.add(1, fart2);
    songs.add(2, fart3);
    songs.add(3, fart4);
    songs.add(4, fart5);
    songs.add(5, fart6);
}

//Plays a random fart from the SoundPool when called
public void playFart(){
    int song;
    song = songs.get(fartSelector.nextInt(songs.size()));//selects a random number from 0-5(up to 6)
    sp.load(c, song, 1);//if this doesnt work, comment this answer
    sp.play(fartList.get(r.nextInt(fartList.size())));
    System.out.println("farting");
}