epic
epic

Reputation: 1443

Long running service with large amount of data transfer to activity

I am using USB to communicate audio and video from some external hardware.

Video is displayed on a Surface as long as the app is in foreground but audio should keep playing even when in background.

Using threads doesn't seem to work, when the app goes to background the audio starts to stutter and sound very bad. I believe i need to use a service, am i wrong?

But from all the online documentation i can't figure out, what is the best type of service (or any) to use for such long running application and the best way to communicate the large amount of data between its Activity & Surface?

I looked into plain services, WorkManagers, ForegroundService, ServiceSocket and many others

Here is the current code i am using to run the streamed audio from the USB. It is using a coroutine and as said, audio starts to stutter when app in background

   class AudioTrackPlayer {
    
        private val channel = Channel<Boolean>(capacity = 15)
        private var dataList = mutableListOf<ByteArray>()
        private var readIndex = 0
        private var writeIndex = 0
        private val scope = CoroutineScope(Job() + Dispatchers.IO)
        private var audio: AudioTrack? = null
        var lastSize = 0
        var isPlaying = false
    
        companion object {
            private const val DATA_LIST_SIZE = 11
        }
    
        init {
            scope.launch {
                startThread()
            }
        }
    
        fun config(channels: Int, sampleRate: Int):Boolean {
             //......
        }
    
        private suspend fun startThread() = withContext(Dispatchers.IO) {
            var data:ByteArray
            var isPlayingLast = false
            var finalByteArray:ByteArray
    
            channel.consumeEach {
                if (audio != null) {
                    if (isPlaying) {
                        if (readIndex != writeIndex) {
                            isPlayingLast = true
                            data = dataList[readIndex]
                            lastSize = data.size - 8
    
                            if (audio?.playState != AudioTrack.PLAYSTATE_PLAYING) {
                                audio?.play()
                            }
    
                            audio?.write(data, 8, lastSize)
    
                            readIndex++
    
                            if (readIndex == DATA_LIST_SIZE) {
                                readIndex = 0
                            }
                        } 
                    } else {
                        if (isPlayingLast) {
                            isPlayingLast = false
                            finalByteArray = ByteArray(lastSize * 2)
                            if (audio?.playState != AudioTrack.PLAYSTATE_PLAYING) {
                                audio!!.play()
                            }
                            audio!!.write(finalByteArray, 0, finalByteArray.size)
                            audio!!.stop()
                            audio!!.flush()
                            writeIndex = readIndex
                        }
                    }
                } 
            }
        }
    
        fun write(data: ByteArray) {
            scope.launch {
                if (isPlaying) {
                    dataList.add(writeIndex, data)
                    writeIndex++
                    if (writeIndex == DATA_LIST_SIZE) {
                        writeIndex = 0
                    }
                    channel.send(true)
                } 
            }
        }
    
        fun play() {
            //...
        }
    
        fun stop() {
            //....
        }
    }

Upvotes: 1

Views: 44

Answers (0)

Related Questions