android Kotlin 实现pcm音频数据的存储和播放

AndroidManifest.xml 权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

build.gradle --用了第三方管理动态权限申请的库

implementation 'com.yanzhenjie:permission:2.0.0-rc4'


下面是代码很简单:

    主界面Main,布局文件就是4个button

class MainActivity3 : AppCompatActivity(), View.OnClickListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
        AndPermission.with(this@MainActivity3).permission(Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE).onGranted(object : Action {
            override fun onAction(permissions: MutableList?) {//同意权限
                var rootDir: File = File(AudioConfig.rootDir)
                var audioFile: File = File(AudioConfig.audioPath)
                if (!rootDir.exists()) {
                    var isDir = rootDir.mkdir()
                    if (!isDir) {
                        Toast.makeText(this@MainActivity3, "创建文件夹失败", Toast.LENGTH_SHORT).show()
                        return
                    }
                }
                if (!audioFile.exists()) {
                    var isFile = audioFile.createNewFile()
                    if (isFile) {
                        Toast.makeText(this@MainActivity3, "创建文件成功", Toast.LENGTH_SHORT).show()
                    } else {
                        Toast.makeText(this@MainActivity3, "创建文件失败", Toast.LENGTH_SHORT).show()
                        return
                    }
                }
            }

        }).onDenied(object : Action {
            //拒绝权限
            override fun onAction(permissions: MutableList?) {
                Toast.makeText(this@MainActivity3, "没有权限", Toast.LENGTH_SHORT).show()
            }

        }).start()

        btn_start.setOnClickListener(this)
        btn_stop.setOnClickListener(this)
        btn_play.setOnClickListener(this)
        btn_post.setOnClickListener(this)
    }

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.btn_start -> {
                AudioRecordManager.isAudioRecord = true
                var audioRecord = AudioRecordManager()
                audioRecord.start()

            }
            R.id.btn_stop -> {
                AudioRecordManager.isAudioRecord = false
            }
            R.id.btn_play -> {
                AudioTrackManager.isPaly = true
                var audioTrack = AudioTrackManager()
                audioTrack.start()

            }
            R.id.btn_post -> {
                AudioTrackManager.isPaly = false
            }
        }
    }
}

参数配置类:

class AudioConfig {
    companion object {
        val frequency:Int = 11025 //采样率
        val audioFormat:Int = AudioFormat.ENCODING_PCM_16BIT //数据位宽
        val channelConfig:Int = AudioFormat.CHANNEL_OUT_STEREO;//双通道
        val rootDir:String = Environment.getExternalStorageDirectory().absolutePath+"/kotlinAudio";
        val audioPath:String = rootDir+"/kotlining.pcm"
    }
}



录音:


class AudioRecordManager : Thread() {
    companion object {
        var isAudioRecord: Boolean = true
    }

    val bufferSize: Int = AudioRecord.getMinBufferSize(AudioConfig.frequency, AudioConfig.channelConfig, AudioConfig.audioFormat)
    val audioRecord: AudioRecord = AudioRecord(MediaRecorder.AudioSource.MIC, AudioConfig.frequency, AudioConfig.channelConfig, AudioConfig.audioFormat, bufferSize)
    lateinit var dataOutput: DataOutputStream
    override fun run() {
        super.run()
        val audioFile: File = File(AudioConfig.audioPath)
        if (!audioFile.exists()) {
            Log.d(">>>>>>>>", ">>>>>文件不存在>>>>")
            return
        }
        try {
            audioRecord.startRecording()
            dataOutput = DataOutputStream(BufferedOutputStream(FileOutputStream(audioFile)))
            val buffer = ShortArray(bufferSize)
            audioRecord.startRecording()
            while (isAudioRecord) {
                val bufferReadResult = audioRecord.read(buffer, 0, bufferSize)
                Log.d("cccc======", "cccc=====result:" + bufferReadResult + "////size:" + buffer.size)
                for (i in 0 until bufferReadResult) {
                    dataOutput.writeShort(buffer[i].toInt())
                }
            }
            audioRecord.stop()
            dataOutput.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }
}


播放:


class AudioTrackManager :Thread(){
    companion object {
        var isPaly:Boolean = true
    }
    val bufferSize: Int = AudioTrack.getMinBufferSize(AudioConfig.frequency, AudioConfig.channelConfig, AudioConfig.audioFormat)
    val buffer = ShortArray(bufferSize / 4)
    lateinit var dataInputStream: DataInputStream
    val audioTrack:AudioTrack = AudioTrack(AudioManager.STREAM_MUSIC, AudioConfig.frequency, AudioConfig.channelConfig, AudioConfig.audioFormat, bufferSize, AudioTrack.MODE_STREAM)

    override fun run() {
        super.run()
        val audioFile: File = File(AudioConfig.audioPath)
        if (!audioFile.exists()) {
            Log.d(">>>>>>>>", ">>>>>文件不存在>>>>")
            return
        }
        try {
            dataInputStream = DataInputStream(BufferedInputStream(FileInputStream(audioFile)))
            audioTrack.play()
            while (isPaly && dataInputStream.available() > 0) {
                var i:Int = 0
                while (dataInputStream.available() > 0 && i < buffer.size) {
                    buffer[i] = dataInputStream.readShort();
                    i++;
                }
                audioTrack.write(buffer, 0, buffer.size);
            }
            dataInputStream.close();
            audioTrack.release()
            audioTrack.stop()
        }catch (e:Exception){
            e.stackTrace
        }
    }
}


布局文件xml:


xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="test.myapplication.MainActivity2">

    <Button
        android:id="@+id/btn_start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="开始录音" />

    <Button
        android:id="@+id/btn_stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="停止录音" />

    <Button
        android:id="@+id/btn_play"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="播放录音" />

    <Button
        android:id="@+id/btn_post"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="停止播放" />
LinearLayout>

你可能感兴趣的:(android Kotlin 实现pcm音频数据的存储和播放)