audio开发实战小技巧:获取系统当前活跃的录音和播放track相关api介绍

背景:

在做一些音频播放或者录音时候,经常会有对当前系统是否有正在处于活跃录音中的判断需求。
对于做audio系统开发的同学来说这个都很简单哈,直接dumpsys audioflinger相关输出就可以一目了然:

在这里插入图片描述看这个input thread下面的是否有active的track既可以。
在这里插入图片描述但是对于普通app应该来如何判断呢?
今天来分析一下如何通过系统现有的api来实现对当前系统有哪些活跃的播放track和活跃的录音track。

相关api介绍:

    /**
     * Returns the current active audio playback configurations of the device
     * @return a non-null list of playback configurations. An empty list indicates there is no
     *     playback active when queried.
     * @see AudioPlaybackConfiguration
     */
    public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
        final IAudioService service = getService();
        try {
            return service.getActivePlaybackConfigurations();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    /**
     * Returns the current active audio recording configurations of the device.
     * @return a non-null list of recording configurations. An empty list indicates there is
     *     no recording active when queried.
     * @see AudioRecordingConfiguration
     */
    public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
        final IAudioService service = getService();
        try {
            return service.getActiveRecordingConfigurations();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

解释如下:
getActivePlaybackConfigurations

主要负责返回当前活跃的playback的相关信息

getActiveRecordingConfigurations

主要负责返回当前活跃的录音trace的相关信息

使用demo进行调用相关的api


    void getAudioRecordConfig() {
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

        List<AudioPlaybackConfiguration> list = audioManager.getActivePlaybackConfigurations();
        for ( AudioPlaybackConfiguration audioRecordingConfiguration : list) {
            Log.i("xxx","getAudioRecordConfig audioRecordingConfiguration " +audioRecordingConfiguration);

        }

        List<AudioRecordingConfiguration> list1 = audioManager.getActiveRecordingConfigurations();
        for ( AudioRecordingConfiguration audioRecordingConfiguration : list1) {
            Log.i("lsm888","getAudioRecordConfig audioRecordingConfiguration " +audioRecordingConfiguration);

        }
    }

getAudioRecordConfig原理源码分析:

下面就以Record部分的信息获取作为案例进行源码分析,playback部分就一样参考record既可以。
frameworks/base/media/java/android/media/AudioManager.java

    /**
     * Returns the current active audio recording configurations of the device.
     * @return a non-null list of recording configurations. An empty list indicates there is
     *     no recording active when queried.
     * @see AudioRecordingConfiguration
     */
    public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
        final IAudioService service = getService();
        try {
        //调用到audioservice部分接口
            return service.getActiveRecordingConfigurations();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

下面看看audioservice部分接口实现
frameworks/base/services/core/java/com/android/server/audio/AudioService.java

    public List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
        final boolean isPrivileged = Binder.getCallingUid() == Process.SYSTEM_UID
                || (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
                        MODIFY_AUDIO_ROUTING));
        
        return mRecordMonitor.getActiveRecordingConfigurations(isPrivileged);
    }

isPrivileged代表一些特权的app可以获取直接获取所有的信息。
再看看:
frameworks/base/services/core/java/com/android/server/audio/RecordingActivityMonitor.java

    List<AudioRecordingConfiguration> getActiveRecordingConfigurations(boolean isPrivileged) {
        List<AudioRecordingConfiguration> configs = new ArrayList<AudioRecordingConfiguration>();
        synchronized (mRecordStates) {
        //获取的是mRecordStates中active进行返回
            for (RecordingState state : mRecordStates) {
                if (state.isActiveConfiguration()) {
                    configs.add(state.getConfig());
                }
            }
        }
        // AudioRecordingConfiguration objects never get updated. If config changes,
        // the reference to the config is set in RecordingState.
        if (!isPrivileged) {
            configs = anonymizeForPublicConsumption(configs);
        }
        return configs;
    }

那么接下来看看mRecordStates变量来自哪里?这块比较复杂涉及到audioflinger,policy等部分,下一篇文章再分享。

命令行进行dump查看:

AudioRecordingConfiguration部分的输出情况
使用如下命令:

 adb shell dumpsys audio

主要看如下的dump信息:

RecordActivityMonitor dump time: 10:46:46 AM
riid 14623; active? true
  session:14609 -- source client=MIC, dev=2ch 48000Hz ENCODING_PCM_16BIT -- uid:10150 -- patch:21 -- pack:com.example.remotesubmix -- format client=2ch 48000Hz ENCODING_PCM_16BIT, dev=2ch 48000Hz ENCODING_PCM_16BIT -- silenced:false -- effects client=, dev=

在这里插入图片描述

AudioPlaybackConfiguration部分的输出情况:

PlaybackActivityMonitor dump time: 11:07:42 AM

  playback listeners:
 (S)com.android.server.audio.PlaybackActivityMonitor$PlayMonitorClient@79b7d56 (S)com.android.server.audio.PlaybackActivityMonitor$PlayMonitorClient@3e8c1d7 (S)com.android.server.audio.PlaybackActivityMonitor$PlayMonitorClient@8743ac4


  players:
(not logged)  AudioPlaybackConfiguration piid:14599 deviceId:0 type:android.media.SoundPool u/pid:1000/2838 state:idle attr:AudioAttributes: usage=USAGE_ASSISTANCE_SONIFICATION content=CONTENT_TYPE_SONIFICATION flags=0x800 tags= bundle=null sessionId:0 mutedState:none  FormatInfo{isSpatialized=false, channelMask=0x0, sampleRate=0}
  AudioPlaybackConfiguration piid:14607 deviceId:0 type:android.media.SoundPool u/pid:10123/3072 state:idle attr:AudioAttributes: usage=USAGE_ASSISTANCE_SONIFICATION content=CONTENT_TYPE_SONIFICATION flags=0x800 tags= bundle=null sessionId:0 mutedState:none  FormatInfo{isSpatialized=false, channelMask=0x0, sampleRate=0}
  AudioPlaybackConfiguration piid:14663 deviceId:2 type:android.media.AudioTrack u/pid:10095/5042 state:started attr:AudioAttributes: usage=USAGE_MEDIA content=CONTENT_TYPE_MUSIC flags=0x900 tags= bundle=null sessionId:14649 mutedState:none  FormatInfo{isSpatialized=false, channelMask=0x3, sampleRate=48000}

  ducked players piids:

  faded out players piids:

  muted player piids due to call/ring:

  banned uids:


在这里插入图片描述

原文内容参考:
https://mp.weixin.qq.com/s/pQr-HrW0EUoi5QHTMOGEBQ

更多framework实战干货,请关注下面“千里马学框架”

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值