Android音视频开发 — AudioTrack的使用

   日期:2021-03-01     浏览:93    评论:0    
核心提示:AudioTrack类为Java应用程序管理和播放单个音频资源。它允许PCM音频缓冲区流到音频接收器进行播放

AudioTrack的使用

    • 简介
    • 使用
    • 测试

简介

AudioTrack类为Java应用程序管理和播放单个音频资源。它允许PCM音频缓冲区流到音频接收器进行播放。

AudioTrack有两个模式

模式 解释 作用范围
静态模式(MODE_STATIC) 这种模式下,在play之前只需要把所有数据通过一次write调用传递到AudioTrack中的内部缓冲区 在处理适合内存的短声音以及需要以尽可能小的延迟播放时,应选择静态模式
流模式(MODE_STREAM) 以流的形式持续把音频数据写到AudioTrack内部的Buffer中 由于音频数据的特性(高采样率、每采样位数…)太大而无法放入内存的 等等

使用

1、加上读取文件的权限

 <uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE" />

2、因用到系统的文件做耗时操作所以需要用到AsyncTask

3、最主要的是public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes)方法
第一个参数是 保存要播放的数据的数组

第二个参数是 在音频数据中,以字节表示的偏移量,其中要写入的数据 (我也不是清楚,希望有大佬能解释一下,建议写0就好)

第三个参数是 写入音频数据的字节数

4、具体解释请看下面的代码

package com.audioandvideo.two.Activity;

import androidx.appcompat.app.AppCompatActivity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.audioandvideo.R;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;


public class AudioTrackActivity extends AppCompatActivity implements View.OnClickListener{ 
    private Button btnStatic;
    private Button btnStream;
    private AudioTrack audioTrack;
    private byte[] audioData;

    // 采样率:音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高
    // 44100是目前的标准,但是某些设备仍然支持22050,16000,11025
    // 采样频率一般共分为22.05KHz、44.1KHz、48KHz三个等级
    private final int AUDIO_SAMPLE_RATE = 44100;

    // 声道设置:android支持双声道立体声和单声道。MONO单声道,STEREO立体声
    private final  int AUDIO_CHANNEL = AudioFormat.CHANNEL_OUT_STEREO;

    // 编码制式和采样大小:采集来的数据当然使用PCM编码
    // (脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。)
    // android支持的采样大小16bit 或者8bit。当然采样大小越大,那么信息量越多,音质也越高,现在主流的采样
    // 大小都是16bit,在低质量的语音传输的时候8bit 足够了。
    private final  int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
    //要播放的pcm文件的储存位置及文件名
    private final String pcmFileName = Environment.getExternalStorageDirectory() + "/Download/record.pcm";
    @Override
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_audio_track);
        btnStatic = findViewById(R.id.btn_static);
        btnStream = findViewById(R.id.btn_stream);
        btnStatic.setOnClickListener(this);
        btnStream.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) { 
        switch (v.getId()){ 
            case R.id.btn_static:
                new AsyncStatic().execute();
                break;
            case R.id.btn_stream:
                new AsyncStream().execute();
                break;
        }
    }

    
   private class AsyncStatic extends AsyncTask{ 
       
       @Override
       protected Object doInBackground(Object[] objects) { 
           try { 
               InputStream in = new FileInputStream(new File(pcmFileName));
               try { 
         //字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中。
                   ByteArrayOutputStream out = new ByteArrayOutputStream();
                   for (int b; (b = in.read()) != -1; ) { 
                       out.write(b);
                   }
                   //创建一个新分配的字节数组。数组的大小和当前输出流的大小,内容是当前输出流的拷贝。
                   audioData = out.toByteArray();
               } finally { 
                   //最后关闭文件
                   in.close();
               }
           } catch (IOException e) { 
           }
           return null;
       }

       
       @Override
       protected void onPostExecute(Object o) { 

           audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, AUDIO_SAMPLE_RATE,
                   AUDIO_CHANNEL, AUDIO_ENCODING, audioData.length,AudioTrack.MODE_STATIC);
           audioTrack.write(audioData, 0, audioData.length); //将音频数据写入音频接收器以便播放
           audioTrack.play();//开始播放
       }
   }

    
   private class AsyncStream extends AsyncTask{ 

       @Override
       protected Object doInBackground(Object[] objects) { 
           final int minBufferSize = AudioTrack.getMinBufferSize(AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING);
           audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, AUDIO_SAMPLE_RATE,
                  AUDIO_CHANNEL, AUDIO_ENCODING, minBufferSize, AudioTrack.MODE_STREAM);//最后一个参数为audioTrack的模式
           audioTrack.play();

           File file = new File(pcmFileName);
           //从文件系统中的某个文件中获得输入字节
           FileInputStream fileInputStream = null;
           try { 
               fileInputStream = new FileInputStream(file);
           } catch (FileNotFoundException e) { 
               e.printStackTrace();
           }
           byte[] tempBuffer = new byte[minBufferSize];
           while (true) { 
               try { 
                   if (!(fileInputStream.available() > 0)) { 
                       stop();            //停止播放
                       break;
                   }
// fileInputStream.read(tempBuffer)返回读入缓冲区的总字节数;如果因为已经到达流末尾而不再有数据可用,则返回 -1。
                   int readCount = fileInputStream.read(tempBuffer);
                   Log.d("TAG", "doInBackground:"+String.valueOf(readCount));
                   if (readCount == AudioTrack.ERROR_INVALID_OPERATION ||
                           readCount == AudioTrack.ERROR_BAD_VALUE) { 
                       continue;
                   }
                   if (readCount != 0 && readCount != -1) { 
                       //将音频数据写入音频接收器以便播放
                       audioTrack.write(tempBuffer, 0, readCount);
                   }
               } catch (IOException e) { 
                   e.printStackTrace();
               }

           }
           return null;
       }
   }
//停止播放
   private void stop(){ 
       if(audioTrack.getState() != AudioTrack.STATE_UNINITIALIZED){ 
           audioTrack.stop();
           audioTrack.release();
       }
   }
}

测试

界面只有两个简单的按钮进行测试,均能播放。

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服