Search code examples
androidandroid-mediaplayerringtone

MediaPlayer setDataSource failed with status=0x80000000 for defaultUri


I have a RingTone class I made to play the device's ringtone, either once or looping.

class RingTone(context: Context) {

    private val player = MediaPlayer()
    private val audioManager: AudioManager

    init {
        val alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
        player.setDataSource(context, alert) // this line may crash

        audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
    }

   fun play(isLooping: Boolean = true): RingTone {
        if (audioManager.getStreamVolume(AudioManager.STREAM_RING) != 0) {
            val attributes = AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                    .build()

            player.setAudioAttributes(attributes)
            player.isLooping = isLooping
            player.prepare()
            player.start()
        }
        return this
    }
}

This works fine on the devices I'm testing on, but we've ran into an issue where one of our devices will crash 100% when trying to setDataSource.

We have multiple of the same device, all running Android 5.1.

The exception:

Caused by java.io.IOException: setDataSource failed.: status=0x80000000
       at android.media.MediaPlayer.nativeSetDataSource(MediaPlayer.java)
       at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1090)
       at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1079)
       at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1032)
       at android.media.MediaPlayer.setDataSource(MediaPlayer.java:968)
       at com.xxxx.yyy.RingTone.<init>(RingTone.kt:21)

How can I reproduce this crash, and fix the issue?

Thanks for your time.


Solution

  • I was able to reproduce this issue by using another device that allowed me to set my ringtone to "NONE". While this isn't possible on the device that was having the issue, I think this was the problem.

    Now, to handle this case, it seems you have to do a try/catch as there isn't anything to check if the source is valid before trying.

        initialized = try {
            player.setDataSource(context, alert)
            true
        } catch (ex: IOException) {
            false
        }
    

    And then within play.

       fun play(isLooping: Boolean = true): RingTone {
            if (initialized && audioManager.getStreamVolume(AudioManager.STREAM_RING) != 0) {
                  ...
            }
            return this
        }