| | |
| | | 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; |
| | |
| | | import com.anyun.libusbcamera.UsbCamera; |
| | | import com.safeluck.floatwindow.MediaArgu; |
| | | import com.safeluck.floatwindow.ResponseVO; |
| | | import com.safeluck.floatwindow.util.AudioRecordManager; |
| | | |
| | | /** |
| | | * USB摄像头推流管理器 |
| | |
| | | |
| | | // 预览 SurfaceView 和隐藏的 Window |
| | | private WindowManager windowManager; |
| | | |
| | | // 音频推流线程池(单线程) |
| | | private ExecutorService audioPushExecutor; |
| | | |
| | | /** |
| | | * 推流回调接口 |
| | |
| | | public void stopPush() { |
| | | Timber.d("stopPush called"); |
| | | stopPushThread(); |
| | | stopAudioTransfer(); |
| | | releaseAlivcPusher(); |
| | | if (usbCamera != null) { |
| | | usbCamera.stopCamera(); |
| | |
| | | public void onPushStarted(AlivcLivePusher alivcLivePusher) { |
| | | Timber.d("onPushStarted"); |
| | | pushStarted = true; |
| | | startAudioTransfer(); |
| | | notifyCallback(1, 0, "推流已开始,分辨率: " + resolutionArr[0] + "x" + resolutionArr[1]); |
| | | } |
| | | |
| | |
| | | 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("音频推流线程池已关闭"); |
| | | } |
| | | } |
| | | } |