Android音视频开发之音频录制和播放

时间:2025-03-08 22:19:04
  • package ;
  • import ;
  • import android.content.Context;
  • import android.content.;
  • import ;
  • import ;
  • import ;
  • import ;
  • import ;
  • import .Environment;
  • import ;
  • import ;
  • import .format.DateFormat;
  • import ;
  • import ;
  • import ;
  • import ;
  • import ;
  • import ;
  • import ;
  • import .File;
  • import ;
  • import ;
  • import ;
  • import ;
  • import ;
  • import .ref.WeakReference;
  • import ;
  • import ;
  • import ;
  • import .Locale;
  • import ;
  • import ;
  • import ;
  • /**
  • * @author: njb
  • * @date: 2023/2/25 18:29
  • * @desc:
  • */
  • public class RecorderAudioManagerUtils {
  • private static final String TAG = "PlayManagerUtils";
  • private WeakReference<Context> weakReference;
  • private File recordFile;
  • private boolean isRecording;
  • /**
  • * 最多只能存2条记录
  • */
  • private final List<File> filePathList = new ArrayList<>(2);
  • /**
  • * 16K采集率
  • */
  • int sampleRateInHz = 16000;
  • /**
  • * 格式
  • */
  • int channelConfiguration = AudioFormat.CHANNEL_OUT_STEREO;
  • /**
  • * 16Bit
  • */
  • int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
  • private static volatile RecorderAudioManagerUtils mInstance;
  • private final Handler handler = new Handler(());
  • AudioRecord audioRecord;
  • ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 1, , new LinkedBlockingDeque<>(10));
  • public static RecorderAudioManagerUtils getInstance() {
  • if (mInstance == null) {
  • synchronized (RecorderAudioManagerUtils.class) {
  • if (mInstance == null) {
  • mInstance = new RecorderAudioManagerUtils();
  • }
  • }
  • }
  • return mInstance;
  • }
  • public void startRecord(WeakReference<Context> weakReference) {
  • = weakReference;
  • (TAG, "开始录音");
  • //生成PCM文件
  • String fileName = DateFormat.format("yyyy-MMdd-HHmmss", (Locale.getDefault())) + ".pcm";
  • File file = new File(Environment.getExternalStorageDirectory(), "/ACC音频/");
  • if (!file.exists()) {
  • file.mkdir();
  • }
  • String audioSaveDir = file.getAbsolutePath();
  • (TAG, audioSaveDir);
  • recordFile = new File(audioSaveDir, fileName);
  • (TAG, "生成文件" + recordFile);
  • //如果存在,就先删除再创建
  • if (()) {
  • recordFile.delete();
  • (TAG, "删除文件");
  • }
  • try {
  • ();
  • (TAG, "创建文件");
  • } catch (IOException e) {
  • (TAG, "未能创建");
  • throw new IllegalStateException("未能创建" + ());
  • }
  • if (filePathList.size() == 2) {
  • ();
  • }
  • filePathList.add(recordFile);
  • try {
  • //输出流
  • OutputStream os = new FileOutputStream(recordFile);
  • BufferedOutputStream bos = new BufferedOutputStream(os);
  • DataOutputStream dos = new DataOutputStream(bos);
  • int bufferSize = (sampleRateInHz, AudioFormat.CHANNEL_IN_STEREO, audioEncoding);
  • if ((weakReference.get(), .RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
  • return;
  • }
  • audioRecord = new AudioRecord(, sampleRateInHz, AudioFormat.CHANNEL_IN_STEREO, audioEncoding, bufferSize);
  • short[] buffer = new short[bufferSize];
  • ();
  • (TAG, "开始录音");
  • isRecording = true;
  • while (isRecording) {
  • int bufferReadResult = audioRecord.read(buffer, 0, bufferSize);
  • for (int i = 0; i < bufferReadResult; i++) {
  • (buffer[i]);
  • }
  • }
  • audioRecord.stop();
  • dos.close();
  • } catch (Exception e) {
  • ();
  • (TAG, "录音失败");
  • showToast("录音失败");
  • }
  • }
  • /**
  • * 播放pcm流的方法,一次性读取所有Pcm流,读完后在开始播放
  • */
  • public void playAllRecord() {
  • if (recordFile == null) {
  • return;
  • }
  • //读取文件
  • int musicLength = (int) (recordFile.length() / 2);
  • short[] music = new short[musicLength];
  • try {
  • InputStream is = new FileInputStream(recordFile);
  • BufferedInputStream bis = new BufferedInputStream(is);
  • DataInputStream dis = new DataInputStream(bis);
  • int i = 0;
  • while (() > 0) {
  • music[i] = ();
  • i++;
  • }
  • dis.close();
  • AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, channelConfiguration, audioEncoding, musicLength * 2, AudioTrack.MODE_STREAM);
  • ();
  • audioTrack.write(music, 0, musicLength);
  • audioTrack.stop();
  • } catch (Throwable t) {
  • (TAG, "播放失败");
  • showToast("播放失败");
  • }
  • }
  • public void playPcm(boolean isChecked) {
  • try {
  • if (isChecked) {
  • //两首一起播放
  • for (File recordFiles : filePathList) {
  • (() -> playPcmData(recordFiles));
  • }
  • } else {
  • //只播放最后一次录音
  • playPcmData(recordFile);
  • }
  • }catch (Exception e){
  • ();
  • }
  • }
  • /**
  • * 播放Pcm流,边读取边播
  • */
  • public void playPcmData(File recordFiles) {
  • (TAG, "打印线程" + ().getName());
  • try {
  • DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(recordFiles)));
  • //最小缓存区
  • int bufferSizeInBytes = (sampleRateInHz, AudioFormat.CHANNEL_OUT_STEREO, audioEncoding);
  • AudioTrack player = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, AudioFormat.CHANNEL_OUT_STEREO, audioEncoding, bufferSizeInBytes, AudioTrack.MODE_STREAM);
  • short[] data = new short[bufferSizeInBytes];
  • //开始播放
  • ();
  • while (true) {
  • int i = 0;
  • while (() > 0 && i < data.length) {
  • data[i] = ();
  • i++;
  • }
  • player.write(data, 0, data.length);
  • //表示读取完了
  • if (i != bufferSizeInBytes) {
  • player.stop();//停止播放
  • player.release();//释放资源
  • dis.close();
  • showToast("播放完成了!!!");
  • break;
  • }
  • }
  • } catch (Exception e) {
  • (TAG, "播放异常: " + ());
  • showToast("播放异常!!!!");
  • ();
  • }
  • }
  • public File getRecordFile() {
  • return recordFile;
  • }
  • public void setRecord(boolean isRecording) {
  • = isRecording;
  • }
  • public void pauseAudio(){
  • if(audioRecord != null ){
  • audioRecord.stop();
  • }
  • }
  • public void releaseAudio(){
  • if(audioRecord != null){
  • audioRecord.release();
  • }
  • if(handler != null){
  • (null);
  • }
  • if(threadPoolExecutor != null){
  • ();
  • }
  • }
  • private void showToast(String msg) {
  • if(weakReference.get() != null){
  • (() -> (weakReference.get(), msg, Toast.LENGTH_LONG).show());
  • }
  • }
  • }