Search code examples
androidkotlinserviceandroid-mediaplayer

Playing audio in the background more than one minute on Android


I am in the process of developping an Android app handling audio data, now seeing how to have the audio keep playing when the app is in the background using a service.

At this point I can set a service playing audio, but the problem is that once in the background, it will stop after exactly one minute. I have tried a few things I found on the net and nothing works. I put my code hereafter, that would be great if someone could let me know what I need to change.

Here is the MainActivity.kt file:

package me.soft.myapp

import android.content.Intent
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View

class MainActivity : AppCompatActivity() {
    private var toggleFlag = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }


    fun startHandler(view: View) {
        val serviceIntent = Intent(this, TheService::class.java)
        startService(serviceIntent)
    }


    fun stopHandler(view: View) {
        val serviceIntent = Intent(this, TheService::class.java)
        stopService(serviceIntent)
    }


    fun toggleHandler(view: View) {
        toggleFlag = !toggleFlag

        when(toggleFlag) {
            true -> view.setBackgroundColor(Color.rgb(0xFF,0x00,0x00))
            false -> view.setBackgroundColor(Color.rgb(0x00,0x00,0xFF))
        }
    }
}

Here is the TheService.kt file:

package me.soft.myapp

import android.R
import android.app.Notification
import android.app.Service
import android.content.Intent
import android.media.MediaPlayer
import android.os.IBinder
import android.provider.Settings
import android.widget.Toast
import androidx.core.app.NotificationCompat


class TheService: Service() {
    private lateinit var audioPlayer:MediaPlayer

    override fun onCreate() {
        super.onCreate()
    }


    override fun onBind(p0: Intent?): IBinder? {
        return null
    }


    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val runnable = Runnable {
            audioPlayer = MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI)
            audioPlayer?.setLooping(true)
            audioPlayer.start()
        }

        val thread = Thread(runnable)
        thread.start() // Stops after one minute when in the background.
        return START_NOT_STICKY
    }


    override fun onDestroy() {
        super.onDestroy()
        audioPlayer.stop()
    }
}

And just in case this is useful, here is the acticity_main.xml file:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/   res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:layout_editor_absoluteX="1dp"
        tools:layout_editor_absoluteY="1dp">

        <Button
            android:id="@+id/strtBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Start"
            android:onClick="startHandler"
            android:textAllCaps="false" />

        <Button
            android:id="@+id/stpBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Stop"
            android:onClick="stopHandler"
            android:textAllCaps="false" />

        <Button
            android:id="@+id/bgctgBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="BCG Toggle"
            android:onClick="toggleHandler"
            android:textAllCaps="false" />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

And also in case this is useful, here is the AndroidManifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="me.soft.myapp">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="myapp"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ServiceTry"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".TheService" />
    </application>

</manifest>

Solution

  • You need to use a foreground service. Background services are killed after 2 minutes if the foreground application isn't using the service.Foreground service can last for a long time unless the phone goes very low on resources. to do that use startForegroundService to launch the service, and have the service's onStartCommand call startForeground as well.