| | |
| | | // 音频推流线程池(单线程) |
| | | private ExecutorService audioPushExecutor; |
| | | |
| | | // 保护 alivcPusher / previewSurfaceView 等生命周期,避免 start/stop 并发导致 NPE |
| | | private final Object pusherLock = new Object(); |
| | | |
| | | /** |
| | | * 推流回调接口 |
| | | */ |
| | |
| | | * 停止推流 |
| | | */ |
| | | public void stopPush() { |
| | | // stop 同样强制在主线程串行执行,避免与 init/setupListeners 并发 |
| | | if (Looper.myLooper() == Looper.getMainLooper()) { |
| | | stopPushInternal(); |
| | | } else { |
| | | mainHandler.post(this::stopPushInternal); |
| | | } |
| | | } |
| | | |
| | | private void stopPushInternal() { |
| | | synchronized (pusherLock) { |
| | | Timber.d("%s stopPush called", getCameraTag()); |
| | | stopPushThread(); |
| | | // stopAudioTransfer(); |
| | | stopWaterMaskSchedule(); |
| | | releaseAlivcPusher(); |
| | | releaseAlivcPusherLocked(); |
| | | if (usbCamera != null) { |
| | | usbCamera.stopCamera(); |
| | | } |
| | | pushStarted = false; |
| | | notifyCallback(1, 4, "推流已停止"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 初始化阿里推流 |
| | | */ |
| | | private void initAlivcPusher() { |
| | | synchronized (pusherLock) { |
| | | try { |
| | | alivcLivePushConfig = new AlivcLivePushConfig(); |
| | | |
| | |
| | | alivcLivePushConfig.setExternMainStream(true); |
| | | alivcLivePushConfig.setAlivcExternMainImageFormat(AlivcImageFormat.IMAGE_FORMAT_YUV420P); |
| | | |
| | | // 初始化推流器 |
| | | alivcPusher = new AlivcLivePusher(); |
| | | alivcPusher.init(context.getApplicationContext(), alivcLivePushConfig); |
| | | // 初始化推流器:先用局部变量,避免中途被 stop 置空导致 setupListeners NPE |
| | | AlivcLivePusher localPusher = new AlivcLivePusher(); |
| | | localPusher.init(context.getApplicationContext(), alivcLivePushConfig); |
| | | |
| | | // 外部自定义流模式下,同样需要先开启预览,让状态从 INIT 进入 PREVIEWED |
| | | // 创建一个隐藏的 Window 来承载 SurfaceView,确保 Surface 能够被创建 |
| | | windowManager = (WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE); |
| | |
| | | public void surfaceCreated(SurfaceHolder holder) { |
| | | try { |
| | | Timber.d("%s previewSurfaceView surfaceCreated, startPreviewAysnc", getCameraTag()); |
| | | if (alivcPusher != null) { |
| | | synchronized (pusherLock) { |
| | | if (alivcPusher != null && previewSurfaceView != null) { |
| | | alivcPusher.startPreviewAysnc(previewSurfaceView); |
| | | |
| | | |
| | | |
| | | // 启动摄像头数据推送线程 |
| | | startPushThread(); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | Timber.e(e, "%s startPreviewAysnc in surfaceCreated failed", getCameraTag()); |
| | |
| | | } |
| | | } |
| | | |
| | | // 设置监听器 |
| | | setupListeners(); |
| | | // 设置监听器(对局部 pusher 先绑定),最后再发布到字段 |
| | | setupListeners(localPusher); |
| | | alivcPusher = localPusher; |
| | | |
| | | Timber.d("%s AlivcPusher initialized successfully", getCameraTag()); |
| | | } catch (Exception e) { |
| | | Timber.e(e, "%s Failed to initialize AlivcPusher", getCameraTag()); |
| | | notifyCallback(1, -3, "初始化推流SDK失败: " + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | /** |
| | | * 设置监听器 |
| | | */ |
| | | private void setupListeners() { |
| | | private void setupListeners(AlivcLivePusher pusher) { |
| | | if (pusher == null) { |
| | | Timber.w("%s setupListeners skipped: pusher is null", getCameraTag()); |
| | | return; |
| | | } |
| | | // 推流信息监听器 |
| | | alivcPusher.setLivePushInfoListener(new AlivcLivePushInfoListener() { |
| | | pusher.setLivePushInfoListener(new AlivcLivePushInfoListener() { |
| | | @Override |
| | | public void onPreviewStarted(AlivcLivePusher alivcLivePusher) { |
| | | Timber.d("%s onPreviewStarted", getCameraTag()); |
| | |
| | | }); |
| | | |
| | | // 错误监听器 |
| | | alivcPusher.setLivePushErrorListener(new AlivcLivePushErrorListener() { |
| | | pusher.setLivePushErrorListener(new AlivcLivePushErrorListener() { |
| | | @Override |
| | | public void onSystemError(AlivcLivePusher alivcLivePusher, AlivcLivePushError alivcLivePushError) { |
| | | Timber.e("onSystemError: %s", alivcLivePushError.toString()); |
| | |
| | | }); |
| | | |
| | | // 网络监听器 |
| | | alivcPusher.setLivePushNetworkListener(new AlivcLivePushNetworkListener() { |
| | | pusher.setLivePushNetworkListener(new AlivcLivePushNetworkListener() { |
| | | @Override |
| | | public void onNetworkPoor(AlivcLivePusher alivcLivePusher) { |
| | | Timber.w("onNetworkPoor"); |
| | |
| | | * 释放阿里推流资源 |
| | | */ |
| | | private void releaseAlivcPusher() { |
| | | synchronized (pusherLock) { |
| | | releaseAlivcPusherLocked(); |
| | | } |
| | | } |
| | | |
| | | private void releaseAlivcPusherLocked() { |
| | | // 兜底:防止外部没有走 stopPush |
| | | stopWaterMaskSchedule(); |
| | | // 移除隐藏的 SurfaceView |