Kotlin读取音频文件信息工具类

调用这个方法前记得判断文件读取权限
import android.content.Context
import android.media.MediaMetadataRetriever
import android.media.MediaPlayer
import android.os.Environment
import android.provider.MediaStore
import androidx.core.content.ContextCompat
import me.zempty.common.R
import java.io.File


/**
 * @Description: 把对于音频文件的文件获取方式单独当做一个类提取出来
 * @Author: dk
 * @Date: 2021/7/9 11:04 AM
 * @Gmail: dk.guo@tron.network
 */
data class Song(
    //歌曲名
    var song: String = "",
    //歌手
    var singer: String = "",
    //歌曲所占空间大小 单位 byte
    var size: Long = 0,
    //歌曲时间长度 单位 ms
    var duration: Int = 0,
    //歌曲地址 /storage/emulated/0/package/name.mp3
    var path: String = ""
)

private val songSuffix = arrayListOf("MP3", "AAC", "M4A", "MP4", "WAV", "3GP")

/**
 * 时长低于10s的不再加入列表
 */
private val MIN_AUDIO_DURATION = 10 * 1000

//调用这个方法前记得判断文件读取权限
//记得在子线程调用
fun Context.getMusics(): MutableList<Song> {
    val list = ArrayList<Song>()
    //优先调用系统的音频路径
    val cursor = contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.AudioColumns.IS_MUSIC)
    if (cursor != null) {
        while (cursor.moveToNext()) {
            val song = Song()
            song.song = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME))
            song.singer = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST))
            song.path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA))
            song.duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION))
            song.size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE))
            if (song.song.contains("-")) {
                val str: Array<String> = song.song.split("-").toTypedArray()
                if (str.size > 1) {
                    song.singer = str[0].trim()
                    val songName = str[1].trim()
                    song.song = if (songName.contains('.')) {
                        songName.dropLast(songName.length - songName.lastIndexOf('.'))
                    } else {
                        songName
                    }
                } else {
                    song.song = str[0]
                    song.singer = getString(R.string.unknown_singer)
                }
            }
            logD("MusicFileExt->" + song.toJson())
            if (song.duration > MIN_AUDIO_DURATION) {
                list.add(song)
            }
        }
        cursor?.close()
    } else {
        //作为cursor无法正常创建的备选方案 该方案获取文件速度很慢 主要原因是音频时长的获取方式在主线程执行
        //在部分机型或者高版本上下面的方法可能无法调用,优先使用上面的方法
        val hasSDCard = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
        val firstPath = if (hasSDCard) Environment.getExternalStorageDirectory() else filesDir.absoluteFile
        val secondPath = getExternalFilesDir(null)?.absoluteFile
        var songFileList = findSong(firstPath)
        if (songFileList.isEmpty() && secondPath != null) {
            songFileList = findSong(secondPath)
        }
        list.addAll(getSongInfoWithFile(songFileList, this))
    }
    return list
}

private fun findSong(file: File): ArrayList<File> {
    val arrayList = ArrayList<File>()
    file.listFiles()?.forEach { singleFile ->
        val suffix = singleFile.name.split(".").lastOrNull()
        if (singleFile.isDirectory && !singleFile.isHidden) {
            arrayList.addAll(findSong(singleFile))
        } else if (songSuffix.find { it.equals(suffix, true) } != null) {
            arrayList.add(singleFile)
        }
    }
    return arrayList
}

private fun getSongInfoWithFile(files: MutableList<File>, context: Context): MutableList<Song> {
    val mediaPlayer = MediaPlayer()
    val mmr = MediaMetadataRetriever()
    val songs = ArrayList<Song>()
    files.forEach { file ->
        val song = Song()
        song.path = file.absolutePath
        song.size = file.length()
        if (file.name.contains("-")) {
            val split = file.name.split("-")
            if (split.size > 1) {
                song.singer = split[0].trim()
                val songName = split[1].trim()
                song.song = if (songName.contains('.')) {
                    songName.dropLast(songName.length - songName.lastIndexOf('.'))
                } else {
                    songName
                }
            } else {
                song.song = file.name
                song.singer = context.getString(R.string.unknown_singer)
            }
        } else {
            song.song = file.name
            song.singer = context.getString(R.string.unknown_singer)
        }
        //这个获取时长的方法会造成卡顿,如果不是强制需要时长,尽量不要调用
        try {
            mmr.setDataSource(file.absolutePath)
            song.duration = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION).number()
            if (song.duration == 0) {
                song.duration = readDurationWithMediaPlayer(mediaPlayer, file)
            }
        } catch (e: Exception) {
            song.duration = readDurationWithMediaPlayer(mediaPlayer, file)
        }
        if (song.duration > MIN_AUDIO_DURATION) {
            songs.add(song)
        }
    }
    if (mediaPlayer != null) {
        mediaPlayer.stop()
        mediaPlayer.reset()
        mediaPlayer.release()
    }
    return songs
}

private fun readDurationWithMediaPlayer(mediaPlayer: MediaPlayer, file: File): Int {
    var duration = 0
    try {
        mediaPlayer.setDataSource(file.absolutePath)
        mediaPlayer.prepare()
        duration = mediaPlayer.getDuration()
    } catch (e: Exception) {
        logE("file->${file.absolutePath} read media duration failed, message-> ${e.message}")
    }
    return duration
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值