使用AndroidTrack播放pcm音频

package com.tlinux.mp3playeraudiotrack;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;

/**
 * Created by tlinux on 18-8-11.
 */

public class SimpleAudioOutput {

    private static final String TAG = "AudioOutputTrack";
    public static final int SAMPLES_PER_FRAME = 2;
    public static final int BYTES_PER_SAMPLE = 4;
    public static final int BYTES_PRE_FRAME = SAMPLES_PER_FRAME * BYTES_PER_SAMPLE;
    private AudioTrack mAudioTrack;
    private int mFrameRate;
    private int minBufferSize;

    public SimpleAudioOutput() {
        super();
    }

    public void start(int frameRate) {
        stop();
        mFrameRate = frameRate;
        mAudioTrack = createAudioTrack(frameRate);
        mAudioTrack.play();
    }

    public AudioTrack createAudioTrack(int frameRate) {
        int minBufferSizeBytes = AudioTrack.getMinBufferSize(frameRate,
                AudioFormat.CHANNEL_OUT_STEREO,AudioFormat.ENCODING_PCM_16BIT);
        Log.i(TAG, "AudioTrack.minBufferSize = " + minBufferSizeBytes
                                 + " bytes = " + (minBufferSizeBytes / BYTES_PRE_FRAME)
                              + " frames");
        int bufferSize = 8*minBufferSizeBytes/8;
        minBufferSize = bufferSize;
        int outputBufferSizeFrames = bufferSize/BYTES_PRE_FRAME;
        Log.i(TAG, "actual bufferSize = " + bufferSize + " bytes = " + outputBufferSizeFrames + " frames");

        AudioTrack player = new AudioTrack(AudioManager.STREAM_MUSIC,mFrameRate,
                AudioFormat.CHANNEL_OUT_STEREO,AudioFormat.ENCODING_PCM_16BIT,
                bufferSize,AudioTrack.MODE_STREAM);

        Log.i(TAG, "created AudioTrack");
        return player;
    }


    public int write(byte[] buffer, int offset, int length) {
        return mAudioTrack.write(buffer,offset,length);
    }

    public void stop() {
        if (mAudioTrack != null) {
            mAudioTrack.stop();
        }
    }

    public int getFrameRate() {
        return mFrameRate;
    }

    public AudioTrack getAudioTrack() {
        return mAudioTrack;
    }

    public int getMinBufferSize() {
        return minBufferSize;
    }

}

主要介绍AudioTrack的使用方法

 AudioTrack player = new AudioTrack(AudioManager.STREAM_MUSIC,mFrameRate,
                 AudioFormat.CHANNEL_OUT_STEREO,AudioFormat.ENCODING_PCM_16BIT,
                 bufferSize,AudioTrack.MODE_STREAM);

构造方法需要传递上面的几个参数

  • AudioManager.STREAM_MUSIC 音频的STREAM_MUSIC,系统会对不同音频类型进行优先级管理,另外调节音量的时候也会根据不同的STREAM类型进行调节
  • AudioFormat.CHANNEL_OUT_STEREO 表示立体声,支持左右声道
  • AudioFormat.ENCODING_PCM_16BIT 编码格式,ENCODING_PCM_16BIT代表录制的时候每一个采样数据用16bit(2字节表示),编码格式占用的字节越多,声音越细腻
  • bufferSize:使用 AudioTrack的getMinBufferSize(frameRate,
    AudioFormat.CHANNEL_OUT_STEREO,AudioFormat.ENCODING_PCM_16BIT) 方法计算出来的,系统会根据要设置的帧率,通道数和编码格式计算出来一个最小支持的缓冲区大小(和系统先机制有关,后面文章会进行分析),创建AudioTrac时候,会根据传递的bufferSize创建缓冲区,注意如果传递的bufferSize小于getMinBufferSize计算出来的值,会创建不成功
  • AudioTrack.MODE_STREAM 表示以流的方式操作AudioTrak,以流的方式要使用mAudioTrack.write(buffer,offset,length) 不断将数据写入.另外一种模式是MODE_STATIC,这种模式是直接将数据加载进内存,传递给AudioTrack处理,由于pcm数据占用内存比较大,这种模式只适合提示音等短音频
mAudioTrack.write(buffer,offset,length)

这就是流模式写入数据的方法,注意当底层提供的缓冲区写满后该方法会阻塞住(底层采用生产者消费者模型,当消费者进行一些消费后,buffer能够完全写入后返回)

AudioTrack就是这么简单生产消费者模型等操作都在底层完成,使用者不需要考虑.

下面介绍一下如何使用ffmpeg获取pcm裸音频数据

ffmpeg -i jiangzhende.mp3 -f s16le  -ar 44100 -ac 2 -acodec pcm_s16le xxx.pcm 
  • -i 制定输入文件
  • -f 指定输出编码格式为16byte小端格式
  • -ar指定输出采样率
  • -ac 指定输出通道数
  • acodec 指定解码格式
  • xxx.pcm 为输出文件
tlinux@tlinux:~/media$ ffmpeg -i jiangzhende.mp3 -f s16le  -ar 44100 -ac 2 -acodec pcm_s16le xxx.pcm 
ffmpeg version 3.0.7-0ubuntu0.16.10.1 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 6.2.0 (Ubuntu 6.2.0-5ubuntu12) 20161005
  configuration: --prefix=/usr --extra-version=0ubuntu0.16.10.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --cc=cc --cxx=g++ --enable-gpl --enable-shared --disable-stripping --disable-decoder=libopenjpeg --disable-decoder=libschroedinger --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librubberband --enable-librtmp --enable-libschroedinger --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzvbi --enable-openal --enable-opengl --enable-x11grab --enable-libdc1394 --enable-libiec61883 --enable-libzmq --enable-frei0r --enable-chromaprint --enable-libx264
  libavutil      55. 17.103 / 55. 17.103
  libavcodec     57. 24.102 / 57. 24.102
  libavformat    57. 25.100 / 57. 25.100
  libavdevice    57.  0.101 / 57.  0.101
  libavfilter     6. 31.100 /  6. 31.100
  libavresample   3.  0.  0 /  3.  0.  0
  libswscale      4.  0.100 /  4.  0.100
  libswresample   2.  0.101 /  2.  0.101
  libpostproc    54.  0.100 / 54.  0.100
[mp3 @ 0x55f314cdfcc0] Skipping 0 bytes of junk at 260803.
[mjpeg @ 0x55f314ce17e0] Changing bps to 8
Input #0, mp3, from 'jiangzhende.mp3':
  Metadata:
    encoder         : Lavf56.4.101
    album           : 不要你为难
    title           : 讲真的
    artist          : 曾惜
    album_artist    : 曾惜
    disc            : 1
    track           : 2
  Duration: 00:03:59.02, start: 0.025056, bitrate: 328 kb/s

Stream #0:0: Audio: mp3, 44100 Hz, stereo, s16p, 320 kb/s Stream    #0:1: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 2000x2000 [SAR 72:72 DAR 1:1], 90k tbr, 90k tbn, 90k tbc

    Metadata:
      comment         : Other
Output #0, s16le, to 'xxx.pcm':
  Metadata:
    track           : 2
    album           : 不要你为难
    title           : 讲真的
    artist          : 曾惜
    album_artist    : 曾惜
    disc            : 1
    encoder         : Lavf57.25.100
    Stream #0:0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s
    Metadata:
      encoder         : Lavc57.24.102 pcm_s16le
Stream mapping:
  Stream #0:0 -> #0:0 (mp3 (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
size=   41171kB time=00:03:58.99 bitrate=1411.2kbits/s speed= 475x    
video:0kB audio:41171kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%

Stream #0:0: Audio: mp3, 44100 Hz, stereo, s16p, 320 kb/s Stream #0:1: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 2000x2000 [SAR 72:72 DAR 1:1], 90k tbr, 90k tbn, 90k tbc
从ffmpeg的输出可以看出,原来的mp3音频采用44100HZ采样率,stereo立体声双通道,s16p编码格式,所以我们在进行pm3转pcm的时候尽量采用相同的采样率,通道数和编码格式,以保证转换出来的pcm音频不失真

完整实例请参考
https://github.com/TangGee/PlayPcmByAudioTrack

猜你喜欢

转载自blog.csdn.net/woai110120130/article/details/81603848