Search code examples
javaandroidaudiotimertasksoundpool

Using SoundPool, Timer and TimerTask to play a random sound every minute


I am trying to play a random sound every minute which prompts a user to interact with the device. I am using SoundPool, Timer, and TimerTask to try to achieve this. When the sound is played I am also using Logcat to see the ID of the sound which is to be played (This is for research and data analysis purposes). I have tried a few methods which include initialising the SoundPool inside and outside the TimerTask run() method as well releasing the SoundPool once a button is clicked. timer.Schedule is used to schedule the TimerTask to run, should I make these static?

The logcat is logging the SoundId but the sound is not played consistently. For example, it will play the first sound and log then it will log other SoundId's without playing the sound. This happens even though the button has been pressed and the SoundPool's resources have been released. Sometimes the sound will not even play at all to start with.

Can anyone advise me on why this would be inconsistent or a better way to go about doing this, please?

public class TouchscreenDashboard extends AppCompatActivity implements View.OnClickListener {

private SoundPool soundPool;
int[] sounds={R.raw.decrease_fan_speed_by_2, R.raw.decrease_fan_speed_by_5,
        R.raw.increase_fan_speed1, R.raw.increase_fan_speed_by_3,R.raw.lower_temp1,
        R.raw.lower_temp4, R.raw.raise_temp2, R.raw.raise_temp3 ,R.raw.skip_backwards_2_songs,
        R.raw.skip_backwards_4_songs,R.raw.skip_forward_1_song, R.raw.skip_forward_5_songs,
        R.raw.volume_down3,R.raw.volume_down6, R.raw.volume_up3, R.raw.volume_up5};

private Button volumeUp;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_2);
    Log.i("DashboardActivity", "Dashboard has started");

    Timer timer = new Timer() {};
    TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {

            AudioAttributes audioAttributes = new AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                    .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
                    .build();

            soundPool = new SoundPool.Builder()
                    .setAudioAttributes(audioAttributes)
                    .build();

            Random r = new Random();
            int Low = 0;
            int High = 16;
            int random = r.nextInt(High-Low) + Low;
            int soundId = soundPool.load(getApplicationContext(), sounds[random], 1);

            soundPool.play(soundId, 1, 1, 0, 0, 1);
            Log.i("DashboardActivity", "SoundId: " + random);
        }
    };
    timer.schedule(timerTask, 60000, 60000);

    volumeUp = findViewById(R.id.volumeUp);

}

@Override
public void onClick(View view) {
    switch (view.getId()) {
        case R.id.volumeUp:
            if (volumeCount < 99) {
                volumeCount++;
                volumeText.setText(Integer.toString(volumeCount));
            }
            soundPool.release();
            Log.i("DashboardActivity", "Volume Up Clicked");
            break;
        }
    }
}

Solution

  • So, after much stressing, I have a working solution! I still think there must be a better way to do it but this is what I have come up with. The setOnLoadCompleteListener now plays the sound only once loaded and timerTask2 runs 5 seconds behind the timerTask1. The reason for the 5 seconds delay is that my sounds are all under 1-3 second long.

    public class TouchscreenDashboard extends AppCompatActivity implements View.OnClickListener {
    
    int[] sounds={R.raw.decrease_fan_speed_by_2, R.raw.decrease_fan_speed_by_5,
            R.raw.increase_fan_speed1, R.raw.increase_fan_speed_by_3,R.raw.lower_temp1,
            R.raw.lower_temp4, R.raw.raise_temp2, R.raw.raise_temp3 ,R.raw.skip_backwards_2_songs,
            R.raw.skip_backwards_4_songs,R.raw.skip_forward_1_song, R.raw.skip_forward_5_songs,
            R.raw.volume_down3,R.raw.volume_down6, R.raw.volume_up3, R.raw.volume_up5};
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_2);
        Log.i("DashboardActivity", "Dashboard has started");
    
        startTimer();
    
    }
    
    public void startTimer() {
        timer = new Timer();
        timer2 = new Timer();
        initializeTimerTask();
        initializeTimerTask2();
        timer.schedule(timerTask, randomTimeInt, randomTimeInt); //
        timer2.schedule(timerTask2, randomTimeInt + 5000, randomTimeInt);
    }
    
    public void initializeTimerTask() {
    
        timerTask = new TimerTask() {
            @Override
            public void run() {
    
                audioAttributes = new AudioAttributes.Builder()
                        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                        .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
                        .build();
                soundPool = new SoundPool.Builder()
                        .setAudioAttributes(audioAttributes)
                        .build();
    
                releaseSoundpool = true;
                Random r = new Random();
                int Low = 0;
                int High = 16;
                int random = r.nextInt(High-Low) + Low;
                final int soundId = soundPool.load(getApplicationContext(), sounds[random], 1);
                soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
                    @Override
                    public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                        soundPool.play(soundId, 1, 1, 1, 0, 1);
                    }
                });
                Log.d("TouchscreenDashboard", "soundID played: " + random);
            }
        };
    }
    
    public void initializeTimerTask2() {
    
        timerTask2 = new TimerTask() {
            @Override
            public void run() {
                soundPool.release();
                Log.d("TouchscreenDashboard", "SoundPool released");
            }
        };
    }
    

    I really hope this helps someone else.