Search code examples
androidkotlinexoplayer2.xaudio-processing

ExoPlayer: Custom AudioProcessor - Equalizer


I'm working on an ExoPlayer based media player for Android, and I'm attempting to write my own Equalizer.

I've looked fairly deeply into ExoPlayer, and I believe the best place to manipulate samples in order to apply Equalier changes, is in a custom AudioProcessor.

I've used ChannelMappingAudioProcessor as a starting point, and cloned what I think are the relevant aspects:

class EqualizerAudioProcessor : BaseAudioProcessor() {

        private lateinit var outputChannels: IntArray

        override fun configure(sampleRateHz: Int, channelCount: Int, encoding: Int): Boolean {
            outputChannels = IntArray(channelCount)
            for (i in 0 until channelCount) {
                outputChannels[i] = i
            }
            return true
        }

        override fun isActive(): Boolean {
            return true
        }

        override fun getOutputChannelCount(): Int {
            return outputChannels.size
        }

        override fun queueInput(inputBuffer: ByteBuffer) {
            var position = inputBuffer.position()
            val limit = inputBuffer.limit()
            val frameCount = (limit - position) / (2 * channelCount)
            val outputSize = frameCount * outputChannels.size * 2
            val buffer = replaceOutputBuffer(outputSize)
            while (position < limit) {
                for (element in outputChannels) {
                    var sample = inputBuffer.getShort(position + 2 * element)
                    // Todo: Manipulate sample
                    buffer.putShort(sample)
                }
                position += channelCount * 2
            }
            inputBuffer.position(limit)
            buffer.flip()
        }

        override fun onReset() {

        }
    }

It seems that if I enable this AudioProcessor, playback doesn't occur (it seems stuck in a 'paused state', as if the samples aren't being passed along, and interestingly, queueInput() is not called. If I disable the AudioProcessor, playback works fine.

I'm hoping someone can help me understand if I'm making a mistake here, and how to get this working.

For reference, the ExoPlayer instance is initialised like so:

    private fun initPlayer(context: Context): ExoPlayer {

        val audioProcessor = EqualizerAudioProcessor()

        val renderersFactory = object : DefaultRenderersFactory(context) {
            override fun buildAudioProcessors(): Array<AudioProcessor> {
                return arrayOf(audioProcessor)
            }
        }

        val player: SimpleExoPlayer = ExoPlayerFactory.newSimpleInstance(
            context,
            renderersFactory,
            DefaultTrackSelector(),
            DefaultLoadControl()
        )

        player.addListener(object : Player.EventListener {
            override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
                callback?.onPlayStateChanged(playWhenReady)
            }
        })

        return player
    }

Thanks in advance


Solution

  • The problem is that you must call setInputFormat() in configure() of the AudioProcessor, or queueInput() will not be called.