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>