AudioPlaybackCapture结合AudioRecord实现音频内录

您所在的位置:网站首页 系统内录音app AudioPlaybackCapture结合AudioRecord实现音频内录

AudioPlaybackCapture结合AudioRecord实现音频内录

#AudioPlaybackCapture结合AudioRecord实现音频内录| 来源: 网络整理| 查看: 265

现在很多安卓手机都自带了录音机或者屏幕录制功能,但是系统自带的录音机是录制麦克风声音;而系统的屏幕录制又是录制的视频,仅需要系统声音的话,使用其他第三方剪辑软件把声音单独剪出来。如果你恰恰只需要录制手机本身发出的声音,那么本文应该对你有些帮助。

在安卓5.0的时候,系统就开放了视频录制接口:MediaProjection 和 MediaProjectionManager,到了安卓10.0的时候系统又提供了音频捕捉接口AudioPlaybackCapture,有了这个接口我们就可以实现对系统播放的音频进行录制了。

AndroidManifest配置

申请和声明必要的用户权限,注意高版本在kt或者java代码中动态申请。

AndroidManifest.xml中配置允许音频播放捕获

Activity中向用户申请录制授权 首先是向用户申请授权。 val mProjectionManager = this.getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager val screenCaptureIntent = mProjectionManager.createScreenCaptureIntent() startActivityForResult(screenCaptureIntent, reqCode)

注意,此时弹出系统弹窗,该弹窗的样式是无法改变的,主要是为了保护用户隐私,防止钓鱼违规录音。

在用户同意授权之后,我们会在onActivityResult中收到回调。然后启动音频录制的service override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == reqCode && resultCode == Activity.RESULT_OK) { val intent = Intent(this, RecordService::class.java) intent.putExtra("resultData", data) intent.putExtra("resultCode", resultCode) startForegroundService(intent) } } service中执行录音功能 定义通知栏 override fun onCreate() { super.onCreate() EventBus.getDefault().register(this) initNotification() } ... ... ... /** * 初始化通知栏 */ private fun initNotification() { val builder: Notification.Builder val channelID = "MRecordService" val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager val channel = NotificationChannel(channelID, "录音服务", NotificationManager.IMPORTANCE_HIGH) channel.enableLights(true) //设置提示灯 channel.lightColor = Color.RED //设置提示灯颜色 channel.setShowBadge(true) //显示logo channel.description = "MRecordService Notification" //设置描述 channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC //设置锁屏可见 VISIBILITY_PUBLIC=可见 manager.createNotificationChannel(channel) builder = Notification.Builder(this, channelID) val notification = builder.setAutoCancel(false) .setContentTitle("录音服务") //标题 .setContentText("录音服务正在运行...") //内容 .setWhen(System.currentTimeMillis()) .setSmallIcon(R.mipmap.ic_launcher) //设置小图标 .setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))//设置大图标 .build() startForeground(1, notification) } 初始化录音机 ... override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { val currentResultCode = intent.getIntExtra("resultCode", 0) val resultData = intent.getParcelableExtra("resultData") initAudioRecord(currentResultCode, resultData) return super.onStartCommand(intent, flags, startId) } ... ... /** * 初始化录音器 */ private fun initAudioRecord(resultCode: Int, intent: Intent) { minBufferSize = AudioRecord.getMinBufferSize(mSampleRateInHZ, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT) val mediaProjectionManager = baseContext.getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager //设置应用程序录制系统音频的能力 val mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, intent) val builder = AudioRecord.Builder() builder.setAudioFormat(AudioFormat.Builder() .setSampleRate(mSampleRateInHZ) //设置采样率(一般为可选的三个-> 8000Hz 、16000Hz、44100Hz) .setChannelMask(AudioFormat.CHANNEL_IN_MONO) //音频通道的配置,可选的有-> AudioFormat.CHANNEL_IN_MONO 单声道,CHANNEL_IN_STEREO为双声道,立体声道,选择单声道就行 .setEncoding(AudioFormat.ENCODING_PCM_16BIT).build()) //音频数据的格式,可选的有-> AudioFormat.ENCODING_PCM_8BIT,AudioFormat.ENCODING_PCM_16BIT .setBufferSizeInBytes(minBufferSize) //设置最小缓存区域 val config = AudioPlaybackCaptureConfiguration.Builder(mediaProjection) .addMatchingUsage(AudioAttributes.USAGE_MEDIA) //设置捕获多媒体音频 .addMatchingUsage(AudioAttributes.USAGE_GAME) //设置捕获游戏音频 .build() //将 AudioRecord 设置为录制其他应用播放的音频 builder.setAudioPlaybackCaptureConfig(config) try { if (ContextCompat.checkSelfPermission(this,Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) { audioRecord = builder.build() } } catch (e: Exception) { e.printStackTrace() LogUtils.e("录音器错误", "录音器初始化失败") } //做完准备工作,就可以开始录音了 startRecord() } 开始录音,保存录音 ... /** * 开始录音 */ private fun startRecord() { if (isRecording) { ToastUtils.showShort("已经在录音了") return } ToastUtils.showShort("开始录音了") isRecording = true //承接音频数据的字节数组 val mAudioData = ByteArray(320) //保存到本地录音文件名 val tmpName = System.currentTimeMillis().toString() //新建文件,承接音频数据 val tmpFile = Utils.createFile("$tmpName.pcm") //新建文件,后面会把音频数据转换为.wav格式,写入到该文件 val tmpOutFile = Utils.createFile("$tmpName.wav") //开始录音 audioRecord?.startRecording() Thread { try { val outputStream = FileOutputStream(tmpFile.absoluteFile) while (isRecording) { //循环从音频硬件读取音频数据录制到字节数组中 audioRecord?.read(mAudioData, 0, mAudioData.size) //将字节数组写入到tmpFile文件 outputStream.write(mAudioData) } outputStream.close() //将.pcm文件转换为.wav文件 Utils.pcmToWave(mSampleRateInHZ.toLong(), minBufferSize, tmpFile.absolutePath, tmpOutFile.absolutePath) } catch (e: IOException) { e.printStackTrace() } }.start() } 停止录音

我们可以在activity中发出停止录音的消息,service接收到该消息之后,执行停止录音。我这里用的是EventBus

... ... @Subscribe(threadMode = ThreadMode.POSTING) fun OnEvent(event: String?) { if (TextUtils.equals(event, "stop")) { ToastUtils.showShort("停止录音了") isRecording = false audioRecord!!.stop() } } ps:参考,感谢: Android录音(AudioRecord)保存本地 Android Q及以上系统音频捕获功能(声音内录)的简单实现)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3