Android12 Native C++ 层AudioRecord录音AudioTrack播放
一、背景:
发现网上能搜到的都是几年前的例子,现在Android版本都出到12了,几年前的例子以及不适用新版本了。于是就自己研究了下AudioRecord.java是如何调用到jni和C++层的AudioRecord.cpp。做一下记录为后来者避坑(PS:以前都不喜欢写博客,本人没时间也不太想分享)。改demo应该适用于Android8,Android9,Android10,Android11,Android12。或许过个几年到Androidxx又不适用了。
二、遇到比较有意思的坑:
程序运行没有报错但是录音没有声音,dump文件拉到电脑播放也是一条直线没有声音。后来分析是google基于安全 权限考虑做的限制。会根据uid,ui是否在前台等对AudioRecord进行静音。
解决方法有两个:
1. 注释掉:void AudioFlinger::setRecordSilenced(audio_port_handle_t portId, bool silenced)函数静音代码。
2. 使用 audio_source_t inputSource =AUDIO_SOURCE_HOTWORD;//AUDIO_SOURCE_MIC;
在老版本Android是使用AUDIO_SOURCE_MIC类型的。这里因为是c++ native没有ui界面等所以必须使用AUDIO_SOURCE_HOTWORD类型,否则 AudioRecord录音没有声音。
三、Demo源码:
例子有点乱,没有整理。AudioTrack是基于framework目录下AudioTrack共享内存例子修改的。
AudioRecord没有原生例子,只能自己研究了。
demo_test:
#define LOG_NDEBUG 0
#define LOG_TAG "demo_test"#include <stdlib.h>
#include <stdio.h>
#include <cutils/properties.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
#include <media/AudioRecord.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <media/AidlConversion.h>#include <utils/Log.h>#include <fcntl.h>
#include "demo_test.h"
#define SOUND_LENGTH 18470
volatile bool g_bQuitAudioRecordThread = false;
int g_iNotificationPeriodInFrames = 8000/10;
void StartAudioRecordThread();
void StopAudioRecordThread();
void * inBuffer = NULL;
int myreadlen = 0;
int mywritelen = 0;
int bufferSizeInBytes = 1600;
#define SAMPLE_RATE 16000// 这里必须使用 AUDIO_SOURCE_HOTWORD 否则录音无声,或者把 void AudioFlinger::setRecordSilenced(audio_port_handle_t portId, bool silenced)
//函数注释为空。
audio_source_t inputSource = AUDIO_SOURCE_HOTWORD;//AUDIO_SOURCE_HOTWORD;//AUDIO_SOURCE_MIC;
static const audio_attributes_t pAttributes = {
/* .content_type = */ AUDIO_CONTENT_TYPE_UNKNOWN, // 0
/* .usage = */ (audio_usage_t)AUDIO_USAGE_UNKNOWN, // 0
/* .source = */ inputSource, // 1
/* .flags = */ AUDIO_FLAG_MUTE_HAPTIC,// 0x00000800 //AUDIO_FLAG_NONE,
/* .tags = */ "demo_test"
};
static android::content::AttributionSourceState attributionSource;namespace android {void AudioRecordCallback(int event, void* user, void *info)
{char *p;if(user)p = (char *)user;if(event == android::AudioRecord::EVENT_NEW_POS){ ALOGD(" android::AudioRecord::EVENT_NEW_POS \n");//if(g_iInSampleTime > g_iNotificationPeriodInFrames*100)// g_bQuitAudioRecordThread = true;}else if (event == android::AudioRecord::EVENT_MORE_DATA){ ALOGD(" android::AudioRecord::EVENT_MORE_DATA..... \n");android::AudioRecord::Buffer* pBuff = (android::AudioRecord::Buffer*)info;pBuff->size = 0;}else if (event == android::AudioRecord::EVENT_OVERRUN){ALOGD(" EVENT_OVERRUN \n");}
}
#if 1
static void AudioRecordThread()
{audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; // 1audio_channel_mask_t channelConfig = AUDIO_CHANNEL_IN_MONO;//AUDIO_CHANNEL_IN_MONO; //AUDIO_CHANNEL_IN_STEREO; int sampleRateInHz = SAMPLE_RATE; sp<AudioRecord> pAudioRecord = 0;FILE * g_pAudioRecordFile = NULL;char strAudioFile[] = "/sdcard/AudioRecordFile.pcm";int iNbChannels = 1; // 1 channel for mono, 2 channel for streoint iBytesPerSample = 2; // 16bits pcm, 2Bytesint frameSize = 0; // frameSize = iNbChannels * iBytesPerSamplesize_t minFrameCount = 0; // get from AudroRecord objectg_pAudioRecordFile = fopen(strAudioFile, "wb+"); iNbChannels = (channelConfig == AUDIO_CHANNEL_IN_STEREO) ? 2 : 1;frameSize = iNbChannels * iBytesPerSample; android::status_t status = AudioRecord::getMinFrameCount(&minFrameCount, sampleRateInHz, audioFormat, channelConfig); if(status != android::NO_ERROR){ALOGD("%s AudioRecord.getMinFrameCount fail \n", __FUNCTION__);}// sampleRateInHz = 16000 minFrameCount = 768 iNbChannels = 2 frameSize = 4ALOGD("sampleRateInHz = %d minFrameCount = %d iNbChannels = %d frameSize = %d ",sampleRateInHz, (int)minFrameCount, iNbChannels, frameSize); bufferSizeInBytes = (int)minFrameCount * frameSize;//bufferSizeInBytes = 2*SOUND_LENGTH;g_iNotificationPeriodInFrames = sampleRateInHz/10; String16 opPackageName("demo_test");uid_t uid = -1;pid_t pid = -1;attributionSource.packageName = VALUE_OR_FATAL(legacy2aidl_String16_string(opPackageName));attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t((unsigned int)uid));attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t((int)pid));attributionSource.token = sp<BBinder>::make();pAudioRecord = new AudioRecord(attributionSource); if(NULL == pAudioRecord){ALOGD(" create native AudioRecord failed! ");} audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;// 0audio_session_t sessionId = (audio_session_t)0;int sharedAudioHistoryMs = 0;status_t status2 =pAudioRecord->set(pAttributes.source, sampleRateInHz,audioFormat, // word length, PCMchannelConfig, 768,AudioRecordCallback, // callback_tNULL, // void* user0, // notificationFrames,true, // threadCanCallJavasessionId, AudioRecord::TRANSFER_DEFAULT, flags, -1,-1, // default uid, pid&pAttributes, AUDIO_PORT_HANDLE_NONE, MIC_DIRECTION_UNSPECIFIED,MIC_FIELD_DIMENSION_DEFAULT, sharedAudioHistoryMs);if (status2 != NO_ERROR) {ALOGE("Error creating AudioRecord instance: initialization check failed with status2 %d.",status2);}pAudioRecord->setCallerName("demo_test"); if(pAudioRecord->initCheck() != android::NO_ERROR) {ALOGD("AudioTrack initCheck error!");}if(pAudioRecord->setPositionUpdatePeriod(g_iNotificationPeriodInFrames) != android::NO_ERROR){ALOGD("AudioTrack setPositionUpdatePeriod error!");}if(pAudioRecord->start()!= android::NO_ERROR){ALOGD("AudioTrack start error!");} int i = 0;int readLen = 0;while (!g_bQuitAudioRecordThread){readLen = pAudioRecord->read((uint8_t*)inBuffer+i*readLen, 320/*bufferSizeInBytes*/, 1);int writeResult = -1;if(readLen > 0){myreadlen += readLen;if ( myreadlen > 7*SOUND_LENGTH ) {ALOGD("pAudioRecord->read end");break;}//iWriteDataCount += readLen;if(NULL != g_pAudioRecordFile){writeResult = fwrite((uint8_t*)inBuffer+i*readLen, 1, readLen, g_pAudioRecordFile); if(writeResult < readLen){ALOGE("Write Audio Record Stream error");}mywritelen += writeResult;}i++; }else{ALOGD("pAudioRecord->read readLen = 0");}}ALOGD("myreadlen = %d mywritelen = %d\n", myreadlen, mywritelen); if(pAudioRecord){pAudioRecord->stop();}if(NULL != g_pAudioRecordFile){fflush(g_pAudioRecordFile);fclose(g_pAudioRecordFile); g_pAudioRecordFile = NULL; }
}#endif/************************************************************
*
* Constructor
*
************************************************************/
AudioTrackTest::AudioTrackTest(void) {ALOGD("01 AudioTrackTest\n");}/************************************************************
*
*
************************************************************/
void AudioTrackTest::Execute(void) {if (Test01() == 0) {ALOGD("01 passed\n");} else {ALOGD("01 failed\n");}
}/************************************************************
*
* Shared memory test
*
************************************************************/
#define BUF_SZ 44100int AudioTrackTest::Test01() {bufferSizeInBytes = 10*SOUND_LENGTH;inBuffer = malloc(bufferSizeInBytes);if(inBuffer == NULL){ ALOGD("%s alloc mem failed \n", __FUNCTION__); }memset(inBuffer, 0, bufferSizeInBytes);uint8_t* buf = (uint8_t*)inBuffer;long sampleRate = SAMPLE_RATE;size_t framecount = 16;AudioRecordThread();if (AudioTrack::getMinFrameCount(&framecount, AUDIO_STREAM_MUSIC, sampleRate) != NO_ERROR ) {ALOGD("Error: cannot compute output frame count\n");return -1;}ALOGD("framecount = %d \n", (int)framecount);sp<AudioTrack> track = new AudioTrack(AUDIO_STREAM_MUSIC,// stream typesampleRate,AUDIO_FORMAT_PCM_16_BIT,// word length, PCMAUDIO_CHANNEL_OUT_MONO, // AUDIO_CHANNEL_OUT_STEREO0);status_t status = track->initCheck();if(status != NO_ERROR) {track.clear();ALOGD("Failed for initCheck()");return -1;}// start playALOGD("start");track->start();for(int j = 0; j < 3; j++)for(int i = 0; i <= 7*SOUND_LENGTH/320 ; i++){track->write(buf+i*320, 320, 1);}ALOGD("stop");track->stop();if(inBuffer){free(inBuffer);inBuffer = NULL;}return 0;}/************************************************************
*
* main in name space
*
************************************************************/
int main() {ProcessState::self()->startThreadPool();AudioTrackTest *test;test = new AudioTrackTest();test->Execute();delete test;return 0;
}}/************************************************************
*
* global main
*
************************************************************/
int main() {return android::main();
}
demo_test.h
// Copyright 2008 The Android Open Source Project#ifndef AUDIOTRACKTEST_H_
#define AUDIOTRACKTEST_H_namespace android {class AudioTrackTest{public:AudioTrackTest(void);~AudioTrackTest() {};void Execute(void);int Test01();};};#endif /*AUDIOTRACKTEST_H_*/
Android.bp
cc_test {name: "demo_test",gtest: false,srcs: ["demo_test.cpp"],shared_libs: ["liblog","libcutils","libutils","libbinder","libhardware_legacy","libmedia","libaudioclient","libaudioclient_aidl_conversion",],header_libs: ["libmediametrics_headers",],}
Android12 Native C++ 层AudioRecord录音AudioTrack播放相关推荐
- Android 录音机小米商业项目开源代码 AudioRecord录音暂停 播放 Wav格式(音频二)
Android MediaRecorder录音录像 暂停 继续录音 播放 ARM格式(音频一) https://blog.csdn.net/WHB20081815/article/details/88 ...
- AudioRecord 录音和播放的Demo
#AudioRecord 录音和播放的Demo 本文介绍一个AudioRecord的简单录音和播放的示例程序. 录音是需要动态获取权限的! ##主要代码 ###1.AudioRecord录音代码 // ...
- Android 音频开发——AudioTrack播放
Android 音频--PCM转WAV Android 音频开发--AudioRecord录音 AudioTrack类用来管理.播放单个音频资源,它只能播放PCM数据,其他音频格式(aac.amr. ...
- Android 音视频开发(一) -- 使用AudioRecord 录制PCM(录音);AudioTrack播放音频
前言,音视频这块,确实比较难入门,本着学习的态度,我这边也跟着 Android 音视频开发入门指南 打怪升级,留下个脚印,大家共勉. 音视频 系列文章 Android 音视频开发(一) – 使用Aud ...
- android 使用 audiorecord 和 audiotrack 实现实时录音播放
基本思路就是用 audiorecord不断得到音频数据,然后使用audiotrack 播放 //得到音频 package com.ysg.audiotest;import java.io.IOExce ...
- NDK学习笔记:JNI调用Java层方法创建Native的AudioTrack播放PCM(方法签名,CallXXXMethod)
NDK学习笔记:JNI调用Java层方法创建Native的AudioTrack播放PCM 题目有点复杂,不过确实就是那么回事.这章想记录的内容比较多,先列出来: native static 与 nat ...
- android 实时录音播放,android 使用 audiorecord 和 audiotrack 实现实时录音播放
基本思路就是用 audiorecord不断得到音频数据,然后使用audiotrack 播放 //得到音频 package com.ysg.audiotest; import java.io.IOExc ...
- android audiotrack权限,android 使用 audiorecord 和 audiotrack 实现实时录音播放
基本思路就是用 audiorecord不断得到音频数据,然后使用audiotrack 播放 //得到音频 package com.ysg.audiotest; import java.io.IOExc ...
- android中录音断点播放,Android实现暂停--继续录音(AudioRecord)
Android提供了两个API用于录音的实现:MediaRecorder 和 AudioRecord,各有优劣. 1.MediaRecorder 已经集成了录音.编码.压缩等,支持少量的录音音频格式, ...
最新文章
- python恶搞程序-愚人节恶搞程序源码【两种语言】
- 将一台电脑的磁盘空间映射到另一台电脑
- 【解析】Alice and Bob_24行代码AC
- USB 摄像头成熟方案介绍
- leetcode 483. 最小好进制
- oracle truncate 日期,【Oracle】truncate和delete区别
- SAP License:成本不是靠算出来的
- Linux中Redis的安装
- RedissonMultiLock + RedissonLock部分源码
- Windows、Linux、Mac OS下的锐捷认证的程序——mentohust
- svn合并分支到主干
- Springboot项目中添加Quartz定时任务
- 让你的网站用上炫酷的中文字体
- html5dragw3c,HTML5拖拽功能drag
- 物联网技术,主要包括哪些核心技术
- 大厂的人自带光环,但光环是从哪儿来的呢?
- 嵌入式linux开发笔记——Ubuntu的使用
- 详细解说RAID6结构及原理
- chromecast 协议_如何删除Chromecast的网络范围内的Android通知
- 微信ipad协议GO版本 最新不封号