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 com.safeluck.floatwindow.util.GlobalData;
|
|
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<IMyCallback> 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 sendInfo(String s, int processId) throws RemoteException {
|
GlobalData.getInstance().setWaterMaskInfo(s);
|
}
|
|
@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);
|
}
|
}
|