package com.safeluck.floatwindow; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteCallbackList; import android.os.RemoteException; import com.safeluck.floatwindow.manager.UsbCameraPushManager; import com.safeluck.floatwindow.manager.UsbCameraRecordManager; import timber.log.Timber; /** * 运行在独立进程(:p2)的 USB 摄像头视频服务,用于同时支持两路 USB 摄像头工作。 * 约定:当 MediaArgu.usbCameraId == 2 时,调用方应使用该服务进行推流/录像。 */ public class P2UsbCameraVideoService extends Service { private static final String TAG = "P2UsbCameraVideoService"; private Context context; private UsbCameraPushManager usbCameraPushManager; private UsbCameraRecordManager usbCameraRecordManager; private ManagerType currentManagerType = ManagerType.NONE; // 主线程 Handler,用于确保 AlivcLivePusher 初始化在主线程执行 private final Handler mainHandler = new Handler(Looper.getMainLooper()); private enum ManagerType { NONE, USB_PUSH, USB_RECORD } private final RemoteCallbackList mCallbacks = new RemoteCallbackList<>(); private final IMediaAidlInterface.Stub mBinder = new IMediaAidlInterface.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) { Timber.d("[%s] basicTypes called", TAG); } @Override public void startMedia(MediaArgu media) throws RemoteException { Timber.d("[%s] startMedia called via AIDL", TAG); P2UsbCameraVideoService.this.startMedia(media); } @Override public void stopMedia(MediaArgu media) throws RemoteException { Timber.d("[%s] stopMedia called via AIDL", TAG); P2UsbCameraVideoService.this.stopMedia(media); } @Override public void registerCallback(IMyCallback cb) throws RemoteException { if (cb != null) { mCallbacks.register(cb); Timber.d("[%s] Callback registered", TAG); } } @Override public void unregisterCallback(IMyCallback cb) throws RemoteException { if (cb != null) { mCallbacks.unregister(cb); Timber.d("[%s] Callback unregistered", TAG); } } }; @Override public void onCreate() { super.onCreate(); context = this; usbCameraPushManager = new UsbCameraPushManager(context); usbCameraPushManager.setCallback(this::notifyCallback); usbCameraRecordManager = new UsbCameraRecordManager(context); usbCameraRecordManager.setCallback(this::notifyCallback); Timber.d("[%s] onCreate", TAG); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; } @Override public IBinder onBind(Intent intent) { Timber.d("[%s] onBind", TAG); return mBinder; } @Override public void onDestroy() { super.onDestroy(); stopCurrentManager(); mCallbacks.kill(); Timber.d("[%s] onDestroy", TAG); } private void startMedia(MediaArgu media) { if (media == null) { notifyCallback(1, -1, "MediaArgu is null"); return; } // 该服务只处理 USB 摄像头 if (!media.isUsedOutCamera()) { notifyCallback(1, -4, "P2 service only supports USB camera"); return; } // 确保在主线程执行,因为 AlivcLivePusher 初始化需要 Handler(必须在有 Looper 的线程) if (Looper.myLooper() == Looper.getMainLooper()) { startMediaInternal(media); } else { mainHandler.post(() -> startMediaInternal(media)); } } private void startMediaInternal(MediaArgu media) { // 先停止当前 stopCurrentManager(); if (media.isPush()) { currentManagerType = ManagerType.USB_PUSH; usbCameraPushManager.startPush(media); } else { currentManagerType = ManagerType.USB_RECORD; usbCameraRecordManager.startRecord(media); } } private void stopMedia(MediaArgu media) { // 确保在主线程执行 if (Looper.myLooper() == Looper.getMainLooper()) { stopCurrentManager(); } else { mainHandler.post(this::stopCurrentManager); } } private void stopCurrentManager() { switch (currentManagerType) { case USB_PUSH: if (usbCameraPushManager != null) { usbCameraPushManager.stopPush(); } break; case USB_RECORD: if (usbCameraRecordManager != null) { usbCameraRecordManager.stopRecord(); } break; case NONE: break; } currentManagerType = ManagerType.NONE; } private void notifyCallback(ResponseVO response) { if (response == null) return; int count = mCallbacks.beginBroadcast(); for (int i = 0; i < count; i++) { try { mCallbacks.getBroadcastItem(i).onResult(response); } catch (RemoteException e) { Timber.e(e, "[%s] Error notifying callback", TAG); } } mCallbacks.finishBroadcast(); } private void notifyCallback(int type, int errCode, String message) { ResponseVO response = new ResponseVO(); response.setType(type); response.setErrCode(errCode); response.setMessage(message); notifyCallback(response); } }