精华内容
下载资源
问答
  • Audiotrack

    2016-09-27 14:44:11
    AudioTrack播放原始音频PCM
  • AudioTrack

    2019-10-11 10:46:15
    由于AudioTrack是Android SDK层提供的最底层的音频播放API,因此只允许输入裸数据。和MediaPlayer相比,对于一个压缩的音频文件(比如MP3、AAC等文件),它需要自行实现解码操作和缓冲区控制。 首先来看一下...
        

    由于AudioTrack是Android SDK层提供的最底层的音频播放API,因此只允许输入裸数据。和MediaPlayer相比,对于一个压缩的音频文件(比如MP3、AAC等文件),它需要自行实现解码操作和缓冲区控制。

    首先来看一下AudioTrack的工作流程,具体如下。
    1)根据音频参数信息,配置出一个AudioTrack的实例。
    2)调用play方法,将AudioTrack切换到播放状态。
    3)启动播放线程,循环向AudioTrack的缓冲区中写入音频数据。
    4)当数据写完或者停止播放的时候,停止播放线程,并且释放所有资源。
    根据AudioTrack的上述工作流程,本节将以4个小部分分别介绍每个流程的详细步骤。

    1.配置AudioTrack
    先来看一下AudioTrack的参数配置,要想构造出一个AudioTrack类型的实例,必须先了解其构造函数原型,代码如下所示:

    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig,int audioFormat, int bufferSizeInBytes, int mode);
    

    其中构造函数的参数说明如下。

    • streamType,Android手机上提供了多重音频管理策略(按一下手机侧边的按键,可以看到有多个音量管理,这其实就是不同音频策略的音量控制展示),当系统有多个进程需要播放音频的时候,管理策略会决定最终的呈现效果,该参数的可选值将以常量的形式定义在类AudioManager中,主要包括以下内容:
      STREAM_VOCIE_CALL:电话声音
      STREAM_SYSTEM:系统声音
      STREAM_RING:铃声
      STREAM_MUSCI:音乐声
      STREAM_ALARM:警告声
      STREAM_NOTIFICATION:通知声
    • sampleRateInHz,采样率,即播放的音频每秒钟会有多少次采样,可选用的采样频率列表为:8000、16000、22050、24000、32000、44100、48000等,大家可以根据自己的应用场景进行合理的选择。
    • channelConfig,声道数(通道数)的配置,可选值以常量的形式配置在类AudioFormat中,常用的是CHANNEL_IN_MONO(单声道)、CHANNEL_IN_STEREO(双声道),因为现在大多数手机的麦克风都是伪立体声的采集,为了性能考虑,笔者建议使用单声道进行采集,而转变为立体声的过程可以在声音的特效处理阶段来完成。
    • audioFormat,该参数是用来配置“数据位宽”的,即采样格式,可选值以常量的形式定义在类AudioFormat中,分别为ENCODING_PCM_16BIT(16bit)ENCODING_PCM_8BIT(8bit),
      注意,前者是可以兼容所有Android手机的。
    • bufferSizeInBytes,其配置的是AudioTrack内部的音频缓冲区的大小,AudioTrack类提供了一个帮助开发者确定bufferSizeInBytes的函数,其原型具体如下:
    int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat);
    

    在实际开发中,强烈建议由该函数计算出需要传入的bufferSizeInBytes,而不是自己手动计算。

    • mode,AudioTrack提供了两种播放模式,可选的值以常量的形式定义在类AudioTrack中,一个是MODE_STATIC,需要一次性将所有的数据都写入播放缓冲区中,简单高效,通常用于播放铃声、系统提醒的音频片段;另一个是MODE_STREAM,需要按照一定的时间间隔不间
      断地写入音频数据,理论上它可以应用于任何音频播放的场景。

    2.将AudioTrack切换到播放状态
    首先判断AudioTrack实例是否初始化成功,如果当前状态处于初始成功的状态,那么就调用它的play方法,并切换到播放状态,代码如下:

    if (null != audioTrack && audioTrack.getState() != AudioTrack.STATE_UNINITIALIZED)
    {
        audioTrack.play();
    }
    

    3.开启播放线程
    首先创建一个播放线程,代码如下:

    playerThread = new Thread(new PlayerThread(), "playerThread");
    playerThread.start();
    

    接下来看看该线程中执行的任务,代码如下:

    class PlayerThread implements Runnable {
        private short[] samples;
        public void run() {
           samples = new short[minBufferSize];
            while(!isStop) {
                int actualSize = decoder.readSamples(samples);
                audioTrack.write(samples, actualSize);
            }
        }
    }
    

    线程中的minBufferSize是在初始化AudioTrack的时候获得的缓冲区大小,会对其进行换算,即以2个字节表示一个采样的大小,也就是2倍的关系(因为初始化的时候是以字节为单位的);decoder是一个解码器,假设已经初始化成功,最后将调用write方法把从解码器中获得的PCM采样数据写入AudioTrack的缓冲区中,注意此方法是阻塞的方法,比如:一般要写入200ms的音频数据需要执行接近200ms的时间。

    4.销毁资源
    首先停止AudioTrack,代码如下:

    if (null != audioTrack && audioTrack.getState() != AudioTrack.STATE_UNINITIALIZED)
    {
        audioTrack.stop();
    }
    

    然后停止线程:

    isStop = true;
    if (null != playerThread) {
        playerThread.join();
        playerThread = null;
    }
    

    最后释放AudioTrack:

    audioTrack.release();
    
    展开全文
  • audioTrack

    2013-04-02 22:59:02
    Android 和MediaPlayer一样功能强大的类。androidtrack可用来实时传输是很有好处的
  • AudioTrack.svg

    2021-06-12 12:00:35
    AudioTrack.svg UML顺序图
  • AudioTrack使用

    2021-07-21 13:35:22
    AudioTrack用来播放音频的原始数据PCM。MediaPlayer把音频解码后的数据交给AudioTrack来播放。 我们看下AudioTrack的构造函数 public AudioTrack(AudioAttributes attributes, AudioFormat format, int ...

    AudioTrack用来播放音频的原始数据PCM。MediaPlayer把音频解码后的数据交给AudioTrack来播放。

    我们看下AudioTrack的构造函数

      public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
                int mode, int sessionId)
                        throws IllegalArgumentException {
            this(attributes, format, bufferSizeInBytes, mode, sessionId, false /*offload*/,
                    ENCAPSULATION_MODE_NONE, null /* tunerConfiguration */);
        }

    AudioAttributes attributes  

            AudioAttributes audioAttributes = (new AudioAttributes.Builder()).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build();
    

    设置当前要播放什么内容的数据

    我们看源码包括下面一下信息

    public final class AudioAttributes implements Parcelable {
        private final static String TAG = "AudioAttributes";
    
        /**
         * Content type value to use when the content type is unknown, or other than the ones defined.
         */
        public final static int CONTENT_TYPE_UNKNOWN = 0;
        /**
         * Content type value to use when the content type is speech.
         */
        public final static int CONTENT_TYPE_SPEECH = 1;
        /**
         * Content type value to use when the content type is music.
         */
        public final static int CONTENT_TYPE_MUSIC = 2;
        /**
         * Content type value to use when the content type is a soundtrack, typically accompanying
         * a movie or TV program.
         */
        public final static int CONTENT_TYPE_MOVIE = 3;
        /**
         * Content type value to use when the content type is a sound used to accompany a user
         * action, such as a beep or sound effect expressing a key click, or event, such as the
         * type of a sound for a bonus being received in a game. These sounds are mostly synthesized
         * or short Foley sounds.
         */
        public final static int CONTENT_TYPE_SONIFICATION = 4;

    包括了 演讲 电影 音乐等类型。我们这里选择

    CONTENT_TYPE_MUSIC

     AudioFormat format

     AudioFormat.Builder builder = new AudioFormat.Builder();
            builder.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
                    .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                    .setSampleRate(44100);
            AudioFormat audioFormat = builder.build();

    设置声道掩码,比如采集音视频我们设置了AudioFormat.CHANNEL_IN_STEREO,那么播放的时候要设置成AudioFormat.CHANNEL_OUT_STEREO

    设置编码格式AudioFormat.ENCODING_PCM_16BIT 每个采样大小是2个字节

    设置采样率 44100

    builder还提供了setChannelIndexMask方法,setChannelIndexMask和setChannelMask是互斥的。

    setChannelIndexMask
    Added in API level 23
    AudioFormat.Builder setChannelIndexMask (int channelIndexMask)
    设置频道索引掩码。 通道索引掩码指定帧中的音频采样与编号的端点通道的关联。 信道索引掩码中的第i位对应于第i个端点信道。 例如,具有四个通道的端点被表示为索引掩码位0至3.这个位置掩码解释的这个setChannelMask(int) 。
    
    AudioTrack和AudioRecord支持通道索引掩码。 如果指定了通道索引掩码,则使用该掩码,否则使用由setChannelMask指定的通道位置掩码。 对于AudioTrack和AudioRecord ,如果指定了通道索引掩码,则不需要通道位置掩码。
    int bufferSizeInBytes
         *   See {@link #getMinBufferSize(int, int, int)} to determine the estimated minimum buffer size
         *   for an AudioTrack instance in streaming mode.

    注释中写道对于流模式AudioTrack getMinBufferSize

    int mode

    @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}.

    MODE_STATIC 一次把数据传进来

    MODE_STREAM 传很多次数据

    int sessionId 会话id
    AudioManager.AUDIO_SESSION_ID_GENERATE

    AudioManager.generateAudioSessionId()

    开始播放

     Runnable recordRunnable = new Runnable() {
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void run() {
                try {
                    //设置线程的优先级
                    android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
                    byte[] tempBuffer = new byte[buffersize];
                    int readCount = 0;
                    while (inputStream.available() > 0) {
                        readCount= inputStream.read(tempBuffer);
                        if (readCount == AudioTrack.ERROR_INVALID_OPERATION || readCount == AudioTrack.ERROR_BAD_VALUE) {
                            continue;
                        }
                        if (readCount != 0 && readCount != -1) {//一边播放一边写入语音数据
                            //判断AudioTrack未初始化,停止播放的时候释放了,状态就为STATE_UNINITIALIZED
                            if(mAudioTrack.getState() == mAudioTrack.STATE_UNINITIALIZED){
                                init();
                            }
                            mAudioTrack.play();
                            mAudioTrack.write(tempBuffer, 0, readCount);
                        }
                    }
                    stopPlay();//播放完就停止播放
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
        };

    停止播放

     public void stopPlay() {
            try {
                if (mAudioTrack != null) {
                    if (mAudioTrack.getState() == AudioRecord.STATE_INITIALIZED) {//初始化成功
                        mAudioTrack.stop();//停止播放
                    }
                    if (mAudioTrack != null) {
                        mAudioTrack.release();//释放audioTrack资源
                    }
                }
                if (inputStream != null) {
                    inputStream.close();//关闭数据输入流
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    完整代码

    package com.yuanxuzhen.androidmedia.audio;
    
    import android.media.AudioAttributes;
    import android.media.AudioFormat;
    import android.media.AudioManager;
    import android.media.AudioRecord;
    import android.media.AudioTrack;
    import android.os.Build;
    import android.provider.MediaStore;
    import android.util.Log;
    
    import androidx.annotation.RequiresApi;
    
    import java.io.DataInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class AudioTrackManager {
        private static volatile AudioTrackManager instance;
        private AudioTrack mAudioTrack;
        private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
        private int buffersize;
        private ExecutorService executorService;
        private DataInputStream inputStream;
    
        private AudioTrackManager() {
            init();
        }
    
        public static AudioTrackManager getInstance() {
            if (instance == null) {
                synchronized (AudioTrackManager.class) {
                    if (instance == null) {
                        instance = new AudioTrackManager();
                    }
                }
            }
            return instance;
        }
    
        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        private void init() {
            executorService = Executors.newCachedThreadPool();
            AudioFormat.Builder builder = new AudioFormat.Builder();
            builder.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
                    .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                    .setSampleRate(44100);
            AudioFormat audioFormat = builder.build();
    
            buffersize = AudioTrack.getMinBufferSize(44100,
                    AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT);
            Log.e("yuanAudioTrack", "init buffersize=" + buffersize);
            AudioAttributes audioAttributes = (new AudioAttributes.Builder()).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build();
            mAudioTrack = new AudioTrack(
                    audioAttributes,
                    audioFormat,
                    buffersize,
                    AudioTrack.MODE_STREAM,
                    AudioManager.AUDIO_SESSION_ID_GENERATE
            );
    
        }
    
    
        /**
         * 播放线程
         */
        Runnable recordRunnable = new Runnable() {
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void run() {
                try {
                    //设置线程的优先级
                    android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
                    byte[] tempBuffer = new byte[buffersize];
                    int readCount = 0;
                    while (inputStream.available() > 0) {
                        readCount= inputStream.read(tempBuffer);
                        if (readCount == AudioTrack.ERROR_INVALID_OPERATION || readCount == AudioTrack.ERROR_BAD_VALUE) {
                            continue;
                        }
                        if (readCount != 0 && readCount != -1) {//一边播放一边写入语音数据
                            //判断AudioTrack未初始化,停止播放的时候释放了,状态就为STATE_UNINITIALIZED
                            if(mAudioTrack.getState() == mAudioTrack.STATE_UNINITIALIZED){
                                init();
                            }
                            mAudioTrack.play();
                            mAudioTrack.write(tempBuffer, 0, readCount);
                        }
                    }
                    stopPlay();//播放完就停止播放
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
        };
    
    
        private void setPath(String path) throws Exception {
            File file = new File(path);
            inputStream = new DataInputStream(new FileInputStream(file));
        }
    
        public void stopPlay() {
            try {
                if (mAudioTrack != null) {
                    if (mAudioTrack.getState() == AudioRecord.STATE_INITIALIZED) {//初始化成功
                        mAudioTrack.stop();//停止播放
                    }
                    if (mAudioTrack != null) {
                        mAudioTrack.release();//释放audioTrack资源
                    }
                }
                if (inputStream != null) {
                    inputStream.close();//关闭数据输入流
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void startPlay(String path) {
            try {
                setPath(path);
                executorService.execute(recordRunnable);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    

    gitee地址

    https://gitee.com/creat151/android-media.git

    展开全文
  • AudioTrack

    AudioTrack

    展开全文
  • audiotrack 播放音频

    2016-06-15 16:04:50
    audiotrack 播放音频
  • AudioTrack过程

    2019-04-29 14:23:03
    AudioTrack流程

    AudioTrack流程

    应用层设置声音类型

    设置属性

    说明: 根据应用层设置的声音类型设置属性
    framework/av/media/libmedia/AudioTrack.cpp
    AudioTrack::setAttributesFromStreamType

    2067 void AudioTrack::setAttributesFromStreamType(audio_stream_type_t streamType) {  
    2068     mAttributes.flags = 0x0;                                                                             
    2069                                                                                                          
    2070     switch(streamType) {                                                                                 
    2071     case AUDIO_STREAM_DEFAULT:                                                                           
    2072     case AUDIO_STREAM_MUSIC:                                                                             
    2073         mAttributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;                    
    2074         mAttributes.usage = AUDIO_USAGE_MEDIA;                                                           
    2075         break;                                                                                           
    2076     case AUDIO_STREAM_VOICE_CALL:                                                                        
    2077         mAttributes.content_type = AUDIO_CONTENT_TYPE_SPEECH;                   
    2078         mAttributes.usage = AUDIO_USAGE_VOICE_COMMUNICATION;                    
    2079         break;                                                                                           
    2080     case AUDIO_STREAM_ENFORCED_AUDIBLE:                                                                  
    2081         mAttributes.flags  |= AUDIO_FLAG_AUDIBILITY_ENFORCED; 
    

    根据streamType设置content_type、usage和flags。

    确定类别/组

    根据声音属性确定它的类别/组
    frameworks/av/services/audiopolicy/AudioPolicyManager.cpp
    AudioPolicyManager::getStrategyForAttr

    3921 uint32_t AudioPolicyManager::getStrategyForAttr(const audio_attributes_t *attr) {                                                                                                               
    3922     // flags to strategy mapping                                                
    3923     if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) {
    3924         return (uint32_t) STRATEGY_ENFORCED_AUDIBLE;                            
    3925     }                                                                           
    3926                                                                                 
    3927     // usage to strategy mapping                                                
    3928     switch (attr->usage) {                                                      
    3929     case AUDIO_USAGE_MEDIA:                                                     
    3930     case AUDIO_USAGE_GAME:                                                      
    3931     case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:                                  
    3932     case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:                            
    3933     case AUDIO_USAGE_ASSISTANCE_SONIFICATION:                                   
    3934         return (uint32_t) STRATEGY_MEDIA;                                       
    3935                                                                                 
    3936     case AUDIO_USAGE_VOICE_COMMUNICATION:                                       
    3937         return (uint32_t) STRATEGY_PHONE;                                       
    3938                                                                                 
    3939     case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:                            
    3940         return (uint32_t) STRATEGY_DTMF;                                        
    3941                                                                                 
    3942     case AUDIO_USAGE_ALARM:                                                     
    3943     case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:                           
    3944         return (uint32_t) STRATEGY_SONIFICATION;                                
    3945                                                                                 
    3946     case AUDIO_USAGE_NOTIFICATION:                                              
    3947     case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:                        
    3948     case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:                        
    3949     case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:                        
    3950     case AUDIO_USAGE_NOTIFICATION_EVENT:                                        
    3951         return (uint32_t) STRATEGY_SONIFICATION_RESPECTFUL;                     
    3952                                                                                 
    3953     case AUDIO_USAGE_UNKNOWN:                                                   
    3954     default:                                                                    
    3955         return (uint32_t) STRATEGY_MEDIA;                                       
    3956     }                                                                           
    3957 } 
    

    确定播放设备

    根据声音类别/组确定播放(耳机/蓝牙/喇叭)
    在这里插入图片描述
    AudioPolicyManager::getDeviceForStrategy
    如果在应用层选的是AUDIO_STREAM_VOICE_CALL,对应的strategy是STRATEGY_PHONE,分析下函数策略:

    3970 audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
    3971                                                              bool fromCache)                                                                                                                    
    3972 {                                                                               
    3973     uint32_t device = AUDIO_DEVICE_NONE;                                        
    3974                                                                                 
    3975     if (fromCache) {                                                            
    3976         ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",      
    3977               strategy, mDeviceForStrategy[strategy]);                          
    3978         return mDeviceForStrategy[strategy];                                    
    3979     }                                                                           
    3980     audio_devices_t availableOutputDeviceTypes = mAvailableOutputDevices.types();
    3981     switch (strategy) {
    4020     case STRATEGY_PHONE:                                                        
    4021         // Force use of only devices on primary output if:                                                                                                                                      
    4022         // - in call AND                                                        
    4023         //   - cannot route from voice call RX OR                               
    4024         //   - audio HAL version is < 3.0 and TX device is on the primary HW module
    4025         if (mPhoneState == AUDIO_MODE_IN_CALL) {                                
    4026             audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
    4027             sp<AudioOutputDescriptor> hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);
    4028             if (((mAvailableInputDevices.types() &                              
    4029                     AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) ||
    4030                     (((txDevice & availablePrimaryInputDevices() & ~AUDIO_DEVICE_BIT_IN) != 0) &&
    4031                          (hwOutputDesc->getAudioPort()->mModule->mHalVersion <  
    4032                              AUDIO_DEVICE_API_VERSION_3_0))) {                  
    4033                 availableOutputDeviceTypes = availablePrimaryOutputDevices();   
    4034             }                                                                   
    4035         }                                                                       
    4036         // for phone strategy, we first consider the forced use and then the available devices by order
    4037         // of priority                                                          
    4038         switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {              
    4039         case AUDIO_POLICY_FORCE_BT_SCO:   //蓝牙                                      
    4040             if (!isInCall() || strategy != STRATEGY_DTMF) {                     
    4041                 device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT//蓝牙车载设备
    4042                 if (device) break;                                              
    4043             }                                                                   
    4044             device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET; //蓝牙耳机
    4045             if (device) break;                                                  
    4046             device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;  //
    4047             if (device) break;                                                  
    4048             // if SCO device is requested but no SCO device is available, fall back to default case
    4049             // FALL THROUGH                                                     
    4050                                                                                                                             
    4051         default:    // FORCE_NONE                                               
    4052             // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
    4053             if (!isInCall() &&                                                  
    4054                     (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
    4055                     (getA2dpOutput() != 0) && !mA2dpSuspended) {                
    4056                 device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;  //蓝牙立体声
    4057                 if (device) break;                                              
    4058                 device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;//蓝牙立体耳机
    4059                 if (device) break;                                              
    4060             }                                                                   
    4061             device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;//不带话筒的耳机
    4062             if (device) break;                                                  
    4063             device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADSET;//带话筒的耳机
    4064             if (device) break;                                                  
    4065             device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_DEVICE;   
    4066             if (device) break;                                                  
    4067             if (mPhoneState != AUDIO_MODE_IN_CALL) {                            
    4068                 device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_ACCESSORY;
    4069                 if (device) break;                                              
    4070                 device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;//
    4071                 if (device) break;                                              
    4072                 device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_AUX_DIGITAL;
    4073                 if (device) break;                                              
    4074                 device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;//
    4075                 if (device) break;                                              
    4076             }                                                                   
    4077             device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_EARPIECE;    //听筒
    4078             if (device) break;                                                  
    4079             device = mDefaultOutputDevice->mDeviceType;                         
    4080             if (device == AUDIO_DEVICE_NONE) {                                  
    4081                 ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
    4082             }                                                                   
    4083             break;   
    
    

    总结:
    安卓手机打电话时:

    1. 如果使用强制设备来播放声音,比如扬声器和蓝牙。
    2. 如果没有使用强制设备来播放
      2.1 如果连接上蓝牙车载导航,优先使用车载导航播放声音
      2.2 连上耳机 ,使用耳机播放声音
      2.3 如果蓝牙,耳机都没有连接,则使用扬声器来播放声音。

    确定outputs

    DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > mOutputs;
            class AudioOutputDescriptor: public AudioPortConfig
            {
            ..........
            const sp<IOProfile> mProfile;
            .....
            }
    

    配置文件格式如下:

     27   primary {                                                                     
     28     outputs {                                                                   
     29       primary {                                                                 
     30         sampling_rates 44100                                                    
     31         channel_masks AUDIO_CHANNEL_OUT_STEREO                                  
     32         formats AUDIO_FORMAT_PCM_16_BIT                                         
     33         devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ALL_SCO|AUDIO_DEVICE_OUT_AUX_DIGITAL
     34         flags AUDIO_OUTPUT_FLAG_PRIMARY                                         
     35       }                                                                         
     36     }  
    

    解析配置文件函数会把outputs选项中所有output放入到mOutputs中,显然这个配置文件中只有1个output。
    每个output所有内容都保存到mProfile中,这样mProfile包括devices也就是该output支持的设备列表。

    audio_io_handle_t AudioPolicyManager::getOutputForDevice(
            audio_devices_t device,
            audio_stream_type_t stream,
            uint32_t samplingRate,
            audio_format_t format,
            audio_channel_mask_t channelMask,
            audio_output_flags_t flags,
            const audio_offload_info_t *offloadInfo)
    {
    non_direct_output:
        // ignoring channel mask due to downmix capability in mixer
        // open a non direct output
        // for non direct outputs, only PCM is supported
        if (audio_is_linear_pcm(format)) {
            // get which output is suitable for the specified stream. The actual
            // routing change will happen when startOutput() will be called
            SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
            // at this stage we should ignore the DIRECT flag as no direct output could be found earlier
            flags = (audio_output_flags_t)(flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
            output = selectOutput(outputs, flags, format);
        }
        ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d,"
                "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags);
        ALOGV("getOutput() returns output %d", output);
        return output;
    }
    

    getOutputsForDevice(device, mOutputs);传输mOutputs就是配置文件中所有output选项的数组。

    SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(audio_devices_t device,
                            DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > openOutputs)
    {
        SortedVector<audio_io_handle_t> outputs;
    
        ALOGVV("getOutputsForDevice() device %04x", device);
        for (size_t i = 0; i < openOutputs.size(); i++) {
            ALOGVV("output %d isDuplicated=%d device=%04x",
                    i, openOutputs.valueAt(i)->isDuplicated(), openOutputs.valueAt(i)->supportedDevices());
            if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) {
                ALOGVV("getOutputsForDevice() found output %d", openOutputs.keyAt(i));
                outputs.add(openOutputs.keyAt(i));
            }
        }
        return outputs;
    }
    

    就是相应的device,轮询mOutputs所有的output中的device选项,查看每个output支持的device如果支持( if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) ),这把该output加入outputs数组中( outputs.add(openOutputs.keyAt(i)))。返回这个outputs数组。

    从outputs 选择output

            SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
    
            // at this stage we should ignore the DIRECT flag as no direct output could be found earlier
            flags = (audio_output_flags_t)(flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
            output = selectOutput(outputs, flags, format);
    

    在得到outputs数组,也就是device支持的output数组。调用selectOutput函数

    audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
                                                           audio_output_flags_t flags,
                                                           audio_format_t format)
    {
        // select one output among several that provide a path to a particular device or set of
        // devices (the list was previously build by getOutputsForDevice()).
        // The priority is as follows:
        // 1: the output with the highest number of requested policy flags
        // 2: the primary output
        // 3: the first output in the list
        }
    

    1
    a. APP创建AudioTrack时传入flag
    b. output对应的profle(/system/etc/audio_policy.conf)中也有flag
    c. 使用上述a,b的flag进行比较,取出吻合度最高的output,也就是两个flag中bit吻合度最高的。如果最高吻合的output不止一个执行步骤2。

    最高吻合的output中有primary output支持该设备,则选择primary output.

    如果最高吻合的output咩有primary output,则选择第一个output。

    后续

    1. 确定了output也就确定了playbackThread
      2)在playbackThread中创建了对应的track
      3)APP的AudioTrack和playbackThread的mTracks中的track之间建立共享内存。
    展开全文
  • I'm experimenting with AudioTrack class. Basically, my app has to generate a sound when the user touches a specific object on screen. I've used this example as a guide.My app seems to work as it shoul...
  • AudioTrack介绍

    2019-11-11 14:20:54
    原因:由于需要实现音频播放,故使用AudioTrack实现功能. 概况:音频播放可以使用MediaPlayer和AudioTrack两种方案,MediaPlayer可以播放多种格式的语音文件,例如.mp3,.wmv.等.而AudioTrack只能播放.pcm文件.通过...
  • AudioTrack.java

    2020-03-19 14:19:09
    使用AudioTrack进行播放时,将音频数据保存下来,保存为pcm格式,可以用于分析音频文件是否有问题。
  • audiotrack详解

    2011-12-29 13:23:02
    audiotrack是用来进行音频播放的类,用它来对播放进行控制
  • android AudioTrack

    2017-12-22 09:09:26
    AudioTrack 是一个音频播放器,这个类我们用很少,基本都是使用的是MediaPlayer 或者一些第三方的播放器,其实他们内部也都是调用的audioTrack,为什么不我们不直接使用audioTrack,首先是他支持播放的音频格式少,它...
  • AudioTrack 分析

    千次阅读 2018-09-10 17:11:29
    AudioTrack 分析 2015年12月05日 15:17:16 阅读数:1498更多 个人分类: android技术 ...AudioTrack主要是用来播放声音的,AudioTrack贯穿了JAVA层,JNI层和Native层。 AudioTrack JAVA层: fra...
  • AudioTrack 使用

    2021-04-03 14:50:27
    使用 AudioTrack 的静态成员,获取音频缓存区最小尺寸: static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) sampleRateInHz:音频采用率,常用的采样率有 8k、16k、...
  • AudioTrack学习

    2017-02-06 00:12:00
    AudioTrack主要是用来播放声音的,AudioTrack贯穿了Java层,JNI层和Native层。 AudioTrack JAVA层: framework\base\media\java\Android\media\AudioTrack.java 以AudioTrack的使用方法举例: [cpp]view ...
  • Android AudioTrack

    2018-06-08 14:46:35
    名词 PCM 脉冲编码调制(Pulse Code Modulation,PCM) A2DP A2DP全名是Advanced Audio Distribution Profile 蓝牙音频传输模型协定。...AudioTrack在JNI层使用了Native的AudioTrack对象 1.new...
  • AudioTrack_socket.zip

    2019-12-23 14:24:10
    Android9.0下使用AudioTrack解析,从socket服务端tcp传输过来的音频流裸数据的示例
  • AudioTrack播放流程

    2021-03-26 16:30:19
    AudioTrack介绍 音频播放声音分为MediaPlayer和AudioTrack两种方案的。MediaPlayer可以播放多种格式的声音文件,例如MP3,WAV,OGG,AAC,MIDI等。然而AudioTrack只能播放PCM数据流。当然两者之间还是有紧密的联系...
  • Android audiotrack 播放pcm

    2015-04-17 10:30:26
    实现用audiotrack播放pcm音频流
  • 主要为大家详细介绍了Android音频系统AudioTrack的使用方法,如何使用AudioTrack进行音频播放,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • AudioRecord和AudioTrack

    2015-01-27 20:43:42
    一个关于AudioRecord和AudioTrack的简单事例 通过录制得到PCM格式的音频,然后通过再用AudioTrack播放该文件
  • 初识AudioTrack

    千次阅读 2016-09-12 15:20:25
    AudioTrack是管理和播放单一音频资源的类。
  • Android 音频开发——AudioTrack播放

    千次阅读 热门讨论 2021-03-12 19:02:32
    AudioTrack类用来管理、播放单个音频资源,它只能播放PCM数据,其他音频格式(aac、amr、opus、flac等)需要经过解码成PCM才能使用。 运行模式 AudioTrack可以运行两种模式: 流模式 静态模式 流模式  可以将...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,585
精华内容 2,634
关键字:

audiotrack