Browse Source

安卓AgoraView封装

邓博 7 years ago
parent
commit
960045d203

+ 132
- 0
android/src/main/java/com/syan/agora/AgoraManager.java View File

@@ -0,0 +1,132 @@
1
+package com.syan.agora;
2
+
3
+import android.content.Context;
4
+import android.util.Log;
5
+import android.util.SparseArray;
6
+import android.view.SurfaceView;
7
+
8
+import com.facebook.react.bridge.ReadableMap;
9
+
10
+import java.util.ArrayList;
11
+import java.util.List;
12
+
13
+import io.agora.rtc.IRtcEngineEventHandler;
14
+import io.agora.rtc.RtcEngine;
15
+import io.agora.rtc.video.VideoCanvas;
16
+
17
+/**
18
+ * Created by Leon on 2017/4/9.
19
+ */
20
+
21
+public class AgoraManager {
22
+
23
+    public static AgoraManager sAgoraManager;
24
+
25
+    private RtcEngine mRtcEngine;
26
+
27
+    private Context context;
28
+
29
+    private int mLocalUid = 0;
30
+
31
+    private AgoraManager() {
32
+        mSurfaceViews = new SparseArray<SurfaceView>();
33
+    }
34
+
35
+    private SparseArray<SurfaceView> mSurfaceViews;
36
+
37
+    public static AgoraManager getInstance() {
38
+        if (sAgoraManager == null) {
39
+            synchronized (AgoraManager.class) {
40
+                if (sAgoraManager == null) {
41
+                    sAgoraManager = new AgoraManager();
42
+                }
43
+            }
44
+        }
45
+        return sAgoraManager;
46
+    }
47
+
48
+    /**
49
+     * 初始化RtcEngine
50
+     */
51
+    public void init(Context context, IRtcEngineEventHandler mRtcEventHandler, ReadableMap options) {
52
+        this.context = context;
53
+
54
+        //创建RtcEngine对象,mRtcEventHandler为RtcEngine的回调
55
+        mRtcEngine = RtcEngine.create(context, options.getString("appid"), mRtcEventHandler);
56
+        //开启视频功能
57
+        mRtcEngine.enableVideo();
58
+        //视频配置,设置为360P
59
+        mRtcEngine.setVideoProfile(options.getInt("videoProfile"), true);
60
+        mRtcEngine.enableWebSdkInteroperability(true);  //设置和web通信
61
+//        mRtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_COMMUNICATION);//设置为通信模式(默认)
62
+        mRtcEngine.setChannelProfile(options.getInt("channelProfile")); //设置为直播模式
63
+//        mRtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_GAME); //设置为游戏模式
64
+        mRtcEngine.setClientRole(options.getInt("clientRole"), null); //设置为主播
65
+    }
66
+
67
+    /**
68
+     * 设置本地视频,即前置摄像头预览
69
+     */
70
+    public AgoraManager setupLocalVideo() {
71
+        //创建一个SurfaceView用作视频预览
72
+        SurfaceView surfaceView = RtcEngine.CreateRendererView(context);
73
+        //将SurfaceView保存起来在SparseArray中,后续会将其加入界面。key为视频的用户id,这里是本地视频, 默认id是0
74
+
75
+        mSurfaceViews.put(mLocalUid, surfaceView);
76
+
77
+        //设置本地视频,渲染模式选择VideoCanvas.RENDER_MODE_HIDDEN,如果选其他模式会出现视频不会填充满整个SurfaceView的情况,
78
+        //具体渲染模式参考官方文档https://docs.agora.io/cn/user_guide/API/android_api.html#set-local-video-view-setuplocalvideo
79
+        mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, mLocalUid));
80
+        return this;//返回AgoraManager以作链式调用
81
+    }
82
+
83
+    public AgoraManager setupRemoteVideo(int uid) {
84
+
85
+        Log.i("Agora", "mSurfaceViews1---" + mSurfaceViews.toString());
86
+
87
+        SurfaceView surfaceView = RtcEngine.CreateRendererView(context);
88
+        mSurfaceViews.put(uid, surfaceView);
89
+        mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
90
+        Log.i("Agora", "mSurfaceViews2---" + mSurfaceViews.toString());
91
+        return this;
92
+    }
93
+
94
+    public AgoraManager joinChannel(String channel) {
95
+        mRtcEngine.joinChannel(null, channel, null, 0);
96
+        return this;
97
+    }
98
+
99
+    public void startPreview() {
100
+        int a = mRtcEngine.startPreview();
101
+        Log.i("Agora", "开启预览---" + a);
102
+    }
103
+
104
+    public void stopPreview() {
105
+        mRtcEngine.stopPreview();
106
+    }
107
+
108
+    public void leaveChannel() {
109
+        mRtcEngine.leaveChannel();
110
+    }
111
+
112
+    public void removeSurfaceView(int uid) {
113
+        mSurfaceViews.remove(uid);
114
+    }
115
+
116
+    public List<SurfaceView> getSurfaceViews() {
117
+        List<SurfaceView> list = new ArrayList<SurfaceView>();
118
+        for (int i = 0; i < mSurfaceViews.size(); i++) {
119
+            SurfaceView surfaceView = mSurfaceViews.valueAt(i);
120
+            list.add(surfaceView);
121
+        }
122
+        return list;
123
+    }
124
+
125
+    public SurfaceView getLocalSurfaceView() {
126
+        return mSurfaceViews.get(mLocalUid);
127
+    }
128
+
129
+    public SurfaceView getSurfaceView(int uid) {
130
+        return mSurfaceViews.get(uid);
131
+    }
132
+}

+ 75
- 156
android/src/main/java/com/syan/agora/AgoraModule.java View File

@@ -1,33 +1,32 @@
1 1
 package com.syan.agora;
2 2
 
3
-import android.content.Context;
4
-import android.os.Handler;
3
+import android.support.annotation.Nullable;
5 4
 import android.util.Log;
6
-import android.view.SurfaceView;
7
-import android.view.View;
8 5
 
6
+import com.facebook.react.bridge.Arguments;
9 7
 import com.facebook.react.bridge.ReactApplicationContext;
8
+import com.facebook.react.bridge.ReactContext;
10 9
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
11 10
 import com.facebook.react.bridge.ReactMethod;
12 11
 import com.facebook.react.bridge.ReadableMap;
12
+import com.facebook.react.bridge.WritableMap;
13 13
 import com.facebook.react.modules.core.DeviceEventManagerModule;
14
-import com.facebook.react.uimanager.NativeViewHierarchyManager;
15
-import com.facebook.react.uimanager.UIBlock;
16
-import com.facebook.react.uimanager.UIManagerModule;
17
-import com.facebook.react.views.view.ReactViewGroup;
18 14
 
19
-import io.agora.rtc.Constants;
20 15
 import io.agora.rtc.IRtcEngineEventHandler;
21
-import io.agora.rtc.RtcEngine;
22
-import io.agora.rtc.video.VideoCanvas;
16
+
17
+import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread;
23 18
 
24 19
 public class AgoraModule extends ReactContextBaseJavaModule {
25 20
 
26
-    private RtcEngine mRtcEngine;
21
+    public AgoraModule(ReactApplicationContext context) {
27 22
 
28
-    private Context mContext;
23
+        super(context);
24
+    }
29 25
 
30
-    private static ReactApplicationContext mRAC;
26
+    @Override
27
+    public String getName() {
28
+        return "RCTAgora";
29
+    }
31 30
 
32 31
     private IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
33 32
 
@@ -36,48 +35,36 @@ public class AgoraModule extends ReactContextBaseJavaModule {
36 35
          */
37 36
         @Override
38 37
         public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
39
-//            runOnUiThread(new Runnable() {
40
-//                @Override
41
-//                public void run() {
42
-//                    mRAC
43
-//                            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
44
-//                            .emit("onFirstRemoteVideoDecoded", uid);
45
-//                }
46
-//            });
47
-
48
-            new Handler().post(new Runnable() {
38
+            runOnUiThread(new Runnable() {
49 39
                 @Override
50 40
                 public void run() {
51
-                    mRAC.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
52
-                            .emit("onFirstRemoteVideoDecoded", uid);
41
+                    WritableMap map = Arguments.createMap();
42
+                    map.putString("type", "onFirstRemoteVideoDecoded");
43
+                    map.putInt("uid", uid);
44
+                    commonEvent(map);
53 45
                 }
54 46
             });
55 47
 
56
-
57
-
58 48
         }
59 49
 
60 50
         /**
61 51
          * 加入频道成功的回调
62 52
          */
63 53
         @Override
64
-        public void onJoinChannelSuccess(String channel,final int uid, int elapsed) {
54
+        public void onJoinChannelSuccess(final String channel,final int uid, int elapsed) {
65 55
 
66 56
             Log.i("Agora", "加入房间成功---");
67
-            mRAC
68
-                    .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
69
-                    .emit("onJoinChannelSuccess",uid);
70
-
71
-//            new Handler().post(new Runnable() {
72
-//                @Override
73
-//                public void run() {
74
-//                    mRAC
75
-//                            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
76
-//                            .emit("onJoinChannelSuccess",uid);
77
-//                }
78
-//            });
79
-
80 57
 
58
+            runOnUiThread(new Runnable() {
59
+                @Override
60
+                public void run() {
61
+                    WritableMap map = Arguments.createMap();
62
+                    map.putString("type", "onJoinChannelSuccess");
63
+                    map.putString("channel", channel);
64
+                    map.putInt("uid", uid);
65
+                    commonEvent(map);
66
+                }
67
+            });
81 68
         }
82 69
 
83 70
         /**
@@ -88,12 +75,13 @@ public class AgoraModule extends ReactContextBaseJavaModule {
88 75
 
89 76
             Log.i("Agora", "有人来了----");
90 77
 
91
-            new Handler().post(new Runnable() {
78
+            runOnUiThread(new Runnable() {
92 79
                 @Override
93 80
                 public void run() {
94
-                    mRAC
95
-                            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
96
-                            .emit("onUserJoined", uid);
81
+                    WritableMap map = Arguments.createMap();
82
+                    map.putString("type", "onUserJoined");
83
+                    map.putInt("uid", uid);
84
+                    commonEvent(map);
97 85
                 }
98 86
             });
99 87
 
@@ -103,16 +91,34 @@ public class AgoraModule extends ReactContextBaseJavaModule {
103 91
          * 错误信息
104 92
          */
105 93
         @Override
106
-        public void onError(int err) {
94
+        public void onError(final int err) {
107 95
             Log.i("Agora", err + "错误---");
96
+            runOnUiThread(new Runnable() {
97
+                @Override
98
+                public void run() {
99
+                    WritableMap map = Arguments.createMap();
100
+                    map.putString("type", "onError");
101
+                    map.putInt("err", err);
102
+                    commonEvent(map);
103
+                }
104
+            });
108 105
         }
109 106
 
110 107
         /**
111 108
          * 警告
112 109
          */
113 110
         @Override
114
-        public void onWarning(int warn) {
111
+        public void onWarning(final int warn) {
115 112
             Log.i("Agora", warn + "警告---");
113
+            runOnUiThread(new Runnable() {
114
+                @Override
115
+                public void run() {
116
+                    WritableMap map = Arguments.createMap();
117
+                    map.putString("type", "onWarning");
118
+                    map.putInt("warn", warn);
119
+                    commonEvent(map);
120
+                }
121
+            });
116 122
         }
117 123
 
118 124
         /**
@@ -133,121 +139,34 @@ public class AgoraModule extends ReactContextBaseJavaModule {
133 139
     };
134 140
 
135 141
 
136
-    public AgoraModule(ReactApplicationContext context) {
137
-
138
-        super(context);
139
-    }
140
-
141
-    @Override
142
-    public String getName() {
143
-        return "RCTAgora";
144
-    }
145
-
146
-
147 142
     @ReactMethod
148
-    public void loadAgoraKit(ReadableMap options) {
149
-        Log.i("Agora", options.toString());
150
-
151
-        mContext = getCurrentActivity();
152
-        mRAC = getReactApplicationContext();
153
-
154
-        mRtcEngine = RtcEngine.create(mContext, options.getString("appid"), mRtcEventHandler);
155
-        mRtcEngine.enableVideo();
156
-//        mRtcEngine.setChannelProfile(options.getInt("channelProfile"));
157
-//        mRtcEngine.setVideoProfile(options.getInt("videoProfile"), true);
158
-
159
-        mRtcEngine.enableWebSdkInteroperability(true);
160
-        mRtcEngine.setVideoProfile(Constants.VIDEO_PROFILE_360P, false);
161
-        mRtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_LIVE_BROADCASTING);
162
-
163
-        mRtcEngine.joinChannel(null, options.getString("channelName"), options.getString("info"), 0);
164
-
165
-
166
-
143
+    public void init(ReadableMap options) {
144
+        AgoraManager.getInstance().init(getReactApplicationContext(), mRtcEventHandler, options);
145
+        AgoraManager.getInstance().setupLocalVideo().startPreview();
167 146
     }
168 147
 
148
+    //进入房间
169 149
     @ReactMethod
170
-    public void setupLocalVideo(final int uid, final int tag) {
171
-
172
-        final UIManagerModule uiManager = getReactApplicationContext().getNativeModule
173
-                (UIManagerModule.class);
174
-        uiManager.addUIBlock(new UIBlock() {
175
-            @Override
176
-            public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
177
-
178
-                ReactViewGroup dView = (ReactViewGroup)nativeViewHierarchyManager.resolveView(tag);
179
-
180
-                Log.i("Agora", dView.getWidth() + "dView");
181
-                Log.i("Agora", dView.getHeight() + "dView");
182
-
183
-                SurfaceView surfaceView = RtcEngine.CreateRendererView(getReactApplicationContext());
184
-
185
-                Log.i("Agora", surfaceView.getWidth() + "surfaceView");
186
-                Log.i("Agora", getReactApplicationContext().toString());
187
-                Log.i("Agora", surfaceView.toString());
188
-
189
-                dView.addView(surfaceView);
190
-
191
-                mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
192
-                mRtcEngine.startPreview();
193
-
194
-            }
195
-        });
150
+    public void joinChannel(String channelName) {
151
+        AgoraManager.getInstance().joinChannel(channelName);
196 152
     }
197 153
 
198
-
154
+    //退出
199 155
     @ReactMethod
200
-    public void setupRemoteVideo(final int uid, final int tag) {
201
-
202
-        final UIManagerModule uiManager = getReactApplicationContext().getNativeModule
203
-                (UIManagerModule.class);
204
-        uiManager.addUIBlock(new UIBlock() {
205
-            @Override
206
-            public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
207
-
208
-                View dView = nativeViewHierarchyManager.resolveView(tag);
209
-
210
-                SurfaceView surfaceView = RtcEngine.CreateRendererView(dView.getContext());
211
-
212
-//                ViewGroup gView = (ViewGroup) dView;
213
-//                gView.addView(surfaceView);
156
+    public void leaveChannel() {
157
+        AgoraManager.getInstance().leaveChannel();
158
+    }
214 159
 
215
-//                Log.i("Agora", surfaceView.getWidth() + "");
216
-//                Log.i("Agora", uid+"---"+tag);
217
-//
218
-                mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
160
+    private void commonEvent(WritableMap map) {
161
+        sendEvent(getReactApplicationContext(), "agoraEvent", map);
162
+    }
219 163
 
220
-            }
221
-        });
164
+    private void sendEvent(ReactContext reactContext,
165
+                           String eventName,
166
+                           @Nullable WritableMap params) {
167
+        reactContext
168
+                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
169
+                .emit(eventName, params);
222 170
     }
223
-}
224
-
225
-//                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
226
-//                surfaceView.setZOrderOnTop(false);
227
-//                surfaceView.setZOrderMediaOverlay(false);
228
-
229
-//                int w = dView.getWidth();
230
-//                int h = dView.getHeight();
231
-//                surfaceView.measure(w, h);
232
-//                int height =surfaceView.getMeasuredHeight();
233
-
234
-//                ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) surfaceView.getLayoutParams();
235
-//                params.width = 120;
236
-//                params.height = 120;
237
-//                surfaceView.setLayoutParams(params);
238
-
239
-//                Log.i("Agora", surfaceView.getWidth() + "surfaceView");
240
-//                Log.i("Agora", uid+"---"+tag);
241
-
242
-//                ViewGroup gView = (ViewGroup) dView;
243
-//                Log.i("Agora", gView.getWidth() + "gView");
244
-//                Log.i("Agora", gView.getHeight() + "gView");
245
-//
246
-//                gView.addView(surfaceView);
247
-//Button button = new Button(dView.getContext());
248
-//button.setText("123");
249
-//
250
-//        dView.addView(button);
251
-//                ArrayList<View> list = new ArrayList<>();
252
-//                list.add(surfaceView);
253
-//                dView.addChildrenForAccessibility(list);
171
+
172
+}

+ 4
- 2
android/src/main/java/com/syan/agora/AgoraPackage.java View File

@@ -15,7 +15,7 @@ public class AgoraPackage implements ReactPackage {
15 15
     @Override
16 16
     public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
17 17
         return Arrays.asList(new NativeModule[]{
18
-            new AgoraModule(reactContext),
18
+                new AgoraModule(reactContext),
19 19
         });
20 20
     }
21 21
 
@@ -25,6 +25,8 @@ public class AgoraPackage implements ReactPackage {
25 25
 
26 26
     @Override
27 27
     public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
28
-        return Collections.emptyList();
28
+        return Arrays.<ViewManager>asList(
29
+                new AgoraViewManage()
30
+        );
29 31
     }
30 32
 }

+ 23
- 0
android/src/main/java/com/syan/agora/AgoraVideoView.java View File

@@ -0,0 +1,23 @@
1
+package com.syan.agora;
2
+
3
+import android.content.Context;
4
+import android.widget.RelativeLayout;
5
+
6
+import com.facebook.react.uimanager.ThemedReactContext;
7
+
8
+/**
9
+ * Created by DB on 2017/6/27.
10
+ */
11
+
12
+public class AgoraVideoView extends RelativeLayout {
13
+
14
+    Context context;
15
+
16
+    public AgoraVideoView(ThemedReactContext context) {
17
+        super(context);
18
+
19
+        this.context = context;
20
+
21
+    }
22
+
23
+}

+ 57
- 0
android/src/main/java/com/syan/agora/AgoraViewManage.java View File

@@ -0,0 +1,57 @@
1
+package com.syan.agora;
2
+
3
+import android.view.SurfaceView;
4
+import android.view.View;
5
+
6
+import com.facebook.react.uimanager.SimpleViewManager;
7
+import com.facebook.react.uimanager.ThemedReactContext;
8
+import com.facebook.react.uimanager.annotations.ReactProp;
9
+
10
+/**
11
+ * Created by DB on 2017/6/23.
12
+ */
13
+
14
+public class AgoraViewManage extends SimpleViewManager<AgoraVideoView> {
15
+
16
+    ThemedReactContext context;
17
+
18
+    private AgoraVideoView agoraVideoView;
19
+
20
+    @Override
21
+    public String getName() {
22
+        return "AgoraView";
23
+    }
24
+
25
+    @Override
26
+    protected AgoraVideoView createViewInstance(ThemedReactContext reactContext) {
27
+        this.context = reactContext;
28
+
29
+        agoraVideoView = new AgoraVideoView(reactContext);
30
+
31
+        return agoraVideoView;
32
+    }
33
+
34
+    @ReactProp(name = "localUid")
35
+    public void setLocalUid(final AgoraVideoView agoraVideoView, int localUid) {
36
+
37
+        if (localUid == 0) {
38
+            SurfaceView surfaceView = AgoraManager.getInstance().getLocalSurfaceView();
39
+            surfaceView.setZOrderMediaOverlay(true);
40
+            surfaceView.setVisibility(View.VISIBLE);
41
+            agoraVideoView.addView(surfaceView);
42
+        }
43
+
44
+    }
45
+
46
+    @ReactProp(name = "remoteUid")
47
+    public void setRemoteUid(final AgoraVideoView agoraVideoView, int remoteUid) {
48
+
49
+        if (remoteUid != 0) {
50
+            AgoraManager.getInstance().setupRemoteVideo(remoteUid);
51
+            SurfaceView surfaceView = AgoraManager.getInstance().getSurfaceView(remoteUid);
52
+            surfaceView.setZOrderMediaOverlay(true);
53
+            surfaceView.setVisibility(View.VISIBLE);
54
+            agoraVideoView.addView(surfaceView);
55
+        }
56
+    }
57
+}

+ 32
- 2
index.js View File

@@ -1,8 +1,38 @@
1 1
 import {
2 2
     NativeModules,
3
-    findNodeHandle
3
+    findNodeHandle,
4
+    NativeAppEventEmitter
4 5
 } from 'react-native';
5 6
 
6 7
 const { Agora } = NativeModules
7 8
 
8
-export const loadAgoraKit = (options) => Agora.loadAgoraKit(options)
9
+export default {
10
+
11
+    init(options = {}) {
12
+        this.listener && this.listener.remove();
13
+        Agora.init(options);
14
+    },
15
+    joinChannel(channelName = '001'){
16
+        Agora.joinChannel(channelName)
17
+    },
18
+    eventEmitter(fnConf) {
19
+        // const {
20
+        //     onFirstRemoteVideoDecoded = () => {},
21
+        //     onJoinChannelSuccess = () => {},
22
+        //     onUserJoined = () => {},
23
+        //     onError = () => {},
24
+        //     onWarning = () => {}
25
+        // } = options;
26
+
27
+        // let fnConf = {...options};
28
+        //there are no `removeListener` for NativeAppEventEmitter & DeviceEventEmitter
29
+        this.listener && this.listener.remove();
30
+        this.listener = NativeAppEventEmitter.addListener('agoraEvent', event => {
31
+            fnConf[event['type']] && fnConf[event['type']](event);
32
+        });
33
+    },
34
+    removeEmitter() {
35
+        this.listener && this.listener.remove();
36
+    }
37
+
38
+};

+ 1
- 1
package.json View File

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "name": "react-native-agora",
3
-  "version": "1.0.2",
3
+  "version": "1.0.3",
4 4
   "description": "声网Agora",
5 5
   "main": "index.js",
6 6
   "scripts": {