Требования к Discord Bot
Для работы с дискорд-ботами я использую Kord. Его требования к передаваемым данным описаны в документации:
Кадр 20-миллисекундных стереоаудиоданных 48k, закодированных Opus.
< /blockquote>
Настройки кодека
Исходя из этого, я установил следующие настройки кодека, согласно требованию:
@OptIn(UnstableApi::class)
class BotAudioProcessor(
private val audioDataListener: AudioDataListener
): BaseAudioProcessor(){
val codec = Opus()
val SAMPLE_RATE = Constants.SampleRate._48000()
val CHANNELS = Constants.Channels.stereo()
val APPLICATION = Constants.Application.audio()
val FRAME_SIZE = Constants.FrameSize._960()
val COMPLEXITY = Constants.Complexity.instance(10)
val BITRATE = Constants.Bitrate.max()
init {
codec.encoderInit(SAMPLE_RATE, CHANNELS, APPLICATION)
codec.encoderSetComplexity(COMPLEXITY)
codec.encoderSetBitrate(BITRATE)
}
override fun onConfigure(inputFormat: AudioProcessor.AudioFormat): AudioProcessor.AudioFormat {
val outputFormat = AudioProcessor.AudioFormat(
SAMPLE_RATE.v,
CHANNELS.v,
C.ENCODING_PCM_16BIT
)
return outputFormat
}
//... queueInput()
}
Здесь я задал все параметры, как того требует документация. Все эти значения были заданы через кодек, единственное, что я потратил час на расчет размера кадра
frame size = SAMPLE_RATE * 0.02 (20ms) = 960
Получение потокового аудио
Если я правильно понимаю, несжатые потоки PCM можно получить с помощью AudioProcessor, для этого я наследуюсь от BaseAudioProcessor и переопределяю метод queueInput, в котором Я кодирую буфер в формате Opus, а затем передаю его прослушивателю, который отправит поток боту Discord.
override fun queueInput(inputBuffer: ByteBuffer) {
if (inputBuffer.remaining() < FRAME_SIZE.v / 2) {
Log.e("BotAudioProcessor", "Input buffer too small")
return
}
val frame = ShortArray( FRAME_SIZE.v / 2)
inputBuffer.asShortBuffer().get(frame)
val encoded = codec.encode(frame, FRAME_SIZE)
audioDataListener.onAudioData(encoded!!.toByteArray())
}
Передача данных боту
Далее полученный аудиопоток сохраняется в переменной, которая затем транслируется ботом.
@UnstableApi
class MusicBot(...) : AudioDataListener {
private var audioData: ByteArray? = null
//...
@OptIn(KordVoice::class)
suspend fun start() {
kord!!.on {
//...
voiceChannel.connect {
audioProvider {
println(audioBuffer?.joinToString(" "))
println(audioBuffer?.size)
audioBuffer?.let { AudioFrame(it) }
}
}
}
}
override fun onAudioData(data: ByteArray) {
audioBuffer = data
}
}
Ссылки и дополнительно
- Библиотека Kord: https://github.com/kordlib/kord/tree/main /voice
- Кодек Opuc: https://github.com/theeasiestway/android-opus-codec
- использовать аудиопроцессор: https://github .com/google/ExoPlayer/issues/8342
@OptIn(UnstableApi::class)
class DiscordRendersFactory
(
context: Context,
private val audioDataListener: AudioDataListener
) : DefaultRenderersFactory(context) {
override fun buildAudioSink(
context: Context,
enableFloatOutput: Boolean,
enableAudioTrackPlaybackParams: Boolean
): AudioSink {
val defaultAudioSink = DefaultAudioSink.Builder()
.setAudioProcessors(arrayOf(BotAudioProcessor(audioDataListener)))
.setEnableFloatOutput(true)
.setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams)
.build()
return defaultAudioSink
}
}
Подробнее здесь: https://stackoverflow.com/questions/791 ... iscord-bot