Android Audio Play Out Channel

1: 7嘴8舌

 

扬声器, 耳机, 和听筒

就是通过: audiomanager.setmode(AudioManager.MODE_IN_COMMUNICATION)
audiomanager.setSpeakerhponeOn(boolean value).这两个来设置.不过有的好像不支持的.

米手机上切换 扬声器和听筒不能切换

 

Android AudioTrack音频播放分析  
音频资源在播放时,会经常出现冲突的情况,如在进行音乐播放时有电话呼入、
有新消息的提示音需要播放等,此类的并发处理就需要有一个统一的处理策略。在 Android系统开发中,通过为不同的场景配置不同的播放接口,在底层执行统一的并发策略,使得开发者可以将精力更集中在应用本身。
A udioTrack、MediaPlayer、SoundPool、Ringtone、JetPlayer等都是Android音频处理中常用接口,本文将针对AudioTrack接口进行详细说明。
AudioTrack AudioTrack用于管理单个的音频资源。 在构造AudioTrack实例时,会涉及到流类型、采样率、通道配置、音频格式、缓冲大小、播放模式等因素。
AudioTrack支持STREAM_VOICE_CALL、STREAM_SYSTEM、STREAM_RING、STREAM_MUSIC和STREAM_ALARM等流类型。
AudioTrack支持44100Hz、22050Hz、11025Hz等采样率。 AudioTrack支持单声道(CHANNEL_OUT_MONO)、立体声(CHANNEL_OUT_STEREO)等两种通道。
AudioTrack支持ENCODING_PCM_16BIT、ENCODING_PCM_8BIT等两种编码格式。
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) 而最小帧数则受制于采样率和音频设备的延迟等因素。
另外,在Android 2.3中,还引入了会话的概念,便于对单曲的音效进行处理。相应的方法包括:attachAuxEffect()、getAudioSessionId()、setAuxEffectSendLevel()等。
通过AudioTrack.OnPlaybackPositionUpdateListener监听器可以监听播放进度。
下面是一个背景音频的播放过程:
代码10-3 AudioTrack播放音频文件


public class BackgroundAudio extends Thread { public static final int SAMPLE_RATE = 16000public static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; public static final int BYTES_PER_SAMPLE = 2public static final int PLAYBACK_STREAM = AudioManager.STREAM_MUSIC; …… 
public BackgroundAudio(byte[] data) { 
 //计算缓冲大小  final int minBufferSize = (BUFFER_TIME *SAMPLE_RATE*BYTES_PER_SAMPLE) / 1000; 
  //计算硬件的最小缓冲 
      final int minHardwareBufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE,AudioFormat.CHANNEL_OUT_MONO,AUDIO_FORMAT); 
        mBufferSize = Math.max(minHardwareBufferSize, minBufferSize);        
     mAudioTrack = new AudioTrack(PLAYBACK_STREAM, SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO,  AUDIO_FORMAT, mBufferSize, AudioTrack.MODE_STREAM);         

     if (mAudioTrack.getState() == AudioTrack.STATE_INITIALIZED) {             
     writeAudio();          start(); 
// 启动背景线程去推送音频数据             mAudioTrack.play();         } else {          Log.e(TAG, "Error initializing audio track.");         
  } } …… 
private void writeAudio() {    
  int len = mData.length;    
  int count;    int maxBytes = Math.min(mBufferSize, len - mPos);     count = mAudioTrack.write(mData, mPos, maxBytes);    
  if (count < 0) {         Log.e(TAG, "Error writing looped audio data");        
  halt();        

  return;     
  }     mPos 
+= count;    

if (mPos == len) {         mPos = 0; // Wraparound    
 }  } }

Media playback  
Supported Media Formats  
Audio Capture  
JetPlayer  
Camera  

        这次我先分享下Media Playback的中一些内容以及我学习中的感悟。  




        首先需要我们接触到的最主要的两个类分别是MediaPlayer、MediaManager。MediaPlayer是用来控制音频/视频流或者文件的播放的,需要我们注意的是MediaPlayer对象加上其支持的一些播放操作会形成一个状态机,在不合适的状态执行不合适的操作就会抛出异常,如果开发者不清楚自己创建的MediaPlayer对象当前处于哪个状态,就很有可能调用错误的方法造成程序的异常,而且这些错误很难被察觉,所以错误处理在这个部分就显得尤为重要。  




        下面要说的就是Audio Focus,举个例子,当你在听歌的时候,突然来了一条短信,如果不加处理,短信的声音很可能被音乐的声音湮没,你就会察觉不到。我们希望发生什么事情呢?我们希望这个时候音乐的声音较之前稍微降低些使得我们能够听到短信提示音,在短信提示音结束后音乐的声音再次回到正常。这个过程就是获取和释放audio focus的过程。  

        在写代码的时候,我忽略了一点:Audio Focus is cooperative in nature.  

申请audio focus  


[java] view plaincopyprint?AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);   
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,    
    AudioManager.AUDIOFOCUS_GAIN);    

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);  
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,  
    AudioManager.AUDIOFOCUS_GAIN);  
处理focus change事件  


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

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

        申请audio focus和处理focus change一定是互相配合实现的,我一开始写了个service用来播放音乐,在start函数调用前并没有申请audio focus,但是我实现了onAudioFocusChange函数。我期待这个service在focus change时停止播放,但是我发现,当另外一个service申请到audio focus时,之前的service不会出现音乐停止播放的情况。 
android培训,就选成都达内,最好的成都软件培训机构,如果你有“达内培训需要多少钱”、“达内培训怎么样”等问题,详情请咨询达内客服(http://www.sctarena.com),我们会给你详细的讲解。

 

 

android 听筒播放音乐


AudioManager.setMode(AudioManager.MODE_IN_CALL) //设定为通话中即可 还是这一句代码的事,不过记得要加上权限 android.permission.MODIFY_AUDIO_SETTINGS 还有一点需要注意的事,在播放完毕后需要 AudioManager.setMode(AudioManager.MODE_NORMAL); 不然其他软件播放都听筒发声了

实际操作中,仅仅上述代码并不能是实现需求:

荣耀:4..2.2

内核3.4.5


audiomanager.setMode(AudioManager.MODE_IN_CALL);

Nexus 5   5.0.1

内核2.4.0

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

 

 

   
   
   
 

 

2:应用场景

 

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

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

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

技术分享

一、Audio输出状态查询与控制

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

 

  •  isBluetoothA2dpOn():检查A2DPAudio是否通过蓝牙耳机;
  •  isSpeakerphoneOn():检查扬声器是否打开;
  •  isWiredHeadsetOn():检查线控耳机是否连着;注意这个方法只是用来判断耳机是否是插入状态,并不能用它的结果来判定当前的Audio是通过耳机输出的,这还依赖于其他条件。

 

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

 

二、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);
}

三、Audio输出通道切换的典型场景—— 用耳机听音乐时,拔出耳机

听耳机听音乐时,耳机别拔出的时序图如下:

技术分享

图中:

 

  •  AudioNoisy Client注册了侦听广播AudioManager.ACTION_AUDIO_BECOMING_NOISY[Step#1 ~ #2];
  •  用耳机一直在听音乐;
  •  HeadsetObserver一直在监视耳机状态的变化。检测到耳机被拔出之后,发出广播AudioManager.ACTION_AUDIO_BECOMING_NOISY[Step#3~4];
  •  AudioNoisy Client收到了广播,发送暂停命令给MediaPaybackService去暂停当前的播放 [Step#5~6]。

 

 3:Android 文档

Building Apps with Multimedia

These classes teach you how to create rich multimedia apps that behave the way users expect.

  1. Managing Audio Playback

    If your app plays audio, it’s important that your users can control the audio in a predictable manner. To ensure a great user experience, it’s also important that your app manages the audio focus to ensure multiple apps aren’t playing audio at the same time.
    
    After this class, you will be able to build apps that respond to hardware audio key presses, which request audio focus when playing audio, and which respond appropriately to changes in audio focus caused by the system or other applications.
    为用户提供便捷的音频状态控制对良好的用户体验是非常重要的。
    
    你可以构建响应物理音频按键,获取音频播放焦点,以及适时的响应由于系统or其他应用引起的音频焦点变化。

     

  2.  


    How to respond to hardware audio key presses, request audio focus when playing audio, and respond appropriately to changes in audio focus.

    1. Controlling Your App‘s Volume and Playback
    2. Managing Audio Focus
    3. Dealing with Audio Output Hardware

 

引用:

http://blog.csdn.net/thl789/article/details/7423523

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。