Dana
7 天以前 8d84949e15636f0afe0012c2fa776d922fc2c5e6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
package com.safeluck.floatwindow;
 
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
 
import com.safeluck.floatwindow.manager.AndroidCameraRecordManager;
import com.safeluck.floatwindow.manager.UsbCameraPushManager;
import com.safeluck.floatwindow.manager.UsbCameraRecordManager;
 
import timber.log.Timber;
 
/**
 * 悬浮窗服务,用于处理推流和录像
 * 根据MediaArgu参数选择使用不同的管理器:
 * - USB摄像头推流:UsbCameraPushManager
 * - USB摄像头录像:UsbCameraRecordManager
 * - Android相机录像:AndroidCameraRecordManager
 */
public class FloatingService extends Service {
    private static final String TAG = "FloatingService";
    
    private Context context;
    
    // 管理器实例
    private UsbCameraPushManager usbCameraPushManager;
    private UsbCameraRecordManager usbCameraRecordManager;
    private AndroidCameraRecordManager androidCameraRecordManager;
    
    // 当前使用的管理器类型
    private ManagerType currentManagerType = ManagerType.NONE;
    
    /**
     * 管理器类型枚举
     */
    private enum ManagerType {
        NONE,
        USB_PUSH,
        USB_RECORD,
        ANDROID_RECORD
    }
    
    // AIDL Binder
    private final IMediaAidlInterface.Stub mBinder = new IMediaAidlInterface.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, 
                double aDouble, String aString) throws RemoteException {
            Timber.d("basicTypes called: anInt=%d, aLong=%d, aBoolean=%s, aFloat=%f, aDouble=%f, aString=%s", 
                    anInt, aLong, aBoolean, aFloat, aDouble, aString);
        }
        
        @Override
        public void startMedia(MediaArgu media) throws RemoteException {
            Timber.d("startMedia called via AIDL");
            FloatingService.this.startMedia(media);
        }
        
        @Override
        public void stopMedia() throws RemoteException {
            Timber.d("stopMedia called via AIDL");
            FloatingService.this.stopMedia();
        }
        
        @Override
        public void registerCallback(IMyCallback cb) throws RemoteException {
            if (cb != null) {
                mCallbacks.register(cb);
                Timber.d("Callback registered");
            }
        }
        
        @Override
        public void unregisterCallback(IMyCallback cb) throws RemoteException {
            if (cb != null) {
                mCallbacks.unregister(cb);
                Timber.d("Callback unregistered");
            }
        }
    };
    
    // 回调列表,使用 RemoteCallbackList 管理跨进程回调
    private final RemoteCallbackList<IMyCallback> mCallbacks = new RemoteCallbackList<>();
    
    @Override
    public void onCreate() {
        super.onCreate();
        context = this;
        
        // 初始化管理器
        usbCameraPushManager = new UsbCameraPushManager(context);
        usbCameraPushManager.setCallback(new UsbCameraPushManager.PushCallback() {
            @Override
            public void onResult(ResponseVO response) {
                notifyCallback(response);
            }
        });
        
        usbCameraRecordManager = new UsbCameraRecordManager(context);
        usbCameraRecordManager.setCallback(new UsbCameraRecordManager.RecordCallback() {
            @Override
            public void onResult(ResponseVO response) {
                notifyCallback(response);
            }
        });
        
        androidCameraRecordManager = new AndroidCameraRecordManager(context);
        androidCameraRecordManager.setCallback(new AndroidCameraRecordManager.RecordCallback() {
            @Override
            public void onResult(ResponseVO response) {
                notifyCallback(response);
            }
        });
        
        Timber.d("FloatingService onCreate");
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }
    
    /**
     * 启动媒体(通过 AIDL 调用)
     */
    private void startMedia(MediaArgu media) {
        if (media == null) {
            Timber.w("startMedia: media is null");
            notifyCallback(1, -1, "MediaArgu is null");
            return;
        }
        
        // 先停止当前正在运行的管理器
        stopCurrentManager();
        
        // 根据参数选择管理器
        if (media.isPush()) {
            // 推流
            if (media.isUsedOutCamera()) {
                // USB摄像头推流
                Timber.i("启动USB摄像头推流");
                currentManagerType = ManagerType.USB_PUSH;
                usbCameraPushManager.startPush(media);
            } else {
                Timber.w("推流仅支持USB摄像头");
                notifyCallback(1, -4, "推流仅支持USB摄像头");
            }
        } else {
            // 录像
            if (media.isUsedOutCamera()) {
                // USB摄像头录像
                Timber.i("启动USB摄像头录像");
                currentManagerType = ManagerType.USB_RECORD;
                usbCameraRecordManager.startRecord(media);
            } else {
                // Android相机录像
                Timber.i("启动Android相机录像");
                currentManagerType = ManagerType.ANDROID_RECORD;
                androidCameraRecordManager.startRecord(media);
            }
        }
    }
    
    /**
     * 停止当前管理器
     */
    private void stopCurrentManager() {
        switch (currentManagerType) {
            case USB_PUSH:
                if (usbCameraPushManager != null) {
                    usbCameraPushManager.stopPush();
                }
                break;
            case USB_RECORD:
                if (usbCameraRecordManager != null) {
                    usbCameraRecordManager.stopRecord();
                }
                break;
            case ANDROID_RECORD:
                if (androidCameraRecordManager != null) {
                    androidCameraRecordManager.stopRecord();
                }
                break;
            case NONE:
                break;
        }
        currentManagerType = ManagerType.NONE;
    }
    
    /**
     * 停止媒体
     */
    private void stopMedia() {
        Timber.d("stopMedia called");
        stopCurrentManager();
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        Timber.d("onBind called");
        return mBinder;
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        stopMedia();
        mCallbacks.kill();
        Timber.d("FloatingService onDestroy");
    }
    
    /**
     * 通知回调:统一使用 ResponseVO
     * @param response ResponseVO 对象,包含 type、errCode、message
     */
    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, "Error notifying callback");
            }
        }
        mCallbacks.finishBroadcast();
    }
    
    /**
     * 创建并发送回调
     * @param type 类型:0-录像 1-推流 2-文件名类型等
     * @param errCode 错误码:0-成功,其他为错误码
     * @param message 消息内容
     */
    private void notifyCallback(int type, int errCode, String message) {
        ResponseVO response = new ResponseVO();
        response.setType(type);
        response.setErrCode(errCode);
        response.setMessage(message);
        notifyCallback(response);
    }
}