Syan 6 år sedan
förälder
incheckning
6596992249

+ 3
- 1
AgoraView.js Visa fil

@@ -5,7 +5,8 @@
5 5
 import  React, {Component, PropTypes} from 'react'
6 6
 import {
7 7
     requireNativeComponent,
8
-    View
8
+    View,
9
+    Platform
9 10
 } from 'react-native'
10 11
 
11 12
 export default class AgoraView extends Component {
@@ -20,6 +21,7 @@ export default class AgoraView extends Component {
20 21
 AgoraView.propTypes = {
21 22
     showLocalVideo: PropTypes.bool,
22 23
     remoteUid: PropTypes.number,
24
+    zOrderMediaOverlay: PropTypes.bool,
23 25
     ...View.propTypes
24 26
 };
25 27
 

+ 44
- 234
README.md Visa fil

@@ -1,8 +1,13 @@
1
-[![QQ Group](https://img.shields.io/badge/QQ%20Group-471757030-red.svg)]()
1
+##### 有任何问题欢迎加入QQ群进行反馈  471757030
2 2
 
3 3
 # react-native-agora
4 4
 
5
-## Installation and linking libraries
5
+## 功能介绍
6
+
7
+- 支持 iOS Android  声网Agora视频通讯SDK
8
+- 支持 直播 多人视频会议 语音 功能
9
+
10
+## 安装使用
6 11
 
7 12
 Install with npm:
8 13
 
@@ -69,16 +74,20 @@ Add following to `AndroidManifest.xml`
69 74
 
70 75
 ## Documentation
71 76
 
72
-[声网API文档](https://docs.agora.io/cn/1.11.1/user_guide/API/ios_api_live_cn.html)
77
+[声网API文档](https://document.agora.io/cn/1.12/api/)
73 78
 
74 79
 ##### RtcEngine方法
75 80
 
76 81
 | Property                         | Type                                     | Description                           |
77 82
 | -------------------------------- | ---------------------------------------- | ------------------------------------- |
78
-| init                             | object {appid: 'agora注册的应用id', channelProfile: '频道模式', videoProfile: '视频模式', clientRole: '角色'} | 初始化Agora引擎                            |
83
+| init                             | object {appid: 'agora注册的应用id', channelProfile: '频道模式', videoProfile: '视频模式', clientRole: '角色', swapWidthAndHeight: 'bool值'} | 初始化Agora引擎                            |
79 84
 | joinChannel                      | string channelName (房间名称)   number uid (用户设置的uid 传0系统会自动分配) | 加入房间                                  |
80 85
 | leaveChannel                     |                                          | 离开频道                                  |
81 86
 | destroy                          |                                          | 销毁引擎实例                                |
87
+| configPublisher                     | object{} config参数请前往Agora文档查看                                        | 配置旁路直播推流方法                               |
88
+| setLocalRenderMode                     | number mode (1 2 3)                                        | 设置本地视频显示模式                                |
89
+| setRemoteRenderMode                     | number uid  number mode (1 2 3)                                          | 设置远端视频显示模式                                |
90
+| enableAudioVolumeIndication                     | number interval (时间间隔) number smooth(平滑系数。可以设置为 3)                                         | 启用说话者音量提示                                |
82 91
 | startPreview                     |                                          | 开启视频预览                                |
83 92
 | stopPreview                      |                                          | 关闭视频预览                                |
84 93
 | switchCamera                     |                                          | 切换前置/后置摄像头                            |
@@ -92,8 +101,8 @@ Add following to `AndroidManifest.xml`
92 101
 | enableLocalVideo                 | bool (default false)                     | 禁用本地视频功能                              |
93 102
 | muteAllRemoteVideoStreams        | bool (default false)                     | 暂停所有远端视频流                             |
94 103
 | muteRemoteVideoStream            | number uid(用户uid) bool  mute(是否暂停)       | 暂停指定远端视频流                             |
95
-| startRecordingService (ios only) | string  recordingKey                     | 启动服务端录制服务                             |
96
-| stopRecordingService (ios only)  | string  recordingKey                     | 停止服务端录制服务                             |
104
+| startRecordingService (iOS only) | string  recordingKey                     | 启动服务端录制服务                             |
105
+| stopRecordingService (iOS only)  | string  recordingKey                     | 停止服务端录制服务                             |
97 106
 | getSdkVersion                    | callback                                 | 获取版本号                                 |
98 107
 
99 108
 ##### 原生通知事件
@@ -106,7 +115,8 @@ RtcEngine.eventEmitter({
106 115
   onUserJoined: data => {},
107 116
   onError: data => {},
108 117
   onWarning: data => {},
109
-  onLeaveChannel: data => {}
118
+  onLeaveChannel: data => {},
119
+  onAudioVolumeIndication: data => {}
110 120
 })
111 121
 ```
112 122
 
@@ -119,6 +129,8 @@ RtcEngine.eventEmitter({
119 129
 | onError                   | 错误信息         |
120 130
 | onWarning                 | 警告           |
121 131
 | onLeaveChannel            | 退出频道         |
132
+| onAudioVolumeIndication            | 音量提示回调         |
133
+
122 134
 
123 135
 ##### AgoraView 组件
124 136
 
@@ -126,234 +138,32 @@ RtcEngine.eventEmitter({
126 138
 | -------------- | -------------------- |
127 139
 | showLocalVideo | 是否显示本地视频(bool)       |
128 140
 | remoteUid      | 显示远程视频(number 传入uid) |
141
+| zOrderMediaOverlay (Android only)      | 多视频界面覆盖 设置为true优先在上层(bool) |
129 142
 
130
-## Usage
143
+
144
+## 运行示例
131 145
 
132 146
 [Example](https://github.com/DBshaoYan/RNAgoraExample)
133 147
 
134
-```
135
-import React, {Component} from 'react';
136
-import {
137
-    StyleSheet,
138
-    View,
139
-    Text,
140
-    TouchableOpacity,
141
-    Image,
142
-    Dimensions
143
-} from 'react-native';
144
-
145
-const {width, height} = Dimensions.get('window');
146
-
147
-import {RtcEngine, AgoraView} from 'react-native-agora'
148
-
149
-export default class Meeting extends Component {
150
-
151
-    constructor(props) {
152
-        super(props);
153
-        this.state = {
154
-            remotes: [],
155
-            isJoinSuccess: false,
156
-            isSpeaker: false,
157
-            isMute: false
158
-        };
159
-    }
160
-
161
-    componentWillMount() {
162
-
163
-        //初始化Agora
164
-        const options = {
165
-            appid: '前往Agora官网进行申请--https://www.agora.io/cn/',
166
-            channelProfile: 1,
167
-            videoProfile: 40,
168
-            clientRole: 1,
169
-        };
170
-        RtcEngine.init(options);
171
-    }
172
-
173
-    componentDidMount() {
174
-
175
-        //加入房间
176
-        RtcEngine.joinChannel();
177
-
178
-        //所以的原生通知统一管理
179
-        RtcEngine.eventEmitter({
180
-            onFirstRemoteVideoDecoded: (data) => {
181
-                console.log(data);
182
-                //有远程视频加入 返回重要的  uid  AgoraView 根据uid 来设置remoteUid值
183
-                const {remotes} = this.state;
184
-
185
-                let arr = [...remotes];
186
-                let sign = false;
187
-                arr.forEach(v => {
188
-                    sign = v === data.uid
189
-                });
190
-
191
-                if (!sign) {
192
-                    arr.push(data.uid)
193
-                }
194
-
195
-                this.setState({
196
-                    remotes: arr
197
-                })
198
-            },
199
-            onUserOffline: (data) => {
200
-             	console.log(data);
201
-              	//有人离开了!
202
-                const {remotes} = this.state;
203
-
204
-                let arr = [...remotes];
205
-
206
-                let newArr = [];
207
-                newArr = arr.filter(v => {
208
-                    return v !== data.uid
209
-                });
210
-
211
-                this.setState({
212
-                    remotes: newArr
213
-                });
214
-            },
215
-            onJoinChannelSuccess: (data) => {
216
-                console.log(data);
217
- 			   //加入房间成功!
218
-                this.setState({
219
-                    isJoinSuccess: true
220
-                });
221
-            },
222
-            onUserJoined: (data) => {
223
-                console.log(data);
224
-                //有人来了!
225
-            },
226
-            onError: (data) => {
227
-                console.log(data);
228
-                //错误!
229
-                RtcEngine.leaveChannel();
230
-            }
231
-        })
232
-    }
233
-
234
-    componentWillUnmount() {
235
-        RtcEngine.removeEmitter()
236
-    }
237
-
238
-    handlerCancel = () => {
239
-        RtcEngine.leaveChannel();
240
-    };
241
-
242
-    handlerSwitchCamera = () => {
243
-        RtcEngine.switchCamera();
244
-    };
245
-
246
-    handlerMuteAllRemoteAudioStreams = () => {
247
-        this.setState({
248
-            isMute: !this.state.isMute
249
-        }, () => {
250
-            RtcEngine.muteAllRemoteAudioStreams(this.state.isMute)
251
-        })
252
-    };
253
-
254
-    handlerSetEnableSpeakerphone = () => {
255
-
256
-        this.setState({
257
-            isSpeaker: !this.state.isSpeaker
258
-        }, () => {
259
-            RtcEngine.setEnableSpeakerphone(this.state.isSpeaker)
260
-        });
261
-
262
-    };
263
-
264
-    render() {
265
-
266
-        const {isMute, isSpeaker, remotes, isJoinSuccess} = this.state;
267
-
268
-        if (!isJoinSuccess) {
269
-            return(
270
-                <View style={{flex:1, backgroundColor:'#fff', justifyContent:'center', alignItems:'center'}}>
271
-                    <Text>正在创建视频会议...</Text>
272
-                </View>
273
-            )
274
-        }
275
-
276
-        return (
277
-            <View style={styles.container}>
278
-                <AgoraView style={styles.localView} showLocalVideo={true} />
279
-                <View style={styles.absView}>
280
-                    <View style={styles.videoView}>
281
-                        {remotes.map((v, k) => {
282
-                            return (
283
-                                <AgoraView
284
-                                    style={styles.remoteView}
285
-                                    key={k}
286
-                                    remoteUid={v}
287
-                                />
288
-                            )
289
-                        })}
290
-                    </View>
291
-                    <View>
292
-                        <TouchableOpacity
293
-                            style={{alignSelf: 'center'}}
294
-                            onPress={this.handlerCancel}>
295
-                            <Image
296
-                                style={{width: 60, height: 60}}
297
-                                source={require('../images/btn_endcall.png')}/>
298
-                        </TouchableOpacity>
299
-                        <View style={styles.bottomView}>
300
-                            <TouchableOpacity onPress={this.handlerMuteAllRemoteAudioStreams} activeOpacity={.7}>
301
-                                <Image
302
-                                    style={{width: 50, height: 50}}
303
-                                    source={ isMute ? require('../images/icon_muted.png') : require('../images/btn_mute.png')}/>
304
-                            </TouchableOpacity>
305
-
306
-                            <TouchableOpacity onPress={this.handlerSwitchCamera} activeOpacity={.7}>
307
-                                <Image
308
-                                    style={{width: 50, height: 50}}
309
-                                    source={ require('../images/btn_switch_camera.png')}/>
310
-                            </TouchableOpacity>
311
-
312
-                            <TouchableOpacity onPress={this.handlerSetEnableSpeakerphone} activeOpacity={.7}>
313
-                                <Image
314
-                                    style={{width: 50, height: 50}}
315
-                                    source={isSpeaker ? require('../images/icon_speaker.png') : require('../images/btn_speaker.png')}/>
316
-                            </TouchableOpacity>
317
-                        </View>
318
-                    </View>
319
-
320
-                </View>
321
-            </View>
322
-        );
323
-    }
324
-}
325
-
326
-const styles = StyleSheet.create({
327
-    container: {
328
-        flex: 1,
329
-        backgroundColor: '#F4F4F4'
330
-    },
331
-    absView: {
332
-        position: 'absolute',
333
-        top: 20,
334
-        left: 0,
335
-        right: 0,
336
-        bottom: 0,
337
-        justifyContent: 'space-between'
338
-    },
339
-    videoView: {
340
-        padding: 5,
341
-        flexWrap: 'wrap',
342
-        flexDirection: 'row',
343
-        zIndex: 100
344
-    },
345
-    localView: {
346
-        flex: 1
347
-    },
348
-    remoteView: {
349
-        width: (width - 40) / 3,
350
-        height: (width - 40) / 3,
351
-        margin: 5
352
-    },
353
-    bottomView: {
354
-        padding: 20,
355
-        flexDirection: 'row',
356
-        justifyContent: 'space-around'
357
-    }
358
-});
359
-```
148
+
149
+## 更新信息
150
+
151
+#### 1.0.8
152
+
153
+ - 更新 Agora SDK 为 1.12
154
+
155
+ - init 不再默认开启视频预览 根据自己需求和时机调用startPreview
156
+
157
+ - init options 新增参数  是否交换宽和高 swapWidthAndHeight 默认false
158
+
159
+ - 新增方法 配置旁路直播推流方法 configPublisher
160
+
161
+ - 新增方法 设置本地视频显示模式 setLocalRenderMode
162
+
163
+ - 新增方法 设置远端视频显示模式 setRemoteRenderMode
164
+
165
+ - 新增方法 启用说话者音量提示 enableAudioVolumeIndication
166
+
167
+ - 新增音量提示回调 onAudioVolumeIndication
168
+
169
+ - Android AgoraView 新增zOrderMediaOverlay属性 解决多视频界面覆盖 设置为true优先在上层

Binär
android/libs/agora-rtc-sdk.jar Visa fil


+ 10
- 3
android/src/main/java/com/syan/agora/AgoraManager.java Visa fil

@@ -1,6 +1,7 @@
1 1
 package com.syan.agora;
2 2
 
3 3
 import android.content.Context;
4
+import android.util.Log;
4 5
 import android.util.SparseArray;
5 6
 import android.view.SurfaceView;
6 7
 
@@ -51,11 +52,15 @@ public class AgoraManager {
51 52
         this.context = context;
52 53
 
53 54
         //创建RtcEngine对象,mRtcEventHandler为RtcEngine的回调
54
-        mRtcEngine = RtcEngine.create(context, options.getString("appid"), mRtcEventHandler);
55
+        try {
56
+            mRtcEngine = RtcEngine.create(context, options.getString("appid"), mRtcEventHandler);
57
+
58
+        } catch (Exception e) {
59
+            throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e));
60
+        }
55 61
         //开启视频功能
56 62
         mRtcEngine.enableVideo();
57
-        //视频配置,设置为360P
58
-        mRtcEngine.setVideoProfile(options.getInt("videoProfile"), true);
63
+        mRtcEngine.setVideoProfile(options.getInt("videoProfile"), options.getBoolean("swapWidthAndHeight")); //视频配置,
59 64
         mRtcEngine.enableWebSdkInteroperability(true);  //设置和web通信
60 65
         mRtcEngine.setChannelProfile(options.getInt("channelProfile")); //设置模式
61 66
         mRtcEngine.setClientRole(options.getInt("clientRole"), null); //设置角色
@@ -122,4 +127,6 @@ public class AgoraManager {
122 127
     public SurfaceView getSurfaceView(int uid) {
123 128
         return mSurfaceViews.get(uid);
124 129
     }
130
+
131
+
125 132
 }

+ 66
- 2
android/src/main/java/com/syan/agora/AgoraModule.java Visa fil

@@ -10,10 +10,12 @@ import com.facebook.react.bridge.ReactContext;
10 10
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
11 11
 import com.facebook.react.bridge.ReactMethod;
12 12
 import com.facebook.react.bridge.ReadableMap;
13
+import com.facebook.react.bridge.WritableArray;
13 14
 import com.facebook.react.bridge.WritableMap;
14 15
 import com.facebook.react.modules.core.DeviceEventManagerModule;
15 16
 
16 17
 import io.agora.rtc.IRtcEngineEventHandler;
18
+import io.agora.rtc.PublisherConfiguration;
17 19
 import io.agora.rtc.RtcEngine;
18 20
 
19 21
 import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread;
@@ -89,6 +91,33 @@ public class AgoraModule extends ReactContextBaseJavaModule {
89 91
 
90 92
         }
91 93
 
94
+        /**
95
+         * 说话声音音量提示回调
96
+         */
97
+        @Override
98
+        public void onAudioVolumeIndication(final AudioVolumeInfo[] speakers,
99
+                                             final int totalVolume ) {
100
+
101
+            runOnUiThread(new Runnable() {
102
+                @Override
103
+                public void run() {
104
+
105
+                    WritableArray arr = Arguments.createArray();
106
+                    for (int i = 0; i < speakers.length; i++) {
107
+                        WritableMap obj = Arguments.createMap();
108
+                        obj.putInt("uid", speakers[i].uid);
109
+                        obj.putInt("volume", speakers[i].volume);
110
+                    }
111
+
112
+                    WritableMap map = Arguments.createMap();
113
+                    map.putString("type", "onAudioVolumeIndication");
114
+                    map.putArray("speakers", arr);
115
+                    map.putInt("totalVolume", totalVolume);
116
+                    commonEvent(map);
117
+                }
118
+            });
119
+        }
120
+
92 121
         /**
93 122
          * 错误信息
94 123
          */
@@ -158,7 +187,6 @@ public class AgoraModule extends ReactContextBaseJavaModule {
158 187
     @ReactMethod
159 188
     public void init(ReadableMap options) {
160 189
         AgoraManager.getInstance().init(getReactApplicationContext(), mRtcEventHandler, options);
161
-        AgoraManager.getInstance().setupLocalVideo().startPreview();
162 190
     }
163 191
 
164 192
     //进入房间
@@ -186,6 +214,42 @@ public class AgoraModule extends ReactContextBaseJavaModule {
186 214
         AgoraManager.getInstance().stopPreview();
187 215
     }
188 216
 
217
+    //配置旁路直播推流
218
+    @ReactMethod
219
+    public void configPublisher(ReadableMap options) {
220
+        PublisherConfiguration config = new PublisherConfiguration.Builder()
221
+                .owner(options.getBoolean("owner"))
222
+                .size(options.getInt("width"), options.getInt("height"))
223
+                .frameRate(options.getInt("framerate"))
224
+                .biteRate(options.getInt("bitrate"))
225
+                .defaultLayout(options.getInt("defaultLayout"))
226
+                .streamLifeCycle(options.getInt("lifeCycle"))
227
+                .rawStreamUrl(options.getString("rawStreamUrl"))
228
+                .publishUrl(options.getString("publishUrl"))
229
+                .extraInfo(options.getString("extraInfo"))
230
+                .build();
231
+
232
+        AgoraManager.getInstance().mRtcEngine.configPublisher(config);
233
+    }
234
+
235
+    //设置本地视频显示模式
236
+    @ReactMethod
237
+    public void setLocalRenderMode(int mode) {
238
+        AgoraManager.getInstance().mRtcEngine.setLocalRenderMode(mode);
239
+    }
240
+
241
+    //设置远端视频显示模式
242
+    @ReactMethod
243
+    public void setRemoteRenderMode(int uid, int mode) {
244
+        AgoraManager.getInstance().mRtcEngine.setRemoteRenderMode(uid, mode);
245
+    }
246
+
247
+    //启用说话者音量提示
248
+    @ReactMethod
249
+    public void enableAudioVolumeIndication(int interval, int smooth) {
250
+        AgoraManager.getInstance().mRtcEngine.enableAudioVolumeIndication(interval, smooth);
251
+    }
252
+
189 253
     //打开音频
190 254
     @ReactMethod
191 255
     public void enableAudio() {
@@ -273,7 +337,7 @@ public class AgoraModule extends ReactContextBaseJavaModule {
273 337
     //查询 SDK 版本号
274 338
     @ReactMethod
275 339
     public void getSdkVersion(Callback callback) {
276
-        callback.invoke( RtcEngine.getSdkVersion());
340
+        callback.invoke(RtcEngine.getSdkVersion());
277 341
     }
278 342
 
279 343
     private void commonEvent(WritableMap map) {

+ 16
- 9
android/src/main/java/com/syan/agora/AgoraViewManage.java Visa fil

@@ -1,7 +1,6 @@
1 1
 package com.syan.agora;
2 2
 
3 3
 import android.view.SurfaceView;
4
-import android.view.View;
5 4
 
6 5
 import com.facebook.react.uimanager.SimpleViewManager;
7 6
 import com.facebook.react.uimanager.ThemedReactContext;
@@ -15,6 +14,8 @@ public class AgoraViewManage extends SimpleViewManager<AgoraVideoView> {
15 14
 
16 15
     public static final String REACT_CLASS = "RCTAgoraView";
17 16
 
17
+    public SurfaceView surfaceView;
18
+
18 19
     @Override
19 20
     public String getName() {
20 21
         return REACT_CLASS;
@@ -28,19 +29,25 @@ public class AgoraViewManage extends SimpleViewManager<AgoraVideoView> {
28 29
     @ReactProp(name = "showLocalVideo")
29 30
     public void setShowLocalVideo(final AgoraVideoView agoraVideoView, boolean showLocalVideo) {
30 31
 
31
-        if (showLocalVideo) {
32
-            SurfaceView surfaceView = AgoraManager.getInstance().getLocalSurfaceView();
33
-            surfaceView.setVisibility(View.VISIBLE);
34
-            agoraVideoView.addView(surfaceView);
35
-        }
32
+        AgoraManager.getInstance().setupLocalVideo();
33
+        surfaceView = AgoraManager.getInstance().getLocalSurfaceView();
34
+        //surfaceView.setVisibility(View.VISIBLE);
35
+        agoraVideoView.addView(surfaceView);
36
+//        surfaceView.setZOrderMediaOverlay(true);
37
+
38
+    }
39
+
40
+    @ReactProp(name = "zOrderMediaOverlay")
41
+    public void setZOrderMediaOverlay(final AgoraVideoView agoraVideoView, boolean zOrderMediaOverlay) {
42
+        surfaceView.setZOrderMediaOverlay(zOrderMediaOverlay);
36 43
     }
37 44
 
38 45
     @ReactProp(name = "remoteUid")
39 46
     public void setRemoteUid(final AgoraVideoView agoraVideoView, int remoteUid) {
40 47
         AgoraManager.getInstance().setupRemoteVideo(remoteUid);
41
-        SurfaceView surfaceView = AgoraManager.getInstance().getSurfaceView(remoteUid);
42
-        surfaceView.setVisibility(View.VISIBLE);
48
+        surfaceView = AgoraManager.getInstance().getSurfaceView(remoteUid);
49
+        //surfaceView.setVisibility(View.VISIBLE);
43 50
         agoraVideoView.addView(surfaceView);
44
-        surfaceView.setZOrderMediaOverlay(true);
51
+//        surfaceView.setZOrderMediaOverlay(true);
45 52
     }
46 53
 }

Binär
android/src/main/jniLibs/arm64-v8a/libagora-rtc-sdk-jni.so Visa fil


Binär
android/src/main/jniLibs/armeabi-v7a/libagora-rtc-sdk-jni.so Visa fil


+ 113
- 47
android/src/main/jniLibs/include/IAgoraRtcEngine.h Visa fil

@@ -72,10 +72,13 @@ public:
72 72
         ptr_ = ptr;
73 73
     }
74 74
     template<class C1, class C2>
75
-    void queryInterface(C1& c, C2 iid) {
76
-		pointer_type p;
77
-        if (!c.queryInterface(iid, (void**)&p))
78
-			reset(p);
75
+    bool queryInterface(C1* c, C2 iid) {
76
+        pointer_type p = NULL;
77
+        if (c && !c->queryInterface(iid, (void**)&p))
78
+        {
79
+            reset(p);
80
+        }
81
+        return p != NULL;;
79 82
 	}
80 83
 private:
81 84
     AutoPtr(const AutoPtr&);
@@ -129,7 +132,6 @@ enum WARN_CODE_TYPE
129 132
     // sdk: 100~1000
130 133
     WARN_SWITCH_LIVE_VIDEO_TIMEOUT = 111,
131 134
 	WARN_SET_CLIENT_ROLE_TIMEOUT = 118,
132
-    WARN_SET_CLIENT_ROLE_NOT_AUTHORIZED = 119,
133 135
 };
134 136
 
135 137
 enum ERROR_CODE_TYPE
@@ -168,6 +170,7 @@ enum ERROR_CODE_TYPE
168 170
 	ERR_BITRATE_LIMIT = 115,
169 171
 	ERR_TOO_MANY_DATA_STREAMS = 116,
170 172
 	ERR_STREAM_MESSAGE_TIMEOUT = 117,
173
+    ERR_SET_CLIENT_ROLE_NOT_AUTHORIZED = 119,
171 174
 
172 175
     //1001~2000
173 176
     ERR_LOAD_MEDIA_ENGINE = 1001,
@@ -230,7 +233,6 @@ enum MEDIA_ENGINE_EVENT_CODE_TYPE
230 233
     MEDIA_ENGINE_RECORDING_WARNING = 2,
231 234
     MEDIA_ENGINE_PLAYOUT_WARNING = 3,
232 235
     MEDIA_ENGINE_AUDIO_FILE_MIX_FINISH = 10,
233
-    MEDIA_ENGINE_AUDIO_SAMPLE_RATE_RECONFIG_FINISH = 11,
234 236
     // media engine role changed
235 237
     MEDIA_ENGINE_ROLE_BROADCASTER_SOLO = 20,
236 238
     MEDIA_ENGINE_ROLE_BROADCASTER_INTERACTIVE = 21,
@@ -258,6 +260,13 @@ enum MEDIA_DEVICE_TYPE
258 260
     VIDEO_CAPTURE_DEVICE = 3,
259 261
 };
260 262
 
263
+enum AUDIO_RECORDING_QUALITY_TYPE
264
+{
265
+    AUDIO_RECORDING_QUALITY_LOW = 0,
266
+    AUDIO_RECORDING_QUALITY_MEDIUM = 1,
267
+    AUDIO_RECORDING_QUALITY_HIGH = 2,
268
+};
269
+
261 270
 enum QUALITY_TYPE
262 271
 {
263 272
     QUALITY_UNKNOWN = 0,
@@ -276,6 +285,13 @@ enum RENDER_MODE_TYPE
276 285
     RENDER_MODE_ADAPTIVE = 3,
277 286
 };
278 287
 
288
+enum VIDEO_MIRROR_MODE_TYPE
289
+{
290
+    VIDEO_MIRROR_MODE_AUTO = 0,//determined by SDK
291
+    VIDEO_MIRROR_MODE_ENABLED = 1,//enabled mirror
292
+    VIDEO_MIRROR_MODE_DISABLED = 2,//disable mirror
293
+};
294
+
279 295
 enum VIDEO_PROFILE_TYPE
280 296
 {                                   // res       fps  kbps
281 297
     VIDEO_PROFILE_120P = 0,         // 160x120   15   65
@@ -435,6 +451,16 @@ struct VideoCompositingLayout
435 451
     {}
436 452
 };
437 453
 
454
+typedef struct Rect {
455
+    int top;
456
+    int left;
457
+    int bottom;
458
+    int right;
459
+
460
+    Rect(): top(0), left(0), bottom(0), right(0) {}
461
+    Rect(int t, int l, int b, int r): top(t), left(l), bottom(b), right(r) {}
462
+} Rect;
463
+
438 464
 #if defined(_WIN32)
439 465
 
440 466
 enum RTMP_STREAM_LIFE_CYCLE_TYPE
@@ -451,10 +477,14 @@ struct PublisherConfiguration {
451 477
 	int defaultLayout;
452 478
 	int lifecycle;
453 479
 	bool owner;
480
+	int injectStreamWidth;
481
+	int injectStreamHeight;
482
+	const char* injectStreamUrl;
454 483
 	const char* publishUrl;
455 484
 	const char* rawStreamUrl;
456 485
 	const char* extraInfo;
457 486
 
487
+
458 488
 	PublisherConfiguration()
459 489
 		: width(640)
460 490
 		, height(360)
@@ -463,6 +493,9 @@ struct PublisherConfiguration {
463 493
 		, defaultLayout(1)
464 494
 		, lifecycle(RTMP_STREAM_LIFE_CYCLE_BIND2CHANNEL)
465 495
 		, owner(true)
496
+		, injectStreamWidth(0)
497
+		, injectStreamHeight(0)
498
+		, injectStreamUrl(NULL)
466 499
 		, publishUrl(NULL)
467 500
 		, rawStreamUrl(NULL)
468 501
 		, extraInfo(NULL)
@@ -673,6 +706,12 @@ public:
673 706
     virtual void onAudioMixingFinished() {
674 707
     }
675 708
 
709
+    /**
710
+    * When audio effect playback finished, this function will be called
711
+    */
712
+    virtual void onAudioEffectFinished(int soundId) {
713
+    }
714
+
676 715
     /**
677 716
     * when the video device state changed(plugged or removed), the function will be called
678 717
     * @param [in] deviceId
@@ -957,7 +996,12 @@ public:
957 996
         (void)uid;
958 997
         (void)elapsed;
959 998
     }
960
-
999
+    /** @param [in] uid
1000
+    *        the speaker uid who is talking in the channel
1001
+    */
1002
+    virtual void onActiveSpeaker(uid_t uid) {
1003
+        (void)uid;
1004
+    }
961 1005
 };
962 1006
 
963 1007
 /**
@@ -1566,7 +1610,7 @@ public:
1566 1610
 class AAudioDeviceManager : public agora::util::AutoPtr<IAudioDeviceManager>
1567 1611
 {
1568 1612
 public:
1569
-    AAudioDeviceManager(IRtcEngine& engine)
1613
+    AAudioDeviceManager(IRtcEngine* engine)
1570 1614
     {
1571 1615
 		queryInterface(engine, AGORA_IID_AUDIO_DEVICE_MANAGER);
1572 1616
     }
@@ -1575,7 +1619,7 @@ public:
1575 1619
 class AVideoDeviceManager : public agora::util::AutoPtr<IVideoDeviceManager>
1576 1620
 {
1577 1621
 public:
1578
-    AVideoDeviceManager(IRtcEngine& engine)
1622
+    AVideoDeviceManager(IRtcEngine* engine)
1579 1623
     {
1580 1624
 		queryInterface(engine, AGORA_IID_VIDEO_DEVICE_MANAGER);
1581 1625
     }
@@ -1584,21 +1628,25 @@ public:
1584 1628
 class AParameter : public agora::util::AutoPtr<IRtcEngineParameter>
1585 1629
 {
1586 1630
 public:
1587
-    AParameter(IRtcEngine& engine)
1631
+    AParameter(IRtcEngine& engine) { initialize(&engine); }
1632
+    AParameter(IRtcEngine* engine) { initialize(engine); }
1633
+    AParameter(IRtcEngineParameter* p) :agora::util::AutoPtr<IRtcEngineParameter>(p) {}
1634
+private:
1635
+    bool initialize(IRtcEngine* engine)
1588 1636
     {
1589
-        IRtcEngineParameter* p;
1590
-        if (!engine.queryInterface(AGORA_IID_RTC_ENGINE_PARAMETER, (void**)&p))
1637
+        IRtcEngineParameter* p = NULL;
1638
+        if (engine && !engine->queryInterface(AGORA_IID_RTC_ENGINE_PARAMETER, (void**)&p))
1591 1639
             reset(p);
1640
+        return p != NULL;
1592 1641
     }
1593
-    AParameter(IRtcEngineParameter* p)
1594
-        :agora::util::AutoPtr<IRtcEngineParameter>(p)
1595
-    {}
1596 1642
 };
1597 1643
 
1598 1644
 class RtcEngineParameters
1599 1645
 {
1600 1646
 public:
1601 1647
     RtcEngineParameters(IRtcEngine& engine)
1648
+        :m_parameter(&engine){}
1649
+    RtcEngineParameters(IRtcEngine* engine)
1602 1650
         :m_parameter(engine){}
1603 1651
 
1604 1652
     /**
@@ -1710,16 +1758,16 @@ public:
1710 1758
     *        the .wav file path you want to saved
1711 1759
     * @return return 0 if success or an error code
1712 1760
     */
1713
-    int startAudioRecording(const char* filePath) {
1761
+    int startAudioRecording(const char* filePath, AUDIO_RECORDING_QUALITY_TYPE quality) {
1714 1762
         if (!m_parameter) return -ERR_NOT_INITIALIZED;
1715 1763
 #if defined(_WIN32)
1716
-		util::AString path;
1717
-		if (!m_parameter->convertPath(filePath, path))
1718
-			filePath = path->c_str();
1719
-		else
1720
-			return -ERR_INVALID_ARGUMENT;
1764
+        util::AString path;
1765
+        if (!m_parameter->convertPath(filePath, path))
1766
+            filePath = path->c_str();
1767
+        else
1768
+            return -ERR_INVALID_ARGUMENT;
1721 1769
 #endif
1722
-		return m_parameter->setString("che.audio.start_recording", filePath);
1770
+        return setObject("che.audio.start_recording", "{\"filePath\":\"%s\",\"quality\":%d}", filePath, quality);
1723 1771
     }
1724 1772
 
1725 1773
     /**
@@ -1799,21 +1847,21 @@ public:
1799 1847
         return m_parameter ? m_parameter->setInt("che.audio.mixing.file.position", pos) : -ERR_NOT_INITIALIZED;
1800 1848
     }
1801 1849
 #if defined(__APPLE__)
1802
-	/**
1803
-	* start screen capture
1804
-	* @return return 0 if success or an error code
1805
-	*/
1806
-	int startScreenCapture(unsigned int windowId) {
1807
-        return m_parameter ? m_parameter->setUInt("che.video.start_screen_capture", windowId) : -ERR_NOT_INITIALIZED;
1808
-	}
1809
-
1810 1850
     /**
1811
-     * specify window id to capture
1812
-     * @return return 0 if success or an error code
1851
+     * start screen/windows capture
1852
+     *
1853
+     *  @param windowId screen capture, if windowId is 0; windows capture if windowsId isn't 0;
1854
+     *  @param rect     valid when windowId is 0; whole screen if rect is NULL.
1855
+     *
1856
+     *  @return return 0 if success or an error code
1813 1857
      */
1814
-    int setScreenCaptureWindow(unsigned int windowId) {
1815
-        return m_parameter ? m_parameter->setUInt("che.video.set_screen_capture_window", windowId) : -ERR_NOT_INITIALIZED;
1858
+    int startScreenCapture(unsigned int windowId, int captureFreq, const Rect *rect) {
1859
+        if (!rect)
1860
+            return setObject("che.video.start_screen_capture", "{\"id\":%u,\"captureFreq\":%d}", windowId, captureFreq);
1861
+        else
1862
+            return setObject("che.video.start_screen_capture", "{\"id\":%u,\"captureFreq\":%d,\"top\":%d,\"left\":%d,\"bottom\":%d,\"right\":%d}", windowId, captureFreq, rect->top, rect->left, rect->bottom, rect->right);
1816 1863
     }
1864
+
1817 1865
     /**
1818 1866
      * stop screen capture
1819 1867
      * @return return 0 if success or an error code
@@ -1823,20 +1871,20 @@ public:
1823 1871
     }
1824 1872
 #elif defined(_WIN32)
1825 1873
     /**
1826
-     * start screen capture
1827
-     * @return return 0 if success or an error code
1828
-     */
1829
-    int startScreenCapture(HWND windowId) {
1830
-        return m_parameter ? m_parameter->setUInt("che.video.start_screen_capture", (unsigned int)windowId) : -ERR_NOT_INITIALIZED;
1831
-    }
1832
-    
1833
-    /**
1834
-     * specify window id to capture
1835
-     * @return return 0 if success or an error code
1874
+     * start screen/windows capture
1875
+     *
1876
+     *  @param windowId screen capture, if windowId is 0; windows capture if windowsId isn't 0;
1877
+     *  @param rect     valid when windowId is 0; whole screen if rect is NULL.
1878
+     *
1879
+     *  @return return 0 if success or an error code
1836 1880
      */
1837
-    int setScreenCaptureWindow(HWND windowId) {
1838
-        return m_parameter ? m_parameter->setUInt("che.video.set_screen_capture_window", (unsigned int)windowId) : -ERR_NOT_INITIALIZED;
1881
+    int startScreenCapture(HWND windowId, int captureFreq, const Rect *rect) {
1882
+        if (!rect)
1883
+            return setObject("che.video.start_screen_capture", "{\"id\":%u,\"captureFreq\":%d}", (unsigned int)windowId, captureFreq);
1884
+        else
1885
+            return setObject("che.video.start_screen_capture", "{\"id\":%u,\"captureFreq\":%d,\"top\":%d,\"left\":%d,\"bottom\":%d,\"right\":%d}", (unsigned int)windowId, captureFreq, rect->top, rect->left, rect->bottom, rect->right);
1839 1886
     }
1887
+
1840 1888
     /**
1841 1889
      * stop screen capture
1842 1890
      * @return return 0 if success or an error code
@@ -1894,6 +1942,24 @@ public:
1894 1942
         return setObject("che.video.render_mode", "{\"uid\":%u,\"mode\":%d}", uid, renderMode);
1895 1943
     }
1896 1944
     
1945
+    int setLocalVideoMirrorMode(VIDEO_MIRROR_MODE_TYPE mirrorMode) {
1946
+        if (!m_parameter) return -ERR_NOT_INITIALIZED;
1947
+        const char *value;
1948
+        switch (mirrorMode) {
1949
+        case VIDEO_MIRROR_MODE_AUTO:
1950
+            value = "default";
1951
+            break;
1952
+        case VIDEO_MIRROR_MODE_ENABLED:
1953
+            value = "forceMirror";
1954
+            break;
1955
+        case VIDEO_MIRROR_MODE_DISABLED:
1956
+            value = "disableMirror";
1957
+            break;
1958
+        default:
1959
+            return -ERR_INVALID_ARGUMENT;
1960
+        }
1961
+        return m_parameter->setString("che.video.localViewMirrorSetting", value);
1962
+    }
1897 1963
 	int startRecordingService(const char* recordingKey) {
1898 1964
         return m_parameter ? m_parameter->setString("rtc.api.start_recording_service", recordingKey) : -ERR_NOT_INITIALIZED;
1899 1965
     }
@@ -1942,7 +2008,7 @@ public:
1942 2008
     }
1943 2009
     //only for live broadcasting
1944 2010
     int setVideoQualityParameters(bool preferFrameRateOverImageQuality) {
1945
-        return m_parameter ? m_parameter->setBool("rtc.video.prefer_frame_rate", preferFrameRateOverImageQuality) : -ERR_NOT_INITIALIZED;
2011
+        return setParameters("{\"rtc.video.prefer_frame_rate\":%s,\"che.video.prefer_frame_rate\":%s}", preferFrameRateOverImageQuality ? "true" : "false", preferFrameRateOverImageQuality ? "true" : "false");
1946 2012
     }
1947 2013
 protected:
1948 2014
     AParameter& parameter() {

Binär
android/src/main/jniLibs/x86/libagora-rtc-sdk-jni.so Visa fil


+ 59
- 4
ios/RCTAgora/RCTAgora.m Visa fil

@@ -59,12 +59,9 @@ RCT_EXPORT_METHOD(init:(NSDictionary *)options) {
59 59
     //启用双流模式
60 60
     [self.rtcEngine enableDualStreamMode:YES];
61 61
     [self.rtcEngine enableVideo];
62
-    [self.rtcEngine setVideoProfile:[options[@"videoProfile"] integerValue]swapWidthAndHeight:YES];
62
+    [self.rtcEngine setVideoProfile:[options[@"videoProfile"] integerValue]swapWidthAndHeight:[options[@"swapWidthAndHeight"]boolValue]];
63 63
     [self.rtcEngine setClientRole:[options[@"clientRole"] integerValue] withKey:nil];
64 64
     
65
-    //开启预览
66
-    [self.rtcEngine startPreview];
67
-    
68 65
     //Agora Native SDK 与 Agora Web SDK 间的互通
69 66
     [self.rtcEngine enableWebSdkInteroperability:YES];
70 67
     
@@ -113,9 +110,48 @@ RCT_EXPORT_METHOD(setupRemoteVideo:(NSDictionary *)options){
113 110
 //开启视频预览
114 111
 RCT_EXPORT_METHOD(startPreview){
115 112
     [self.rtcEngine startPreview];
113
+}
114
+
115
+//配置旁路直播推流(configPublisher)
116
+//请确保用户已经调用 setClientRole() 且已将用户角色设为主播
117
+//主播必须在加入频道前调用本章 API
118
+RCT_EXPORT_METHOD(configPublisher:(NSDictionary *)config){
119
+    AgoraPublisherConfiguration *apc = [AgoraPublisherConfiguration new];
116 120
     
121
+    apc.width = [config[@"width"] integerValue];  //旁路直播的输出码流的宽度
122
+    apc.height = [config[@"height"] integerValue]; //旁路直播的输出码流的高度
123
+    apc.framerate = [config[@"framerate"] integerValue]; //旁路直播的输出码率帧率
124
+    apc.bitrate = [config[@"bitrate"] integerValue]; //旁路直播输出码流的码率
125
+    apc.defaultLayout = [config[@"defaultLayout"] integerValue]; //设置流生命周期
126
+    apc.lifeCycle = [config[@"lifeCycle"] integerValue]; //默认合图布局
127
+    apc.publishUrl = config[@"publishUrl"]; //合图推流地址
128
+    apc.rawStreamUrl = config[@"rawStreamUrl"]; //单流地址
129
+    apc.extraInfo = config[@"extraInfo"]; //其他信息
130
+    apc.owner = [config[@"owner"] boolValue]; //是否将当前主播设为该 RTMP 流的主人
131
+  
132
+    [self.rtcEngine configPublisher:apc];
133
+}
134
+
135
+//设置本地视频显示模式
136
+RCT_EXPORT_METHOD(setLocalRenderMode:(NSUInteger)mode){
137
+    [self.rtcEngine setLocalRenderMode:mode];
117 138
 }
118 139
 
140
+//设置远端视频显示模式
141
+RCT_EXPORT_METHOD(setRemoteRenderMode:(NSUInteger)uid mode:(NSUInteger)mode){
142
+    [self.rtcEngine setRemoteRenderMode:uid mode:mode];
143
+}
144
+
145
+//启用说话者音量提示
146
+RCT_EXPORT_METHOD(enableAudioVolumeIndication:(NSUInteger)interval smooth:(NSUInteger)smooth){
147
+    [self.rtcEngine enableAudioVolumeIndication:interval smooth:smooth];
148
+}
149
+
150
+//开启屏幕共享
151
+//RCT_EXPORT_METHOD(startScreenCapture:(NSUInteger)windowId){
152
+//
153
+//}
154
+
119 155
 //关闭视频预览
120 156
 RCT_EXPORT_METHOD(stopPreview){
121 157
     [self.rtcEngine stopPreview];
@@ -265,6 +301,25 @@ RCT_EXPORT_METHOD(getSdkVersion:(RCTResponseSenderBlock)callback){
265 301
     [self sendEvent:params];
266 302
 }
267 303
 
304
+/*
305
+ 音量提示回调
306
+ 需要开启enableAudioVolumeIndication
307
+ */
308
+- (void)rtcEngine:(AgoraRtcEngineKit *)engine reportAudioVolumeIndicationOfSpeakers:(NSArray*)speakers totalVolume:(NSInteger)totalVolume {
309
+    NSMutableDictionary *params = @{}.mutableCopy;
310
+    params[@"type"] = @"onAudioVolumeIndication";
311
+    
312
+    NSMutableArray *arr = [NSMutableArray array];
313
+    for (AgoraRtcAudioVolumeInfo *obj in speakers) {
314
+        [arr addObject:@{@"uid":[NSNumber numberWithInteger:obj.uid], @"volume":[NSNumber numberWithInteger:obj.volume]}];
315
+    }
316
+    
317
+    params[@"speakers"] = arr;
318
+    params[@"totalVolume"] = [NSNumber numberWithInteger:totalVolume];
319
+    
320
+    [self sendEvent:params];
321
+}
322
+
268 323
 - (void)sendEvent:(NSDictionary *)params {
269 324
     [_bridge.eventDispatcher sendDeviceEventWithName:@"agoraEvent" body:params];
270 325
 }

Binär
ios/RCTAgora/libs/AgoraRtcCryptoLoader.framework/AgoraRtcCryptoLoader Visa fil


+ 54
- 29
ios/RCTAgora/libs/AgoraRtcEngineKit.framework/Headers/AgoraRtcEngineKit.h Visa fil

@@ -39,7 +39,6 @@ typedef NS_ENUM(NSInteger, AgoraRtcWarningCode) {
39 39
     AgoraRtc_Warn_Adm_PlaybackMalfunction = 1020,
40 40
     AgoraRtc_Warn_Adm_RecordMalfunction = 1021,
41 41
     AgoraRtc_Warn_Adm_Interruption = 1025,
42
-    AgoraRtc_Warn_Adm_RouteChange = 1026,
43 42
     AgoraRtc_Warn_Apm_Howling = 1051,
44 43
 };
45 44
 
@@ -188,15 +187,21 @@ typedef NS_ENUM(NSInteger, AgoraRtcVideoStreamType) {
188 187
     AgoraRtc_VideoStream_Low = 1,
189 188
 };
190 189
 
191
-typedef NS_ENUM(NSInteger, AudioOutputRouting)
190
+typedef NS_ENUM(NSInteger, AgoraRtcAudioOutputRouting)
192 191
 {
193
-    AudioOutputRouting_Default = -1,
194
-    AudioOutputRouting_Headset = 0,
195
-    AudioOutputRouting_Earpiece = 1,
196
-    AudioOutputRouting_HeadsetNoMic = 2,
197
-    AudioOutputRouting_Speakerphone = 3,
198
-    AudioOutputRouting_Loudspeaker = 4,
199
-    AudioOutputRouting_HeadsetBluetooth = 5
192
+    AgoraRtc_AudioOutputRouting_Default = -1,
193
+    AgoraRtc_AudioOutputRouting_Headset = 0,
194
+    AgoraRtc_AudioOutputRouting_Earpiece = 1,
195
+    AgoraRtc_AudioOutputRouting_HeadsetNoMic = 2,
196
+    AgoraRtc_AudioOutputRouting_Speakerphone = 3,
197
+    AgoraRtc_AudioOutputRouting_Loudspeaker = 4,
198
+    AgoraRtc_AudioOutputRouting_HeadsetBluetooth = 5
199
+};
200
+
201
+typedef NS_ENUM(NSInteger, AgoraRtcAudioRecordingQuality) {
202
+    AgoraRtc_AudioRecordingQuality_Low = 0,
203
+    AgoraRtc_AudioRecordingQuality_Medium = 1,
204
+    AgoraRtc_AudioRecordingQuality_High = 2
200 205
 };
201 206
 
202 207
 typedef NS_ENUM(NSUInteger, AgoraRtcLogFilter) {
@@ -372,6 +377,9 @@ __attribute__((visibility("default"))) @interface AgoraPublisherConfiguration :
372 377
 @property (assign, nonatomic) NSInteger bitrate;
373 378
 @property (assign, nonatomic) NSInteger defaultLayout;
374 379
 @property (assign, nonatomic) AgoraRtmpStreamLifeCycle lifeCycle;
380
+@property (assign, nonatomic) NSInteger injectStreamWidth;
381
+@property (assign, nonatomic) NSInteger injectStreamHeight;
382
+@property (copy, nonatomic) NSString* injectStreamUrl;
375 383
 @property (copy, nonatomic) NSString* publishUrl;
376 384
 @property (copy, nonatomic) NSString* rawStreamUrl;
377 385
 @property (copy, nonatomic) NSString* extraInfo;
@@ -387,6 +395,7 @@ __attribute__((visibility("default"))) @interface AgoraPublisherConfigurationBui
387 395
 - (AgoraPublisherConfigurationBuilder *) setPublisherUrl:(NSString*)url;
388 396
 - (AgoraPublisherConfigurationBuilder *) setRawStreamUrl:(NSString*)url;
389 397
 - (AgoraPublisherConfigurationBuilder *) setExtraInfo:(NSString *)info;
398
+- (AgoraPublisherConfigurationBuilder *) injectStream:(NSString *)url width:(NSInteger)width height:(NSInteger)height;
390 399
 - (AgoraPublisherConfiguration *) build;
391 400
 @end
392 401
 
@@ -500,7 +509,7 @@ __attribute__((visibility("default"))) @interface AgoraPublisherConfigurationBui
500 509
  *  @param engine The engine kit
501 510
  *  @param routing the current audio output routing
502 511
  */
503
-- (void)rtcEngine:(AgoraRtcEngineKit *)engine didAudioRouteChanged:(AudioOutputRouting)routing;
512
+- (void)rtcEngine:(AgoraRtcEngineKit *)engine didAudioRouteChanged:(AgoraRtcAudioOutputRouting)routing;
504 513
 
505 514
 
506 515
 /**
@@ -549,6 +558,13 @@ __attribute__((visibility("default"))) @interface AgoraPublisherConfigurationBui
549 558
  */
550 559
 - (void)rtcEngineMediaEngineDidAudioMixingFinish:(AgoraRtcEngineKit *)engine;
551 560
 
561
+/**
562
+ *  Event of meida engine finish audio mixing.
563
+ *
564
+ *  @param engine The engine kit
565
+ */
566
+- (void)rtcEngineMediaEngineDidAudioEffectFinish:(AgoraRtcEngineKit *)engine soundId:(NSInteger)soundId;
567
+
552 568
 /**
553 569
  *  Event of camera opened
554 570
  *
@@ -723,6 +739,14 @@ __attribute__((visibility("default"))) @interface AgoraPublisherConfigurationBui
723 739
  */
724 740
 - (void)rtcEngine:(AgoraRtcEngineKit *)engine firstRemoteAudioFrameOfUid:(NSUInteger)uid elapsed:(NSInteger)elapsed;
725 741
 
742
+
743
+/**
744
+ *  The sdk reports who is active speaker in the channel
745
+ *
746
+ *  @param engine      The engine kit
747
+ *  @param speakerUid  The speaker who is talking
748
+ */
749
+- (void)rtcEngine:(AgoraRtcEngineKit *)engine activeSpeaker:(NSUInteger)speakerUid;
726 750
 @end
727 751
 
728 752
 
@@ -1004,10 +1028,12 @@ __attribute__((visibility("default"))) @interface AgoraRtcEngineKit : NSObject
1004 1028
  *  Start recording conversation to file specified by the file path.
1005 1029
  *
1006 1030
  *  @param filePath file path to save recorded conversation.
1031
+ *  @param quality  encode quality for the record file
1007 1032
  *
1008 1033
  *  @return 0 when executed successfully. return negative value if failed.
1009 1034
  */
1010
-- (int)startAudioRecording:(NSString*)filePath;
1035
+- (int)startAudioRecording:(NSString*)filePath
1036
+                   quality:(AgoraRtcAudioRecordingQuality)quality;
1011 1037
 
1012 1038
 
1013 1039
 /**
@@ -1029,23 +1055,9 @@ __attribute__((visibility("default"))) @interface AgoraRtcEngineKit : NSObject
1029 1055
 - (int)getAudioMixingCurrentPosition;
1030 1056
 - (int)setAudioMixingPosition:(NSInteger) pos;
1031 1057
 
1032
-/**
1033
- *  Start screen capture
1034
- *
1035
- *  @return 0 when executed successfully. return negative value if failed.
1036
- */
1037
-- (int)startScreenCapture:(NSUInteger)windowId;
1038
-
1039
-
1040
-/**
1041
- *  Stop screen capture
1042
- *
1043
- *  @return 0 when executed successfully. return negative value if failed.
1044
- */
1045
-- (int)stopScreenCapture;
1046 1058
 
1047 1059
 
1048
-- (int)setScreenCaptureId:(NSUInteger)windowId;
1060
+//- (int)setScreenCaptureId:(NSUInteger)windowId;
1049 1061
 
1050 1062
 
1051 1063
 /**
@@ -1322,6 +1334,20 @@ __attribute__((visibility("default"))) @interface AgoraRtcEngineKit : NSObject
1322 1334
 - (int)clearVideoCompositingLayout;
1323 1335
 
1324 1336
 #if (!(TARGET_OS_IPHONE) && (TARGET_OS_MAC))
1337
+/**
1338
+ *  Start screen capture
1339
+ *
1340
+ *  @return 0 when executed successfully. return negative value if failed.
1341
+ */
1342
+- (int)startScreenCapture:(NSUInteger)windowId withCaptureFreq: (int) captureFreq AndRect :(CGRect)rect;
1343
+
1344
+
1345
+/**
1346
+ *  Stop screen capture
1347
+ *
1348
+ *  @return 0 when executed successfully. return negative value if failed.
1349
+ */
1350
+- (int)stopScreenCapture;
1325 1351
 
1326 1352
 - (void) monitorDeviceChange: (BOOL)enabled;
1327 1353
 - (NSArray*) enumerateDevices:(AgoraRtcDeviceType)type;  // return array of AgoraRtcDeviceInfo
@@ -1340,12 +1366,11 @@ __attribute__((visibility("default"))) @interface AgoraRtcEngineKit : NSObject
1340 1366
 - (int) stopCaptureDeviceTest;
1341 1367
 #endif
1342 1368
 
1343
-- (int) checkAVUrlCompatibility:(NSURL*)url
1344
-                 completionBlock:(void(^)())checkCompletionBlock;
1345
-
1346 1369
 //Audio Effects
1347 1370
 - (double) getEffectsVolume;
1348 1371
 - (int) setEffectsVolume:(double) volume;
1372
+- (int) setVolumeOfEffect:(int) soundId
1373
+               withVolume:(double) volume;
1349 1374
 - (int) playEffect:(int) soundId
1350 1375
           filePath:(NSString*)filePath
1351 1376
               loop:(BOOL)loop

+ 113
- 47
ios/RCTAgora/libs/AgoraRtcEngineKit.framework/Headers/IAgoraRtcEngine.h Visa fil

@@ -72,10 +72,13 @@ public:
72 72
         ptr_ = ptr;
73 73
     }
74 74
     template<class C1, class C2>
75
-    void queryInterface(C1& c, C2 iid) {
76
-		pointer_type p;
77
-        if (!c.queryInterface(iid, (void**)&p))
78
-			reset(p);
75
+    bool queryInterface(C1* c, C2 iid) {
76
+        pointer_type p = NULL;
77
+        if (c && !c->queryInterface(iid, (void**)&p))
78
+        {
79
+            reset(p);
80
+        }
81
+        return p != NULL;;
79 82
 	}
80 83
 private:
81 84
     AutoPtr(const AutoPtr&);
@@ -129,7 +132,6 @@ enum WARN_CODE_TYPE
129 132
     // sdk: 100~1000
130 133
     WARN_SWITCH_LIVE_VIDEO_TIMEOUT = 111,
131 134
 	WARN_SET_CLIENT_ROLE_TIMEOUT = 118,
132
-    WARN_SET_CLIENT_ROLE_NOT_AUTHORIZED = 119,
133 135
 };
134 136
 
135 137
 enum ERROR_CODE_TYPE
@@ -168,6 +170,7 @@ enum ERROR_CODE_TYPE
168 170
 	ERR_BITRATE_LIMIT = 115,
169 171
 	ERR_TOO_MANY_DATA_STREAMS = 116,
170 172
 	ERR_STREAM_MESSAGE_TIMEOUT = 117,
173
+    ERR_SET_CLIENT_ROLE_NOT_AUTHORIZED = 119,
171 174
 
172 175
     //1001~2000
173 176
     ERR_LOAD_MEDIA_ENGINE = 1001,
@@ -230,7 +233,6 @@ enum MEDIA_ENGINE_EVENT_CODE_TYPE
230 233
     MEDIA_ENGINE_RECORDING_WARNING = 2,
231 234
     MEDIA_ENGINE_PLAYOUT_WARNING = 3,
232 235
     MEDIA_ENGINE_AUDIO_FILE_MIX_FINISH = 10,
233
-    MEDIA_ENGINE_AUDIO_SAMPLE_RATE_RECONFIG_FINISH = 11,
234 236
     // media engine role changed
235 237
     MEDIA_ENGINE_ROLE_BROADCASTER_SOLO = 20,
236 238
     MEDIA_ENGINE_ROLE_BROADCASTER_INTERACTIVE = 21,
@@ -258,6 +260,13 @@ enum MEDIA_DEVICE_TYPE
258 260
     VIDEO_CAPTURE_DEVICE = 3,
259 261
 };
260 262
 
263
+enum AUDIO_RECORDING_QUALITY_TYPE
264
+{
265
+    AUDIO_RECORDING_QUALITY_LOW = 0,
266
+    AUDIO_RECORDING_QUALITY_MEDIUM = 1,
267
+    AUDIO_RECORDING_QUALITY_HIGH = 2,
268
+};
269
+
261 270
 enum QUALITY_TYPE
262 271
 {
263 272
     QUALITY_UNKNOWN = 0,
@@ -276,6 +285,13 @@ enum RENDER_MODE_TYPE
276 285
     RENDER_MODE_ADAPTIVE = 3,
277 286
 };
278 287
 
288
+enum VIDEO_MIRROR_MODE_TYPE
289
+{
290
+    VIDEO_MIRROR_MODE_AUTO = 0,//determined by SDK
291
+    VIDEO_MIRROR_MODE_ENABLED = 1,//enabled mirror
292
+    VIDEO_MIRROR_MODE_DISABLED = 2,//disable mirror
293
+};
294
+
279 295
 enum VIDEO_PROFILE_TYPE
280 296
 {                                   // res       fps  kbps
281 297
     VIDEO_PROFILE_120P = 0,         // 160x120   15   65
@@ -435,6 +451,16 @@ struct VideoCompositingLayout
435 451
     {}
436 452
 };
437 453
 
454
+typedef struct Rect {
455
+    int top;
456
+    int left;
457
+    int bottom;
458
+    int right;
459
+
460
+    Rect(): top(0), left(0), bottom(0), right(0) {}
461
+    Rect(int t, int l, int b, int r): top(t), left(l), bottom(b), right(r) {}
462
+} Rect;
463
+
438 464
 #if defined(_WIN32)
439 465
 
440 466
 enum RTMP_STREAM_LIFE_CYCLE_TYPE
@@ -451,10 +477,14 @@ struct PublisherConfiguration {
451 477
 	int defaultLayout;
452 478
 	int lifecycle;
453 479
 	bool owner;
480
+	int injectStreamWidth;
481
+	int injectStreamHeight;
482
+	const char* injectStreamUrl;
454 483
 	const char* publishUrl;
455 484
 	const char* rawStreamUrl;
456 485
 	const char* extraInfo;
457 486
 
487
+
458 488
 	PublisherConfiguration()
459 489
 		: width(640)
460 490
 		, height(360)
@@ -463,6 +493,9 @@ struct PublisherConfiguration {
463 493
 		, defaultLayout(1)
464 494
 		, lifecycle(RTMP_STREAM_LIFE_CYCLE_BIND2CHANNEL)
465 495
 		, owner(true)
496
+		, injectStreamWidth(0)
497
+		, injectStreamHeight(0)
498
+		, injectStreamUrl(NULL)
466 499
 		, publishUrl(NULL)
467 500
 		, rawStreamUrl(NULL)
468 501
 		, extraInfo(NULL)
@@ -673,6 +706,12 @@ public:
673 706
     virtual void onAudioMixingFinished() {
674 707
     }
675 708
 
709
+    /**
710
+    * When audio effect playback finished, this function will be called
711
+    */
712
+    virtual void onAudioEffectFinished(int soundId) {
713
+    }
714
+
676 715
     /**
677 716
     * when the video device state changed(plugged or removed), the function will be called
678 717
     * @param [in] deviceId
@@ -957,7 +996,12 @@ public:
957 996
         (void)uid;
958 997
         (void)elapsed;
959 998
     }
960
-
999
+    /** @param [in] uid
1000
+    *        the speaker uid who is talking in the channel
1001
+    */
1002
+    virtual void onActiveSpeaker(uid_t uid) {
1003
+        (void)uid;
1004
+    }
961 1005
 };
962 1006
 
963 1007
 /**
@@ -1566,7 +1610,7 @@ public:
1566 1610
 class AAudioDeviceManager : public agora::util::AutoPtr<IAudioDeviceManager>
1567 1611
 {
1568 1612
 public:
1569
-    AAudioDeviceManager(IRtcEngine& engine)
1613
+    AAudioDeviceManager(IRtcEngine* engine)
1570 1614
     {
1571 1615
 		queryInterface(engine, AGORA_IID_AUDIO_DEVICE_MANAGER);
1572 1616
     }
@@ -1575,7 +1619,7 @@ public:
1575 1619
 class AVideoDeviceManager : public agora::util::AutoPtr<IVideoDeviceManager>
1576 1620
 {
1577 1621
 public:
1578
-    AVideoDeviceManager(IRtcEngine& engine)
1622
+    AVideoDeviceManager(IRtcEngine* engine)
1579 1623
     {
1580 1624
 		queryInterface(engine, AGORA_IID_VIDEO_DEVICE_MANAGER);
1581 1625
     }
@@ -1584,21 +1628,25 @@ public:
1584 1628
 class AParameter : public agora::util::AutoPtr<IRtcEngineParameter>
1585 1629
 {
1586 1630
 public:
1587
-    AParameter(IRtcEngine& engine)
1631
+    AParameter(IRtcEngine& engine) { initialize(&engine); }
1632
+    AParameter(IRtcEngine* engine) { initialize(engine); }
1633
+    AParameter(IRtcEngineParameter* p) :agora::util::AutoPtr<IRtcEngineParameter>(p) {}
1634
+private:
1635
+    bool initialize(IRtcEngine* engine)
1588 1636
     {
1589
-        IRtcEngineParameter* p;
1590
-        if (!engine.queryInterface(AGORA_IID_RTC_ENGINE_PARAMETER, (void**)&p))
1637
+        IRtcEngineParameter* p = NULL;
1638
+        if (engine && !engine->queryInterface(AGORA_IID_RTC_ENGINE_PARAMETER, (void**)&p))
1591 1639
             reset(p);
1640
+        return p != NULL;
1592 1641
     }
1593
-    AParameter(IRtcEngineParameter* p)
1594
-        :agora::util::AutoPtr<IRtcEngineParameter>(p)
1595
-    {}
1596 1642
 };
1597 1643
 
1598 1644
 class RtcEngineParameters
1599 1645
 {
1600 1646
 public:
1601 1647
     RtcEngineParameters(IRtcEngine& engine)
1648
+        :m_parameter(&engine){}
1649
+    RtcEngineParameters(IRtcEngine* engine)
1602 1650
         :m_parameter(engine){}
1603 1651
 
1604 1652
     /**
@@ -1710,16 +1758,16 @@ public:
1710 1758
     *        the .wav file path you want to saved
1711 1759
     * @return return 0 if success or an error code
1712 1760
     */
1713
-    int startAudioRecording(const char* filePath) {
1761
+    int startAudioRecording(const char* filePath, AUDIO_RECORDING_QUALITY_TYPE quality) {
1714 1762
         if (!m_parameter) return -ERR_NOT_INITIALIZED;
1715 1763
 #if defined(_WIN32)
1716
-		util::AString path;
1717
-		if (!m_parameter->convertPath(filePath, path))
1718
-			filePath = path->c_str();
1719
-		else
1720
-			return -ERR_INVALID_ARGUMENT;
1764
+        util::AString path;
1765
+        if (!m_parameter->convertPath(filePath, path))
1766
+            filePath = path->c_str();
1767
+        else
1768
+            return -ERR_INVALID_ARGUMENT;
1721 1769
 #endif
1722
-		return m_parameter->setString("che.audio.start_recording", filePath);
1770
+        return setObject("che.audio.start_recording", "{\"filePath\":\"%s\",\"quality\":%d}", filePath, quality);
1723 1771
     }
1724 1772
 
1725 1773
     /**
@@ -1799,21 +1847,21 @@ public:
1799 1847
         return m_parameter ? m_parameter->setInt("che.audio.mixing.file.position", pos) : -ERR_NOT_INITIALIZED;
1800 1848
     }
1801 1849
 #if defined(__APPLE__)
1802
-	/**
1803
-	* start screen capture
1804
-	* @return return 0 if success or an error code
1805
-	*/
1806
-	int startScreenCapture(unsigned int windowId) {
1807
-        return m_parameter ? m_parameter->setUInt("che.video.start_screen_capture", windowId) : -ERR_NOT_INITIALIZED;
1808
-	}
1809
-
1810 1850
     /**
1811
-     * specify window id to capture
1812
-     * @return return 0 if success or an error code
1851
+     * start screen/windows capture
1852
+     *
1853
+     *  @param windowId screen capture, if windowId is 0; windows capture if windowsId isn't 0;
1854
+     *  @param rect     valid when windowId is 0; whole screen if rect is NULL.
1855
+     *
1856
+     *  @return return 0 if success or an error code
1813 1857
      */
1814
-    int setScreenCaptureWindow(unsigned int windowId) {
1815
-        return m_parameter ? m_parameter->setUInt("che.video.set_screen_capture_window", windowId) : -ERR_NOT_INITIALIZED;
1858
+    int startScreenCapture(unsigned int windowId, int captureFreq, const Rect *rect) {
1859
+        if (!rect)
1860
+            return setObject("che.video.start_screen_capture", "{\"id\":%u,\"captureFreq\":%d}", windowId, captureFreq);
1861
+        else
1862
+            return setObject("che.video.start_screen_capture", "{\"id\":%u,\"captureFreq\":%d,\"top\":%d,\"left\":%d,\"bottom\":%d,\"right\":%d}", windowId, captureFreq, rect->top, rect->left, rect->bottom, rect->right);
1816 1863
     }
1864
+
1817 1865
     /**
1818 1866
      * stop screen capture
1819 1867
      * @return return 0 if success or an error code
@@ -1823,20 +1871,20 @@ public:
1823 1871
     }
1824 1872
 #elif defined(_WIN32)
1825 1873
     /**
1826
-     * start screen capture
1827
-     * @return return 0 if success or an error code
1828
-     */
1829
-    int startScreenCapture(HWND windowId) {
1830
-        return m_parameter ? m_parameter->setUInt("che.video.start_screen_capture", (unsigned int)windowId) : -ERR_NOT_INITIALIZED;
1831
-    }
1832
-    
1833
-    /**
1834
-     * specify window id to capture
1835
-     * @return return 0 if success or an error code
1874
+     * start screen/windows capture
1875
+     *
1876
+     *  @param windowId screen capture, if windowId is 0; windows capture if windowsId isn't 0;
1877
+     *  @param rect     valid when windowId is 0; whole screen if rect is NULL.
1878
+     *
1879
+     *  @return return 0 if success or an error code
1836 1880
      */
1837
-    int setScreenCaptureWindow(HWND windowId) {
1838
-        return m_parameter ? m_parameter->setUInt("che.video.set_screen_capture_window", (unsigned int)windowId) : -ERR_NOT_INITIALIZED;
1881
+    int startScreenCapture(HWND windowId, int captureFreq, const Rect *rect) {
1882
+        if (!rect)
1883
+            return setObject("che.video.start_screen_capture", "{\"id\":%u,\"captureFreq\":%d}", (unsigned int)windowId, captureFreq);
1884
+        else
1885
+            return setObject("che.video.start_screen_capture", "{\"id\":%u,\"captureFreq\":%d,\"top\":%d,\"left\":%d,\"bottom\":%d,\"right\":%d}", (unsigned int)windowId, captureFreq, rect->top, rect->left, rect->bottom, rect->right);
1839 1886
     }
1887
+
1840 1888
     /**
1841 1889
      * stop screen capture
1842 1890
      * @return return 0 if success or an error code
@@ -1894,6 +1942,24 @@ public:
1894 1942
         return setObject("che.video.render_mode", "{\"uid\":%u,\"mode\":%d}", uid, renderMode);
1895 1943
     }
1896 1944
     
1945
+    int setLocalVideoMirrorMode(VIDEO_MIRROR_MODE_TYPE mirrorMode) {
1946
+        if (!m_parameter) return -ERR_NOT_INITIALIZED;
1947
+        const char *value;
1948
+        switch (mirrorMode) {
1949
+        case VIDEO_MIRROR_MODE_AUTO:
1950
+            value = "default";
1951
+            break;
1952
+        case VIDEO_MIRROR_MODE_ENABLED:
1953
+            value = "forceMirror";
1954
+            break;
1955
+        case VIDEO_MIRROR_MODE_DISABLED:
1956
+            value = "disableMirror";
1957
+            break;
1958
+        default:
1959
+            return -ERR_INVALID_ARGUMENT;
1960
+        }
1961
+        return m_parameter->setString("che.video.localViewMirrorSetting", value);
1962
+    }
1897 1963
 	int startRecordingService(const char* recordingKey) {
1898 1964
         return m_parameter ? m_parameter->setString("rtc.api.start_recording_service", recordingKey) : -ERR_NOT_INITIALIZED;
1899 1965
     }
@@ -1942,7 +2008,7 @@ public:
1942 2008
     }
1943 2009
     //only for live broadcasting
1944 2010
     int setVideoQualityParameters(bool preferFrameRateOverImageQuality) {
1945
-        return m_parameter ? m_parameter->setBool("rtc.video.prefer_frame_rate", preferFrameRateOverImageQuality) : -ERR_NOT_INITIALIZED;
2011
+        return setParameters("{\"rtc.video.prefer_frame_rate\":%s,\"che.video.prefer_frame_rate\":%s}", preferFrameRateOverImageQuality ? "true" : "false", preferFrameRateOverImageQuality ? "true" : "false");
1946 2012
     }
1947 2013
 protected:
1948 2014
     AParameter& parameter() {

+ 5
- 2
package.json Visa fil

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "name": "react-native-agora",
3
-  "version": "1.0.7",
3
+  "version": "1.0.8",
4 4
   "description": "声网Agora",
5 5
   "main": "index.js",
6 6
   "scripts": {
@@ -13,7 +13,10 @@
13 13
   "keywords": [
14 14
     "agora",
15 15
     "react-native",
16
-    "react-native-agora"
16
+    "react-native-agora",
17
+    "live",
18
+    "react",
19
+    "Agora"
17 20
   ],
18 21
   "author": "",
19 22
   "license": "ISC",