android O及P之后禁止Microphone录音

qualcomm 同时被 2 个专栏收录
17 篇文章 0 订阅
4 篇文章 0 订阅

目录

背景

Android O的处理方式

Android P及之后的处理方式


背景

客户需求禁止所有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);
      }
  }

  • 0
    点赞
  • 4
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值