Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ringtone plays over and over again (looping infinitely)

I have an Android app that plays a notification ringtone (RingtoneManager.TYPE_NOTIFICATION) when certain events are sent to a BroadcastReceiver.

The code that plays the ringtone basically does:

    onReceive(Context context, Intent intent)
    {
        ...
        Uri ringtoneUri = someFunctionToLookupAValidNotificationRingtoneUri();
        ...
        Ringtone tone = RingtoneManager.getRingtone(context, uri);
        Log.v(TAG, "About to play ringtone");
        tone.play();
    }

Every so often when this code is run, the ringtone starts playing over and over again infinitely. Sometimes it happens when a large number of events are bunched close together, but it has also happened when only one event came in. The log message (and debugging) verifies that the tone.play() call is happening only once per event, and there isn't an infinite stream of events.

The only way stop the infinite looping is to kill my app.

It's almost as if every so often, Android forgets to flush the sound output buffer and so it keeps looping through playing whatever is inside.

Any ideas how to debug and/or fix this issue?

like image 773
0xbe5077ed Avatar asked Jan 20 '13 23:01

0xbe5077ed


1 Answers

I had a similar problem. It turned out that when a ringtone is played, it will repeat indefinitely until stopped, whereas when a notification sound is played, it will play only once. So my guess is that the difference in your case lies in whether a ringtone or a notification sound was selected in someFunctionToLookupAValidNotificationRingtoneUri(). As you do not supply the code for someFunctionToLookupAValidNotificationRingtoneUri(), I cannot know what happens there.

Picking a notification sound

If you use a ringtone picker for the user to select a notification sound, this code will start the intent to pick a notification sound as opposed to a ringtone:

    private void PickANotificationSound() {
        Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);

        // We want a notification sound picked. If we don't add this to the
        // intent, a ringtone is picked; this means that when it is played,  
        // it will keep on playing until it is explicitly stopped. A  
        // notification sound, however, plays only once.
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE,
            RingtoneManager.TYPE_NOTIFICATION);

        // Start the intent to pick a notification sound. The result will show 
        // up later when onActivityResult() is called.
        startActivityForResult(intent, REQUESTCODE_NOTIFICATION_SOUND);
    }

where REQUESTCODE_NOTIFICATION_SOUND is just a local constant with any name and value, identifying the request:

    private static final int REQUESTCODE_NOTIFICATION_SOUND = 1;

An onActivityResult() callback function like this will then pick up the notification sound URI and play it:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, 
            Intent data) {

        if (requestCode == REQUESTCODE_NOTIFICATION_SOUND) {
            try {
                if (resultCode == RESULT_OK) {
                    Uri ringtoneUri = data.getParcelableExtra(
                            RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
                    if (ringtoneUri != null) {
                        PlayRingtoneOrNotificationSoundFromUri(ringtoneUri);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else
            super.onActivityResult(requestCode, resultCode, data);
    }

    private void PlayRingtoneOrNotificationSoundFromUri(Uri ringtoneUri) {

        Ringtone ringtone = RingtoneManager.getRingtone(
            getApplicationContext(), ringtoneUri);

        if (ringtone != null) {
            ringtone.play();
        }
    }

Because we said in the intent that we wanted to pick a notification sound, the resulting sound is a notification sound and is therefore only played once after the call to ringtone.play().

If we had said in the intent that we wanted to pick a ringtone, like this:

    intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE,
        RingtoneManager.TYPE_RINGTONE);

the picker would return a ringtone that would play indefinitely after the ringtone.play() call – until stopped by ringtone.stop() or the application was killed.

Two meanings of 'ringtone'

Note that the terminology in the Android API adds to the confusion, as the word "ringtone" is used with two different meanings (cf. the documentation of RingtoneManager):

  1. Any sound meant to catch the user's attention, such as a sound to play repeatedly when the phone rings, a notification sound, or a similar sound. This meaning is used in the name RingtoneManager.

  2. A sound to play repeatedly when the phone rings, as opposed to a notification sound or a similar sound. This meaning is used in the name TYPE_RINGTONE in RingtoneManager.TYPE_RINGTONE.

like image 99
Jesper Avatar answered Oct 12 '22 10:10

Jesper