android O及P之后禁止Microphone录音
背景客户需求禁止所有Mic数据输入,既包括安卓设备普通的使用场景下,还包括外接带Mic耳机的场景,首先,得考虑如何才能达到我们的目的,基本思路就是得掐断源头,源头在何处,下面便慢慢道来....
·
目录
背景
客户需求禁止所有mic数据输入,既包括安卓设备普通的使用场景下,还包括外接带mic耳机的场景,首先,得考虑如何才能达到我们的目的,基本思路就是得掐断源头,源头在何处,下面便慢慢道来.
正常场景下
AudioFlinger作为音频数据处理的大管家,录音这一重要的数据处理过程肯定少不了AudioFlinger的参与,如果android 没有现成的接口解决方案,那我们就得考虑,是不是在接收录音数据时,清空数据,让app无法获取到数据即可.
于是我们能在AudioFlinger的Thread 处理Recoder的
frameworks\av\services\audioflinger\Threads.cpp
bool AudioFlinger::PlaybackThread::threadLoop() {
...
...
// If an NBAIO source is present, use it to read the normal capture's data
//各种找才找到NBAIO的含义,Non-blocking Audio Input/Output 非阻塞音频输入/输出
//AudioFlinger 端口的抽象表示
if (mPipeSource != 0) {
size_t framesToRead = mBufferSize / mFrameSize;
framesToRead = min(mRsmpInFramesOA - rear, mRsmpInFramesP2 / 2);
framesRead = mPipeSource->read((uint8_t*)mRsmpInBuffer + rear * mFrameSize,
framesToRead);
//禁止录音数据的实现,清空buffer数据
memset(((uint8_t*)mRsmpInBuffer + rear * mFrameSize), 0, framesToRead * mFrameSize);
//禁止录音数据的实现,清空buffer数据
// since pipe is non-blocking, simulate blocking input by waiting for 1/2 of
// buffer size or at least for 20ms.
size_t sleepFrames = max(
min(mPipeFramesP2, mRsmpInFramesP2) / 2, FMS_20 * mSampleRate / 1000);
if (framesRead <= (ssize_t) sleepFrames) {
sleepUs = (sleepFrames * 1000000LL) / mSampleRate;
}
if (framesRead < 0) {
status_t status = (status_t) framesRead;
switch (status) {
case OVERRUN:
ALOGW("overrun on read from pipe");
framesRead = 0;
break;
case NEGOTIATE:
ALOGE("re-negotiation is needed");
framesRead = -1; // Will cause an attempt to recover.
break;
default:
ALOGE("unknown error %d on read from pipe", status);
break;
}
}
// otherwise use the HAL / AudioStreamIn directly
} else {
ATRACE_BEGIN("read");
size_t bytesRead;
status_t result = mInput->stream->read(
(uint8_t*)mRsmpInBuffer + rear * mFrameSize, mBufferSize, &bytesRead);
//禁止录音数据的实现,清空buffer数据
memset(((uint8_t*)mRsmpInBuffer + rear * mFrameSize), 0, mBufferSize);
//禁止录音数据的实现,清空buffer数据
ATRACE_END();
if (result < 0) {
framesRead = result;
} else {
framesRead = bytesRead / mFrameSize;
}
}
...
...
}
hal层
hardware/qcom/audio / hal/audio_hw.c
static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
size_t bytes)
{
struct stream_in *in = (struct stream_in *)stream;
struct audio_device *adev = in->dev;
int ret = -1;
size_t bytes_read = 0;
lock_input_stream(in);
if (in->is_st_session) {
ALOGVV(" %s: reading on st session bytes=%zu", __func__, bytes);
/* Read from sound trigger HAL */
audio_extn_sound_trigger_read(in, buffer, bytes);
pthread_mutex_unlock(&in->lock);
return bytes;
}
if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
ret = -ENOSYS;
goto exit;
}
if (in->standby) {
pthread_mutex_lock(&adev->lock);
if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
ret = voice_extn_compress_voip_start_input_stream(in);
else
ret = start_input_stream(in);
pthread_mutex_unlock(&adev->lock);
if (ret != 0) {
goto exit;
}
in->standby = 0;
}
// what's the duration requested by the client?
long ns = 0;
if (in->pcm && in->config.rate)
ns = pcm_bytes_to_frames(in->pcm, bytes)*1000000000LL/
in->config.rate;
request_in_focus(in, ns);
bool use_mmap = is_mmap_usecase(in->usecase) || in->realtime;
if (audio_extn_cin_attached_usecase(in->usecase)) {
ret = audio_extn_cin_read(in, buffer, bytes, &bytes_read);
} else if (in->pcm) {
if (audio_extn_ssr_get_stream() == in) {
ret = audio_extn_ssr_read(stream, buffer, bytes);
} else if (audio_extn_compr_cap_usecase_supported(in->usecase)) {
ret = audio_extn_compr_cap_read(in, buffer, bytes);
} else if (use_mmap) {
ret = pcm_mmap_read(in->pcm, buffer, bytes);
} else {
ret = pcm_read(in->pcm, buffer, bytes);
/* data from DSP comes in 24_8 format, convert it to 8_24 */
if (!ret && bytes > 0 && (in->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
if (audio_extn_utils_convert_format_24_8_to_8_24(buffer, bytes)
!= bytes) {
ret = -EINVAL;
goto exit;
}
} else if (ret < 0) {
ret = -errno;
}
}
/* bytes read is always set to bytes for non compress usecases */
bytes_read = bytes;
}
release_in_focus(in);
/*
* Instead of writing zeroes here, we could trust the hardware
* to always provide zeroes when muted.
*/
if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call_rec_stream(in) &&
in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY)
memset(buffer, 0, bytes);
exit:
if (-ENETRESET == ret)
in->card_status = CARD_STATUS_OFFLINE;
pthread_mutex_unlock(&in->lock);
if (ret != 0) {
if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
pthread_mutex_lock(&adev->lock);
voice_extn_compress_voip_close_input_stream(&in->stream.common);
pthread_mutex_unlock(&adev->lock);
in->standby = true;
}
if (!audio_extn_cin_attached_usecase(in->usecase)) {
bytes_read = bytes;
memset(buffer, 0, bytes);
}
in_standby(&in->stream.common);
ALOGV("%s: read failed status %d- sleeping for buffer duration", __func__, ret);
usleep((uint64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) /
in_get_sample_rate(&in->stream.common));
}
//清除buffer数据
memset(buffer, 0, bytes_read);
//清除buffer数据
return bytes_read;
}
usb 层 hal
hardware/libhardware / modules/usbaudio/audio_hal.c
static ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
{
size_t num_read_buff_bytes = 0;
void * read_buff = buffer;
void * out_buff = buffer;
int ret = 0;
struct stream_in * in = (struct stream_in *)stream;
stream_lock(&in->lock);
if (in->standby) {
device_lock(in->adev);
ret = start_input_stream(in);
device_unlock(in->adev);
if (ret != 0) {
goto err;
}
in->standby = false;
}
alsa_device_profile * profile = in->profile;
/*
* OK, we need to figure out how much data to read to be able to output the requested
* number of bytes in the HAL format (16-bit, stereo).
*/
num_read_buff_bytes = bytes;
int num_device_channels = proxy_get_channel_count(&in->proxy); /* what we told Alsa */
int num_req_channels = in->hal_channel_count; /* what we told AudioFlinger */
if (num_device_channels != num_req_channels) {
num_read_buff_bytes = (num_device_channels * num_read_buff_bytes) / num_req_channels;
}
/* Setup/Realloc the conversion buffer (if necessary). */
if (num_read_buff_bytes != bytes) {
if (num_read_buff_bytes > in->conversion_buffer_size) {
/*TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
(and do these conversions themselves) */
in->conversion_buffer_size = num_read_buff_bytes;
in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size);
}
read_buff = in->conversion_buffer;
}
ret = proxy_read(&in->proxy, read_buff, num_read_buff_bytes);
if (ret == 0) {
if (num_device_channels != num_req_channels) {
// ALOGV("chans dev:%d req:%d", num_device_channels, num_req_channels);
out_buff = buffer;
/* Num Channels conversion */
if (num_device_channels != num_req_channels) {
audio_format_t audio_format = in_get_format(&(in->stream.common));
unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
num_read_buff_bytes =
adjust_channels(read_buff, num_device_channels,
out_buff, num_req_channels,
sample_size_in_bytes, num_read_buff_bytes);
}
}
/* no need to acquire in->adev->lock to read mic_muted here as we don't change its state */
if (num_read_buff_bytes > 0 && in->adev->mic_muted)
memset(buffer, 0, num_read_buff_bytes);
} else {
num_read_buff_bytes = 0; // reset the value after USB headset is unplugged
}
err:
stream_unlock(&in->lock);
//缓冲buffer清零,直接清空usb mic录音数据
memset(buffer, 0, num_read_buff_bytes);
//缓冲buffer清零,直接清空usb mic录音数据
return num_read_buff_bytes;
}
Android P及之后的处理方式
frameworks\av\services\audiopolicy\service\AudioPolicyService.cpp
void AudioPolicyService::updateUidStates_l()
{
// Go over all active clients and allow capture (does not force silence) in the
// following cases:
// Another client in the same UID has already been allowed to capture
// OR The client is the assistant
// AND an accessibility service is on TOP or a RTT call is active
// AND the source is VOICE_RECOGNITION or HOTWORD
// OR uses VOICE_RECOGNITION AND is on TOP
// OR uses HOTWORD
// AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
// OR The client is an accessibility service
// AND Is on TOP
// AND the source is VOICE_RECOGNITION or HOTWORD
// OR The assistant is not on TOP
// AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
// AND is on TOP
// AND the source is VOICE_RECOGNITION or HOTWORD
// OR the client source is virtual (remote submix, call audio TX or RX...)
// OR Any client
// AND The assistant is not on TOP
// AND is on TOP or latest started
// AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
...
if (mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
silenceAllRecordings_l();
return;
}
...
}
//setAppState_l设置portId,
void AudioPolicyService::silenceAllRecordings_l() {
for (size_t i = 0; i < mAudioRecordClients.size(); i++) {
sp<AudioRecordClient> current = mAudioRecordClients[i];
if (!isVirtualSource(current->attributes.source)) {
setAppState_l(current->portId, APP_STATE_IDLE);
}
}
}
//然后setAppState_l调用AudioFlinger的setRecordSilenced函数静音mic
void AudioPolicyService::setAppState_l(audio_port_handle_t portId, app_state_t state)
{
AutoCallerClear acc;
if (mAudioPolicyManager) {
mAudioPolicyManager->setAppState(portId, state);
}
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af) {
bool silenced = state == APP_STATE_IDLE;
af->setRecordSilenced(portId, silenced);
}
}
更多推荐
已为社区贡献9条内容
所有评论(0)