0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Android AudioTrack音频播放分析

哆啦安全 来源:哆啦安全 2023-01-14 09:44 次阅读

a62af6a2-939f-11ed-bfe3-dac502259ad0.png

a65af3ac-939f-11ed-bfe3-dac502259ad0.png

一、Android Audio Play Out Channel

扬声器、耳机、听筒,通过这两个来设置,不过有的好像不支持的

/frameworks/base/media/java/android/media/AudioManager.java


audiomanager.setmode(AudioManager.MODE_IN_COMMUNICATION)
audiomanager.setSpeakerhponeOn(booleanvalue)

Android AudioTrack音频播放分析

音频资源在播放时,会经常出现冲突的情况,如在进行音乐播放时有电话呼入、有新消息的提示音需要播放等,此类的并发处理就需要有一个统一的处理策略。

在Android系统开发中,通过为不同的场景配置不同的播放接口,在底层执行统一的并发策略,使得开发者可以将精力更集中在应用本身。

AudioTrack、MediaPlayer、SoundPool、Ringtone、JetPlayer等都是Android音频处理中常用接口

针对AudioTrack接口进行详细说明

(1).AudioTrack、AudioTrack用于管理单个的音频资源。在构造AudioTrack实例时,会涉及到流类型、采样率、通道配置、音频格式、缓冲大小、播放模式等因素。

(2).AudioTrack支持STREAM_VOICE_CALL、STREAM_SYSTEM、STREAM_RING、STREAM_MUSIC和STREAM_ALARM等流类型。

(3).AudioTrack支持44100Hz、22050Hz、11025Hz等采样率。

(4).AudioTrack支持单声道(CHANNEL_OUT_MONO)、

立体声(CHANNEL_OUT_STEREO)等两种通道。

(5).AudioTrack支持ENCODING_PCM_16BIT、ENCODING_PCM_8BIT等两种编码格式。

(6).AudioTrack支持两种播放模式

静态模式(static mode)

流模式(Streaming mode)

其中静态模式由于没有从Java层向原生层传递数据造成的延迟,时延很小,当然受限于音频缓冲的大小,通常在游戏场景中用于播放时长很短的音频资源。

当音频流较大不足以在音频缓冲中一次写入时,可采用流模式。

AudioTrack的播放状态包括

PLAYSTATE_STOPPED

PLAYSTATE_PAUSED

PLAYSTATE_PLAYING等

AudioTrack实例的状态包括

STATE_INITIALIZED

STATE_NO_STATIC_DATA

STATE_UNINITIALIZED等

向音频缓冲中添加数据的方法为write()

在设置音频缓冲时,其大小与采样率、通道和音频格式有关,其计算公式为:

缓冲大小 = 最小帧数 × (通道==CHANNEL_OUT_STEREO?2:1) × (音频格式== PCM16?2:1)

而最小帧数则受制于采样率和音频设备的延迟等因素

另外,在Android2.3中,还引入了会话的概念,便于对单曲的音效进行处理。相应的方法包括:

attachAuxEffect()

getAudioSessionId()

setAuxEffectSendLevel()等

通过AudioTrack.OnPlaybackPositionUpdateListener监听器可以监听播放进度

当在听歌的时候,突然来了一条短信,如果不加处理,短信的声音很可能被音乐的声音湮没,就会察觉不到。

获取和释放audio focus的过程

(1).申请audio focus

AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
intresult=audioManager.requestAudioFocus(this,AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN);

(2).处理focus change事件

class MyService extends Service implements AudioManager.OnAudioFocusChangeListener {
    // ....
    public void onAudioFocusChange(int focusChange) {
        // Do something based on focus change...
    }
}

申请audio focus和处理focus change一定是互相配合实现的

android听筒播放音乐

AudioManager.setMode(AudioManager.MODE_IN_CALL)//设定为通话中即可


添加权限
android.permission.MODIFY_AUDIO_SETTINGS


播放完毕后需要
AudioManager.setMode(AudioManager.MODE_NORMAL);

不然其他软件播放都听筒发声,实际操作中,仅仅上述代码并不能是实现需求

Android 5.0.1
audiomanager.setMode(AudioManager.MODE_IN_CALL); //不能生效,即便添加该行仍然从扬声器播出

应用场景

Audio输出通道有很多,Speaker、headset、bluetooth A2DP等

Android中的Audio播放(控制Audio输出通道切换)

通话或播放音乐等使用Audio输出过程中,可能发生Audio输出通道的切换

例如:

插入有线耳机播放音乐时,声音是从耳机发出的;而此时拔出耳机,Audio输出通道会发生切换。如果音乐播放器不做处理,Audio输出是被切换到扬声器的,声音直接从Speaker发出。

Android中可以通过android.media.AudioManager查询当前Audio输出的情况,并且在Audio输出发生变化时,捕获并处理这种变化。

a67d43d0-939f-11ed-bfe3-dac502259ad0.png

(1).Audio输出状态查询与控制

android.media.AudioManager提供的下列方法可以用来查询当前Audio输出的状态

isBluetoothA2dpOn() //检查A2DPAudio是否通过蓝牙耳机

isSpeakerphoneOn() //检查扬声器是否打开

isWiredHeadsetOn() //检查线控耳机是否连着,注意这个方法只是用来判断耳机是否是插入状态,并不能用它的结果来判定当前的Audio是通过耳机输出的,这还依赖于其他条件。

另外还有一些设置这些Audio输出的setXYZ()方法,这些方法在一般使用Audio输出的应用程序不要直接调用,他们由系统来管理,实现Audio输出通道的自动切换。除非,界面提供给用户切换的菜单或按钮,而用户选择了却换

例如:

要直接选择扬声器发声,可直接调用setSpeakerphoneOn()

(2).Audio输出通道切换的事件的捕获与处理

因为耳机插拔、蓝牙耳机的断开,Audio输出通路会自动切换。此时正在播放Audio的程序要获得通知,知道这一事件的发生。

Android中是通过广播ACTION_AUDIO_BECOMING_NOISY这个Intent通知的。

处理广播的较好的方式,是动态注册/注销自己所关心的广播。

开始播放时注册广播的Receiver,停止播放时注销广播的Receiver。对Audio输出通道切换的处理是暂停当前的播放,不直接从新的通道里发出声来

private class NoisyAudioStreamReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
            // Pause the playback
        }
    }
}


private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);


private void startPlayback() {
    registerReceiver(myNoisyAudioStreamReceiver(), intentFilter);
}


private void stopPlayback() {
    unregisterReceiver(myNoisyAudioStreamReceiver);
}

(3).Audio输出通道切换的典型场景——用耳机听音乐时,拔出耳机

a697e852-939f-11ed-bfe3-dac502259ad0.png

AudioNoisy Client注册了侦听广播

AudioManager.ACTION_AUDIO_BECOMING_NOISY

用耳机一直在听音乐

HeadsetObserver一直在监视耳机状态的变化。检测到耳机被拔出之后,发出广播AudioManager.ACTION_AUDIO_BECOMING_NOISY

frameworks/base/services/java/com/android/server/HeadsetObserver.java

AudioNoisy Client收到了广播,发送暂停命令给MediaPaybackService去暂停当前的播放

Managing Audio Playback

提供便捷的音频状态控制

可以构建响应物理音频按键,获取音频播放焦点,以及适时的响应由于系统或其他应用引起的音频焦点变化

三个AudioCommandThread线程分别是ApmTone、ApmAudio、ApmOutput

ApmTone用于播放tone音

ApmAudio用于执行audio命令

ApmOutput用于执行输出命令

a6c3e308-939f-11ed-bfe3-dac502259ad0.png

在AudioPolicyManager创建过程中会通过加载audio_policy.conf配置文件来加载音频设备,Android为每种音频接口定义了对应的硬件抽象层。硬件抽象层代码

hardware/libhardware/modules/audio
external/bluetooth/bluedroid/audio_a2dp_hw/audio.a2dp.default.so
hardware/libhardware/modules/audio/audio.primary.default.so
hardware/libhardware/modules/usbaudio/audio.usb.default.so

原文链接:
https://www.shuzhiduo.com/A/1O5EDokGJ7/
https://blog.csdn.net/thl789/article/details/7423523
https://www.shuzhiduo.com/A/Gkz1Lj3GdR/

二、Android上播放视频时没有声音的问题

(1).如果在android上播放视频时遇到没有声音的问题,要么是android手机上有问题,要么就是视频本身有问题。无论那种情况,都有相对应的解决方案。

(2).在Android Audio相关开发过程中,可能会遇到播放ringtone时无声,但播放Music可以听到声音,关于无声问题的分析。

三、Android设备上播放有声视频的技巧

(1).始终保持扬声器清洁

(2).未经验证的应用程序不应安装在设备上

(3).手机的音频端口。这是因为一旦拔出耳机,某些设备就会卡在耳机模式

(4).还应检查听筒

四、Android Audio遇到播放无声时的分析思路

(1).在音量控制面板中确认该音频流对应的Volume_index大小是否等于0

(2).若Volume_index != 0时,看user space的logcat与kernel log中有无明显的Audio Fail项,比如设备是否选择正确以及对应的路径是否有配通

(3).在hardware层,在audio_hw.cpp文件中的out_write函数中添加log,判断是否有数据写入(QCOM MSM8939)

/hardware/libhardware/modules/audio_remote_submix/audio_hw.cpp
785  static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
786                           size_t bytes)

a6d719c8-939f-11ed-bfe3-dac502259ad0.png

(4).通过dumpsys media.audio_policy命令来查看对应音频流是否被mute住,若被mute,需要分析AudioPolicyManager.cpp文件

/frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp

(5).看当前音源档本身的音量是否为0

其中1与5之间的区别在于:

在播放某音源档时,在AudioTrack::set()函数里,先将音源数据的左右声道的Volume设置为1.0,即为最大声。而通过音量按键或则在VolumePanel中调节音量则是在最大音量基础上做衰减操作

/frameworks/av/media/libaudioclient/AudioTrack.cpp


326  status_t AudioTrack::set(
327          audio_stream_type_t streamType,
328          uint32_t sampleRate,
329          audio_format_t format,
330          audio_channel_mask_t channelMask,
331          size_t frameCount,
332          audio_output_flags_t flags,
333          callback_t cbf,
334          void* user,
335          int32_t notificationFrames,
336          const sp& sharedBuffer,
337          bool threadCanCallJava,
338          audio_session_t sessionId,
339          transfer_type transferType,
340          const audio_offload_info_t *offloadInfo,
341          uid_t uid,
342          pid_t pid,
343          const audio_attributes_t* pAttributes,
344          bool doNotReconnect,
345          float maxRequiredSpeed,
346          audio_port_handle_t selectedDeviceId)

a70037fe-939f-11ed-bfe3-dac502259ad0.png

a72df81a-939f-11ed-bfe3-dac502259ad0.png

/frameworks/base/services/core/java/com/android/server/audio/AudioService.java
mVolumeControlStream 
VolumePanel


/frameworks/base/media/java/android/media/AudioManager.java
VolumePanel

a74fb982-939f-11ed-bfe3-dac502259ad0.png

(6).在Android开发中可以通过AudioManager来判断是否有声音在播放

/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java


/frameworks/base/media/java/android/media/AudioManager.java
2046      public boolean isMusicActive() {
2047          return AudioSystem.isStreamActive(STREAM_MUSIC, 0);
2048      }

(7).Android中的Audio播放(分析控制Audio输出通道切换设置)

检查Android Audio音频setMode()的默认设置
AudioManager.setMode(AudioManager.MODE_NORMAL);

Android各版本系统源码在线阅读地址

http://aospxref.com/
http://androidxref.com
https://aosp.opersys.com
https://wiki.lineageos.org/devices/
https://wiki.pixelexperience.org/devices/





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • PCM
    PCM
    +关注

    关注

    1

    文章

    186

    浏览量

    52671
  • 编码器
    +关注

    关注

    41

    文章

    3360

    浏览量

    131481
  • JAVA
    +关注

    关注

    19

    文章

    2904

    浏览量

    102989
  • Android系统
    +关注

    关注

    0

    文章

    55

    浏览量

    13185

原文标题:Android10以上系统Audio音频遇到播放视频无声时的分析方法

文章出处:【微信号:哆啦安全,微信公众号:哆啦安全】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    DSP教学实验箱:音频采集与播放实验

    学习McASP管脚的使用方法,掌握音频采集播放的原理和过程,并实现音频的采集与播放
    的头像 发表于 10-25 17:41 745次阅读
    DSP教学实验箱:<b class='flag-5'>音频</b>采集与<b class='flag-5'>播放</b>实验

    音频信息是怎么保存和播放的?

    常用的音频格式有哪几种,我所了解的有mp3,WAV等,这些音频资料信息是怎么保存在电脑硬盘上的,我所说的保存是指怎么以二进制信息存储的? 在音频信息播放时,
    发表于 02-08 16:06

    音频播放功能的爱普生IC支持12种言语

    音频播放
    Piezoman压电侠
    发布于 :2024年01月12日 09:55:57

    如何去降低Android音频系统的底噪问题

    耳机可以分为哪几种?Android音频播放外接模拟耳机时,音乐播放过程是怎样的?Android音频
    发表于 08-09 08:55

    为什么AudioTrack播放服务端传过来的音频有强电流声

    为什么AudioTrack播放服务端传过来的音频有强电流声?有什么解决办法吗?
    发表于 09-30 06:38

    求一种基于android系统的HIFI播放器开发方案

    的hifiplayer。其实就是基于ffplayer做剪裁了。可参考extern/ffmpeg。三 音频流处理。Android用来播放pcm的 AudioTrack类。之后混音重采样都
    发表于 06-08 17:45

    如何通过tinyalsa命令音频正在通过wm8960播放

    我能够在 imx8mp phytec pollux 板上检测到 android 11 中的 wm8960 编解码器 问题是:我能够通过命令行方式播放音频,通过 tinyalsa 命令音频正在通过
    发表于 05-12 06:33

    Android11中通过GUI的wm8960模块播放音频找不到是为什么?

    1. 在命令提示符下使用 Tinyplay 命令,我们验证了模块是否正常工作。默认 wm8960 模块正在播放音频也在播放。 2.我们通过报警默认歌曲播放,也可以自定义报警歌曲,可以
    发表于 05-17 10:00

    为什么无法使用媒体播放器应用程序通过GUI在android11中播放音频

    1. 在命令提示符下使用 Tinyplay 命令,我们验证了模块是否正常工作。默认 wm8960 模块正在播放音频也在播放。 2.我们播放了报警默认歌曲,我们可以通过wm8960
    发表于 05-30 07:11

    MP4播放音频播放格式

    MP4播放音频播放格式              音频
    发表于 12-21 15:59 2958次阅读

    基于Android系统的影音播放器设计

    本文以Android上影音播放器的开发为范例,详细给出了Android上应用的开发方法。开发的影音播放器在Android手机模拟器和OMAP
    发表于 04-11 11:41 3122次阅读
    基于<b class='flag-5'>Android</b>系统的影音<b class='flag-5'>播放</b>器设计

    Android系统WMA文件播放功能的设计与实现

    基于Android多媒体系统的Stagefright框架,通过创建WMA的文件解析单元和解码单元,使WMA音频文件中的编码数据被正确地解码成原始数据并输出。通过在Android平台测试机上反复
    发表于 11-04 11:33 42次下载

    使用低级音频函数实现音频采集与播放

    使用低级音频函数实现音频采集与播放,下来看看。
    发表于 01-21 11:17 7次下载

    树莓派音频视频播放

    树莓派音频视频播放
    的头像 发表于 06-21 11:41 423次阅读

    芯知识 | 什么是音频蓝牙播放语音芯片?

    随着科技的不断进步,音频蓝牙播放语音芯片成为嵌入式音频系统中备受关注的创新解决方案。本文将深入解析什么是音频蓝牙播放语音芯片,以及其在实现无
    的头像 发表于 12-15 08:36 320次阅读
    芯知识 | 什么是<b class='flag-5'>音频</b>蓝牙<b class='flag-5'>播放</b>语音芯片?