基于大疆MSDK V5实现喊话器播放本地mp3文件

566 阅读1分钟

大疆MSDK V5为喊话器封装了MegaphoneManager管理类,简化了各种型号的喊话器对接工作。MegaphoneManager对音频统一采用opus编码,V5 Sample中也提供了录音音频opus编码的方法,但是缺失mp3转opus编码的相关方法。本文提供一种mp3转opus的方案:mp3->pcm->opus。

FFmpeg命令

Mobile-ffmpeg

implementation 'com.arthenica:mobile-ffmpeg-full:4.4'

mp3转pcm

val file1 = "${PathUtils.getExternalStoragePath()}/record/AudioFile/test.mp3"
val file2 = "${PathUtils.getExternalStoragePath()}/record/AudioFile/ffmpegConvert.pcm"

//利用ffmpeg命令将mp3转为pcm,并将采样率修改为16000
val cmd = "-i $file1 -f s16le -ar 16000 -ac 1 -acodec pcm_s16le -y $file2"
FFmpeg.executeAsync(cmd,object :ExecuteCallback{
    override fun apply(executionId: Long, returnCode: Int){
    }
})

pcm转opus

  • 读取pcm文件
 private fun convertMP3() {
    val file1 = "${PathUtils.getExternalStoragePath()}/record/AudioFile/test_le.pcm"
    launch(Dispatchers.IO) {
        readPcmFrames(file1)
            .flowOn(Dispatchers.IO)
            .buffer()
            .collect { bytes->
                convertPcmData(bytes)
            }
    }
}
//opus编码对每一帧的数据大小做了限制,固定为1280
fun readPcmFrames(filePath: String, frameSize: Int = 1280): Flow<ByteArray> = flow {
    val file = File(filePath)
    val inputStream = file.inputStream()
    val buffer = ByteArray(frameSize)
    var bytesRead:Int
    while ((inputStream.read(buffer).also { bytesRead = it }) != -1) {
        emit(buffer.copyOf(bytesRead)) // 发射当前帧的数据
        delay(35) //opus编码接受能力有限,利用延迟防止数据丢失
    }
    inputStream.close()
}
  • opus编码
fun initEncoder(dstPath:String) {
    //初始化opus文件存储位置
    mAudioBos = BufferedOutputStream(FileOutputStream(dstPath))
    //初始化opus编码器
    opusEncoder = OpusEncoder()
    val audioConfig = AudioConfig()
    audioConfig.audioChannelCount = 1 //通道数
    audioConfig.audioSampleRate = 16000 //采样率
    audioConfig.audioFormat = AudioFormat.ENCODING_PCM_16BIT
    audioConfig.bufferSize = 2560
    opusEncoder!!.config(audioConfig)
    opusEncoder!!.setEncodedDataCallback(object : EncodedDataCallback {
        override fun onAudioEncodedCallback(
        data: ByteArray?,size: Int) {
            //opus编码后的数据大小为160
            mAudioBos?.write(data)
        }
    })
    opusEncoder!!.start()
}
//转换pcm数据
fun convertPcmData(bytes: ByteArray) {
    opusEncoder?.putData(bytes)
}