| app/src/main/java/com/safeluck/floatwindow/manager/UsbCameraPushManager.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/safeluck/floatwindow/util/AudioRecordManager.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
app/src/main/java/com/safeluck/floatwindow/manager/UsbCameraPushManager.java
@@ -7,6 +7,9 @@ import android.view.SurfaceView; import android.view.WindowManager; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.alivc.live.pusher.AlivcAudioAACProfileEnum; import timber.log.Timber; import com.alivc.live.pusher.AlivcEncodeModeEnum; @@ -26,6 +29,7 @@ import com.anyun.libusbcamera.UsbCamera; import com.safeluck.floatwindow.MediaArgu; import com.safeluck.floatwindow.ResponseVO; import com.safeluck.floatwindow.util.AudioRecordManager; /** * USB摄像头推流管理器 @@ -60,6 +64,9 @@ // 预览 SurfaceView 和隐藏的 Window private WindowManager windowManager; // 音频推流线程池(单线程) private ExecutorService audioPushExecutor; /** * 推流回调接口 @@ -132,6 +139,7 @@ public void stopPush() { Timber.d("stopPush called"); stopPushThread(); stopAudioTransfer(); releaseAlivcPusher(); if (usbCamera != null) { usbCamera.stopCamera(); @@ -293,6 +301,7 @@ public void onPushStarted(AlivcLivePusher alivcLivePusher) { Timber.d("onPushStarted"); pushStarted = true; startAudioTransfer(); notifyCallback(1, 0, "推流已开始,分辨率: " + resolutionArr[0] + "x" + resolutionArr[1]); } @@ -624,4 +633,52 @@ callback.onResult(response); } } private void startAudioTransfer() { Timber.i("开始通过mic录制声音,上传"); // 创建单线程线程池用于音频推流 if (audioPushExecutor == null || audioPushExecutor.isShutdown()) { audioPushExecutor = Executors.newSingleThreadExecutor(r -> { Thread thread = new Thread(r, "AudioPushThread"); thread.setDaemon(true); return thread; }); } AudioRecordManager.getInstance().startRecording((data, size) -> { if (alivcPusher != null && audioPushExecutor != null && !audioPushExecutor.isShutdown()) { // 在单线程线程池中执行音频推流 audioPushExecutor.execute(() -> { try { alivcPusher.inputStreamAudioData(data, data.length, System.nanoTime() / 1000); } catch (Exception e) { Timber.e(e, "Error pushing audio data"); } }); } }); } private void stopAudioTransfer() { Timber.i("停止通过mic录制声音,上传"); AudioRecordManager.getInstance().stopRecording(); // 停止并关闭音频推流线程池 if (audioPushExecutor != null && !audioPushExecutor.isShutdown()) { audioPushExecutor.shutdown(); try { // 等待最多1秒让任务完成 if (!audioPushExecutor.awaitTermination(1, java.util.concurrent.TimeUnit.SECONDS)) { audioPushExecutor.shutdownNow(); } } catch (InterruptedException e) { audioPushExecutor.shutdownNow(); Thread.currentThread().interrupt(); } audioPushExecutor = null; Timber.d("音频推流线程池已关闭"); } } } app/src/main/java/com/safeluck/floatwindow/util/AudioRecordManager.java
New file @@ -0,0 +1,123 @@ package com.safeluck.floatwindow.util; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.os.Environment; import android.util.Log; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * aaa * Created by lzw on 2019/8/29. 11:19:57 * 邮箱:632393724@qq.com * All Rights Saved! Chongqing AnYun Tech co. LTD */ public class AudioRecordManager { private static final String TAG = "AudioRecordManager"; private static AudioRecordManager instance; /***标记是否正在录音**/ private boolean isRecording = false; private AudioRecord audioRecord; /***最小缓冲区大小*/ private int bufferSize = 0; /***采样率*/ private int sampleRateInHz = 32000; /***量化位数**/ private int audioFormat = AudioFormat.ENCODING_PCM_16BIT; /***存放音频数据的buffer**/ private byte[] buffer; private int channelConf = AudioFormat.CHANNEL_IN_STEREO; private OnAudioRecordListener onAudioRecordListener; private AudioRecordManager() { //计算最小缓冲区 bufferSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConf, audioFormat); // bufferSize = bufferSize > 320 ? 320 : bufferSize; Log.i(TAG,"mini buffersize="+bufferSize); audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConf, audioFormat, bufferSize); } public static AudioRecordManager getInstance() { if (instance == null) { synchronized (AudioRecordManager.class) { if (instance == null) { instance = new AudioRecordManager(); } } } return instance; } /*** * 开始采集音频 */ public void startRecording(final OnAudioRecordListener onAudioRecordListener) { setAudioRecordListener(onAudioRecordListener); if (audioRecord == null){ audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConf, audioFormat, bufferSize); } buffer = new byte[bufferSize]; isRecording = true; audioRecord.startRecording(); try { while (isRecording){ int readSize = audioRecord.read(buffer,0,bufferSize); Log.i(TAG, "run: buffer length"+buffer.length+" readSize="+readSize); if (onAudioRecordListener != null){ onAudioRecordListener.onVoiceRecord(buffer,bufferSize); } } audioRecord.stop(); destroy(); } catch (Exception e) { e.printStackTrace(); } } /*** * 停止音频采集 */ public void stopRecording(){ Log.i(TAG, "stopRecording"); isRecording = false; setAudioRecordListener(null); } public void destroy(){ if (audioRecord!=null){ audioRecord.release(); audioRecord = null; } } public interface OnAudioRecordListener { /*** * 采集到的音频信息回调到上层 * @param data * @param size */ void onVoiceRecord(byte[] data,int size); } private void setAudioRecordListener(OnAudioRecordListener onAudioRecordListener){ this.onAudioRecordListener = onAudioRecordListener; } }