Browse Source

Merge pull request #90 from syanbo/chore/2.9.0-sdk-integrate

upgrade to 2.9.0 sdk
matrixbirds 5 years ago
parent
commit
b013b6d64e

+ 15
- 0
CHANGELOG View File

2
 
2
 
3
 #### 2.9.0-alpha.1
3
 #### 2.9.0-alpha.1
4
   - fix typo: rename `methodisSpeakerphoneEnabled` to `isSpeakerphoneEnabled`
4
   - fix typo: rename `methodisSpeakerphoneEnabled` to `isSpeakerphoneEnabled`
5
+  - events deprecated & instead:
6
+    * `microphoneEnabled` instead `localAudioStateChanged`
7
+    * `audioTransportStatsOfUid` instead `remoteAudioStats`
8
+    * `videoTransportStatsOfUid` instead `remoteVideoStats`
9
+    * `userMuteVideo`, `userEnableVideo`, `userEnableLocalVideo` & `firstRemoteVideoDecoded` instead `remoteVideoStateChanged`
10
+  - events enhancement:
11
+    * `rtcStats`, `leaveChannel` add channel stats `txAudioBytes`, `txVideoBytes`, `rxAudioBytes`, `rxVideoBytes`, `txPacketLossRate`, `rxPacketLossRate`
12
+  - new events:
13
+    * `remoteAudioStateChanged` subscribe for remote audio state
14
+    * `localAudioStateChanged` subscribe for local audio state
15
+    * `localAudioStats` subscribe for local audio stats
16
+    * `mediaRelayStateChanged`, `receivedChannelMediaRelay`
17
+  - new apis:
18
+    * `switchChannel` switch to specified channel
19
+    * `startChannelMediaRelay`, `updateChannelMediaRelay`, `stopChannelMediaRelay`, `removeChannelMediaRelay` relay media streams operation for across channels.
5
 
20
 
6
 #### 2.8.0-alpha.1
21
 #### 2.8.0-alpha.1
7
   - add `string uid` api support
22
   - add `string uid` api support

+ 44
- 0
android/CMakeLists.txt View File

1
+# For more information about using CMake with Android Studio, read the
2
+# documentation: https://d.android.com/studio/projects/add-native-code.html
3
+
4
+# Sets the minimum version of CMake required to build the native library.
5
+
6
+cmake_minimum_required(VERSION 3.4.1)
7
+
8
+# Creates and names a library, sets it as either STATIC
9
+# or SHARED, and provides the relative paths to its source code.
10
+# You can define multiple libraries, and CMake builds them for you.
11
+# Gradle automatically packages shared libraries with your APK.
12
+
13
+add_library( # Sets the name of the library.
14
+             apm-plugin-raw-data-api-java
15
+
16
+             # Sets the library as a shared library.
17
+             SHARED
18
+
19
+             # Provides a relative path to your source file(s).
20
+             src/main/cpp/src/agora_media_pre_processing.cpp )
21
+
22
+# Searches for a specified prebuilt library and stores the path as a
23
+# variable. Because CMake includes system libraries in the search path by
24
+# default, you only need to specify the name of the public NDK library
25
+# you want to add. CMake verifies that the library exists before
26
+# completing its build.
27
+
28
+find_library( # Sets the name of the path variable.
29
+              log-lib
30
+
31
+              # Specifies the name of the NDK library that
32
+              # you want CMake to locate.
33
+              log )
34
+
35
+# Specifies libraries CMake should link to your target library. You
36
+# can link multiple libraries, such as libraries you define in this
37
+# build script, prebuilt third-party libraries, or system libraries.
38
+
39
+target_link_libraries( # Specifies the target library.
40
+                       apm-plugin-raw-data-api-java
41
+
42
+                       # Links the target library to the log library
43
+                       # included in the NDK.
44
+                       ${log-lib} )

+ 1
- 1
android/build.gradle View File

61
     def androidSupportVersion = rootProject.hasProperty("androidSupportVersion")  ? rootProject.androidSupportVersion : DEFAULT_ANDROID_SUPPORT_VERSION
61
     def androidSupportVersion = rootProject.hasProperty("androidSupportVersion")  ? rootProject.androidSupportVersion : DEFAULT_ANDROID_SUPPORT_VERSION
62
     // from internet
62
     // from internet
63
     implementation "com.android.support:appcompat-v7:$androidSupportVersion"
63
     implementation "com.android.support:appcompat-v7:$androidSupportVersion"
64
-    implementation "io.agora.rtc:full-sdk:2.8.2"
64
+    implementation "io.agora.rtc:full-sdk:2.9.0"
65
     // from node_modules
65
     // from node_modules
66
     implementation "com.facebook.react:react-native:+"
66
     implementation "com.facebook.react:react-native:+"
67
 }
67
 }

+ 781
- 0
android/src/main/cpp/include/AgoraBase.h View File

1
+//  Agora Engine SDK
2
+//
3
+//  Copyright (c) 2019 Agora.io. All rights reserved.
4
+//
5
+
6
+#ifndef AGORA_BASE_H
7
+#define AGORA_BASE_H
8
+
9
+#include <stddef.h>
10
+#include <stdio.h>
11
+#include <stdarg.h>
12
+
13
+#if defined(_WIN32)
14
+#define WIN32_LEAN_AND_MEAN
15
+#include <windows.h>
16
+#define AGORA_CALL __cdecl
17
+#if defined(AGORARTC_EXPORT)
18
+#define AGORA_API extern "C" __declspec(dllexport)
19
+#else
20
+#define AGORA_API extern "C" __declspec(dllimport)
21
+#endif
22
+#elif defined(__APPLE__)
23
+#include <TargetConditionals.h>
24
+#define AGORA_API __attribute__((visibility("default"))) extern "C"
25
+#define AGORA_CALL
26
+#elif defined(__ANDROID__) || defined(__linux__)
27
+#define AGORA_API extern "C" __attribute__((visibility("default")))
28
+#define AGORA_CALL
29
+#else
30
+#define AGORA_API extern "C"
31
+#define AGORA_CALL
32
+#endif
33
+
34
+namespace agora {
35
+namespace util {
36
+
37
+template<class T>
38
+class AutoPtr {
39
+    typedef T value_type;
40
+    typedef T* pointer_type;
41
+public:
42
+    AutoPtr(pointer_type p=0)
43
+        :ptr_(p)
44
+    {}
45
+    ~AutoPtr() {
46
+        if (ptr_)
47
+            ptr_->release();
48
+    }
49
+    operator bool() const { return ptr_ != (pointer_type)0; }
50
+    value_type& operator*() const {
51
+        return *get();
52
+    }
53
+
54
+    pointer_type operator->() const {
55
+        return get();
56
+    }
57
+
58
+    pointer_type get() const {
59
+        return ptr_;
60
+    }
61
+
62
+    pointer_type release() {
63
+        pointer_type tmp = ptr_;
64
+        ptr_ = 0;
65
+        return tmp;
66
+    }
67
+
68
+    void reset(pointer_type ptr = 0) {
69
+        if (ptr != ptr_ && ptr_)
70
+            ptr_->release();
71
+        ptr_ = ptr;
72
+    }
73
+    template<class C1, class C2>
74
+    bool queryInterface(C1* c, C2 iid) {
75
+        pointer_type p = NULL;
76
+        if (c && !c->queryInterface(iid, (void**)&p))
77
+        {
78
+            reset(p);
79
+        }
80
+        return p != NULL;
81
+	}
82
+private:
83
+    AutoPtr(const AutoPtr&);
84
+    AutoPtr& operator=(const AutoPtr&);
85
+private:
86
+    pointer_type ptr_;
87
+};
88
+class IString {
89
+protected:
90
+    virtual ~IString(){}
91
+public:
92
+    virtual bool empty() const = 0;
93
+    virtual const char* c_str() = 0;
94
+    virtual const char* data() = 0;
95
+    virtual size_t length() = 0;
96
+    virtual void release() = 0;
97
+};
98
+typedef AutoPtr<IString> AString;
99
+
100
+}//namespace util
101
+
102
+enum INTERFACE_ID_TYPE
103
+{
104
+    AGORA_IID_AUDIO_DEVICE_MANAGER = 1,
105
+    AGORA_IID_VIDEO_DEVICE_MANAGER = 2,
106
+    AGORA_IID_RTC_ENGINE_PARAMETER = 3,
107
+    AGORA_IID_MEDIA_ENGINE = 4,
108
+    AGORA_IID_SIGNALING_ENGINE = 8,
109
+};
110
+
111
+    /** Warning code.
112
+     */
113
+enum WARN_CODE_TYPE
114
+{
115
+  /** 8: The specified view is invalid. Specify a view when using the video call function.
116
+  */
117
+    WARN_INVALID_VIEW = 8,
118
+    /** 16: Failed to initialize the video function, possibly caused by a lack of resources. The users cannot see the video while the voice communication is not affected.
119
+    */
120
+    WARN_INIT_VIDEO = 16,
121
+    /** 20: The request is pending, usually due to some module not being ready, and the SDK postponed processing the request.
122
+    */
123
+    WARN_PENDING = 20,
124
+    /** 103: No channel resources are available. Maybe because the server cannot allocate any channel resource.
125
+    */
126
+    WARN_NO_AVAILABLE_CHANNEL = 103,
127
+    /** 104: A timeout occurs when looking up the channel. When joining a channel, the SDK looks up the specified channel. This warning usually occurs when the network condition is too poor for the SDK to connect to the server.
128
+    */
129
+    WARN_LOOKUP_CHANNEL_TIMEOUT = 104,
130
+    /** **DEPRECATED** 105: The server rejects the request to look up the channel. The server cannot process this request or the request is illegal.
131
+     
132
+     Deprecated as of v2.4.1. Use CONNECTION_CHANGED_REJECTED_BY_SERVER(10) in the \ref agora::rtc::IRtcEngineEventHandler::onConnectionStateChanged "onConnectionStateChanged" callback instead.
133
+    */
134
+    WARN_LOOKUP_CHANNEL_REJECTED = 105,
135
+    /** 106: A timeout occurs when opening the channel. Once the specific channel is found, the SDK opens the channel. This warning usually occurs when the network condition is too poor for the SDK to connect to the server.
136
+    */
137
+    WARN_OPEN_CHANNEL_TIMEOUT = 106,
138
+    /** 107: The server rejects the request to open the channel. The server cannot process this request or the request is illegal.
139
+    */
140
+    WARN_OPEN_CHANNEL_REJECTED = 107,
141
+
142
+    // sdk: 100~1000
143
+    /** 111: A timeout occurs when switching to the live video.
144
+    */
145
+    WARN_SWITCH_LIVE_VIDEO_TIMEOUT = 111,
146
+    /** 118: A timeout occurs when setting the client role in the live broadcast profile.
147
+    */
148
+    WARN_SET_CLIENT_ROLE_TIMEOUT = 118,
149
+    /** 121: The ticket to open the channel is invalid.
150
+    */
151
+    WARN_OPEN_CHANNEL_INVALID_TICKET = 121,
152
+    /** 122: Try connecting to another server.
153
+    */
154
+    WARN_OPEN_CHANNEL_TRY_NEXT_VOS = 122,
155
+    WARN_CHANNEL_CONNECTION_UNRECOVERABLE = 131,
156
+    WARN_CHANNEL_CONNECTION_IP_CHANGED = 132,
157
+    WARN_CHANNEL_CONNECTION_PORT_CHANGED = 133,
158
+    /** 701: An error occurs in opening the audio mixing file.
159
+    */
160
+    WARN_AUDIO_MIXING_OPEN_ERROR = 701,
161
+    /** 1014: Audio Device Module: a warning occurs in the playback device.
162
+    */
163
+    WARN_ADM_RUNTIME_PLAYOUT_WARNING = 1014,
164
+    /** 1016: Audio Device Module: a warning occurs in the recording device.
165
+    */
166
+    WARN_ADM_RUNTIME_RECORDING_WARNING = 1016,
167
+    /** 1019: Audio Device Module: no valid audio data is collected.
168
+    */
169
+    WARN_ADM_RECORD_AUDIO_SILENCE = 1019,
170
+    /** 1020: Audio Device Module: the playback device fails.
171
+    */
172
+    WARN_ADM_PLAYOUT_MALFUNCTION = 1020,
173
+    /** 1021: Audio Device Module: the recording device fails.
174
+    */
175
+    WARN_ADM_RECORD_MALFUNCTION = 1021,
176
+    /** 1029: During a call, the audio session category should be set to 
177
+     * AVAudioSessionCategoryPlayAndRecord, and RtcEngine monitors this value. 
178
+     * If the audio session category is set to other values, this warning code 
179
+     * is triggered and RtcEngine will forcefully set it back to 
180
+     * AVAudioSessionCategoryPlayAndRecord.
181
+    */
182
+    WARN_ADM_IOS_CATEGORY_NOT_PLAYANDRECORD = 1029,
183
+    /** 
184
+     */
185
+    WARN_ADM_IOS_SAMPLERATE_CHANGE = 1030,
186
+    /** 1031: Audio Device Module: the recorded audio voice is too low.
187
+    */
188
+    WARN_ADM_RECORD_AUDIO_LOWLEVEL = 1031,
189
+    /** 1032: Audio Device Module: the playback audio voice is too low.
190
+    */
191
+    WARN_ADM_PLAYOUT_AUDIO_LOWLEVEL = 1032,
192
+    /** 1040: Audio device module: An exception occurs with the audio drive. 
193
+     * Solutions: 
194
+     * - Disable or re-enable the audio device.
195
+     * - Re-enable your device.
196
+     * - Update the sound card drive.
197
+     */
198
+    WARN_ADM_WINDOWS_NO_DATA_READY_EVENT = 1040,
199
+    /** 1051: Audio Device Module: howling is detected.
200
+    */
201
+    WARN_APM_HOWLING = 1051,
202
+    /** 1052: Audio Device Module: the device is in the glitch state.
203
+    */
204
+    WARN_ADM_GLITCH_STATE = 1052,
205
+    /** 1053: Audio Device Module: the underlying audio settings have changed.
206
+    */
207
+    WARN_ADM_IMPROPER_SETTINGS = 1053,
208
+    /**
209
+        */
210
+    WARN_ADM_WIN_CORE_NO_RECORDING_DEVICE = 1322,
211
+    /** 1323: Audio device module: No available playback device. 
212
+     * Solution: Plug in the audio device.
213
+    */
214
+    WARN_ADM_WIN_CORE_NO_PLAYOUT_DEVICE = 1323,
215
+    /** Audio device module: The capture device is released improperly. 
216
+     * Solutions: 
217
+     * - Disable or re-enable the audio device.
218
+     * - Re-enable your device.
219
+     * - Update the sound card drive.
220
+     */
221
+    WARN_ADM_WIN_CORE_IMPROPER_CAPTURE_RELEASE = 1324,
222
+    /** 1610: Super-resolution warning: the original video dimensions of the remote user exceed 640 &times; 480.
223
+    */
224
+    WARN_SUPER_RESOLUTION_STREAM_OVER_LIMITATION = 1610,
225
+    /** 1611: Super-resolution warning: another user is using super resolution.
226
+    */
227
+    WARN_SUPER_RESOLUTION_USER_COUNT_OVER_LIMITATION = 1611,
228
+    /** 1612: The device is not supported.
229
+    */
230
+    WARN_SUPER_RESOLUTION_DEVICE_NOT_SUPPORTED = 1612,
231
+
232
+    WARN_RTM_LOGIN_TIMEOUT = 2005,
233
+    WARN_RTM_KEEP_ALIVE_TIMEOUT = 2009
234
+};
235
+
236
+/** Error code.
237
+*/
238
+enum ERROR_CODE_TYPE
239
+{
240
+  /** 0: No error occurs.
241
+  */
242
+    ERR_OK = 0,
243
+    //1~1000
244
+    /** 1: A general error occurs (no specified reason).
245
+    */
246
+    ERR_FAILED = 1,
247
+    /** 2: An invalid parameter is used. For example, the specific channel name includes illegal characters.
248
+    */
249
+    ERR_INVALID_ARGUMENT = 2,
250
+    /** 3: The SDK module is not ready. Possible solutions:
251
+
252
+     - Check the audio device.
253
+     - Check the completeness of the application.
254
+     - Re-initialize the RTC engine.
255
+     */
256
+    ERR_NOT_READY = 3,
257
+    /** 4: The SDK does not support this function.
258
+     */
259
+    ERR_NOT_SUPPORTED = 4,
260
+    /** 5: The request is rejected. This is for internal SDK use only, and it does not return to the application through any method or callback.
261
+     */
262
+    ERR_REFUSED = 5,
263
+    /** 6: The buffer size is not big enough to store the returned data.
264
+     */
265
+    ERR_BUFFER_TOO_SMALL = 6,
266
+    /** 7: The SDK is not initialized before calling this method.
267
+     */
268
+    ERR_NOT_INITIALIZED = 7,
269
+    /** 9: No permission exists. This is for internal SDK use only, and it does not return to the application through any method or callback.
270
+     */
271
+    ERR_NO_PERMISSION = 9,
272
+    /** 10: An API method timeout occurs. Some API methods require the SDK to return the execution result, and this error occurs if the request takes too long (more than 10 seconds) for the SDK to process.
273
+     */
274
+    ERR_TIMEDOUT = 10,
275
+    /** 11: The request is canceled. This is for internal SDK use only, and it does not return to the application through any method or callback.
276
+     */
277
+    ERR_CANCELED = 11,
278
+    /** 12: The method is called too often. This is for internal SDK use only, and it does not return to the application through any method or callback.
279
+     */
280
+    ERR_TOO_OFTEN = 12,
281
+    /** 13: The SDK fails to bind to the network socket. This is for internal SDK use only, and it does not return to the application through any method or callback.
282
+     */
283
+    ERR_BIND_SOCKET = 13,
284
+    /** 14: The network is unavailable. This is for internal SDK use only, and it does not return to the application through any method or callback.
285
+     */
286
+    ERR_NET_DOWN = 14,
287
+    /** 15: No network buffers are available. This is for internal SDK internal use only, and it does not return to the application through any method or callback.
288
+     */
289
+    ERR_NET_NOBUFS = 15,
290
+    /** 17: The request to join the channel is rejected. This error usually occurs when the user is already in the channel, and still calls the method to join the channel, for example, \ref agora::rtc::IRtcEngine::joinChannel "joinChannel".
291
+     */
292
+    ERR_JOIN_CHANNEL_REJECTED = 17,
293
+    /** 18: The request to leave the channel is rejected.
294
+
295
+     This error usually occurs:
296
+
297
+     - When the user has left the channel and still calls \ref agora::rtc::IRtcEngine::leaveChannel "leaveChannel" to leave the channel. In this case, stop calling \ref agora::rtc::IRtcEngine::leaveChannel "leaveChannel".
298
+     - When the user has not joined the channel and still calls \ref agora::rtc::IRtcEngine::leaveChannel "leaveChannel" to leave the channel. In this case, no extra operation is needed.
299
+     */
300
+    ERR_LEAVE_CHANNEL_REJECTED = 18,
301
+    /** 19: Resources are occupied and cannot be reused.
302
+     */
303
+    ERR_ALREADY_IN_USE = 19,
304
+    /** 20: The SDK gives up the request due to too many requests.
305
+     */
306
+    ERR_ABORTED = 20,
307
+    /** 21: In Windows, specific firewall settings can cause the SDK to fail to initialize and crash.
308
+     */
309
+    ERR_INIT_NET_ENGINE = 21,
310
+    /** 22: The application uses too much of the system resources and the SDK fails to allocate the resources.
311
+     */
312
+    ERR_RESOURCE_LIMITED = 22,
313
+    /** 101: The specified App ID is invalid. Please try to rejoin the channel with a valid App ID.
314
+     */
315
+    ERR_INVALID_APP_ID = 101,
316
+    /** 102: The specified channel name is invalid. Please try to rejoin the channel with a valid channel name.
317
+     */
318
+    ERR_INVALID_CHANNEL_NAME = 102,
319
+    /** **DEPRECATED** 109: Deprecated as of v2.4.1. Use CONNECTION_CHANGED_TOKEN_EXPIRED(9) in the \ref agora::rtc::IRtcEngineEventHandler::onConnectionStateChanged "onConnectionStateChanged" callback instead.
320
+     
321
+     The token expired due to one of the following reasons:
322
+     
323
+     - Authorized Timestamp expired: The timestamp is represented by the number of seconds elapsed since 1/1/1970. The user can use the Token to access the Agora service within five minutes after the Token is generated. If the user does not access the Agora service after five minutes, this Token is no longer valid.
324
+     - Call Expiration Timestamp expired: The timestamp is the exact time when a user can no longer use the Agora service (for example, when a user is forced to leave an ongoing call). When a value is set for the Call Expiration Timestamp, it does not mean that the token will expire, but that the user will be banned from the channel.
325
+     */
326
+    ERR_TOKEN_EXPIRED = 109,
327
+    /** **DEPRECATED** 110: Deprecated as of v2.4.1. Use CONNECTION_CHANGED_INVALID_TOKEN(8) in the \ref agora::rtc::IRtcEngineEventHandler::onConnectionStateChanged "onConnectionStateChanged" callback instead.
328
+     
329
+     The token is invalid due to one of the following reasons:
330
+     
331
+     - The App Certificate for the project is enabled in Dashboard, but the user is still using the App ID. Once the App Certificate is enabled, the user must use a token.
332
+     - The uid is mandatory, and users must set the same uid as the one set in the \ref agora::rtc::IRtcEngine::joinChannel "joinChannel" method.
333
+     */
334
+    ERR_INVALID_TOKEN = 110,
335
+    /** 111: The internet connection is interrupted. This applies to the Agora Web SDK only.
336
+     */
337
+    ERR_CONNECTION_INTERRUPTED = 111, // only used in web sdk
338
+    /** 112: The internet connection is lost. This applies to the Agora Web SDK only.
339
+     */
340
+    ERR_CONNECTION_LOST = 112, // only used in web sdk
341
+    /** 113: The user is not in the channel when calling the \ref agora::rtc::IRtcEngine::sendStreamMessage "sendStreamMessage" or \ref agora::rtc::IRtcEngine::getUserInfoByUserAccount "getUserInfoByUserAccount" method.
342
+     */
343
+    ERR_NOT_IN_CHANNEL = 113,
344
+    /** 114: The size of the sent data is over 1024 bytes when the user calls the \ref agora::rtc::IRtcEngine::sendStreamMessage "sendStreamMessage" method.
345
+     */
346
+    ERR_SIZE_TOO_LARGE = 114,
347
+    /** 115: The bitrate of the sent data exceeds the limit of 6 Kbps when the user calls the \ref agora::rtc::IRtcEngine::sendStreamMessage "sendStreamMessage" method.
348
+     */
349
+    ERR_BITRATE_LIMIT = 115,
350
+    /** 116: Too many data streams (over 5 streams) are created when the user calls the \ref agora::rtc::IRtcEngine::createDataStream "createDataStream" method.
351
+     */
352
+    ERR_TOO_MANY_DATA_STREAMS = 116,
353
+    /** 117: The data stream transmission timed out.
354
+     */
355
+    ERR_STREAM_MESSAGE_TIMEOUT = 117,
356
+    /** 119: Switching roles fail. Please try to rejoin the channel.
357
+     */
358
+    ERR_SET_CLIENT_ROLE_NOT_AUTHORIZED = 119,
359
+    /** 120: Decryption fails. The user may have used a different encryption password to join the channel. Check your settings or try rejoining the channel.
360
+     */
361
+    ERR_DECRYPTION_FAILED = 120,
362
+    /** 123: The client is banned by the server.
363
+     */
364
+    ERR_CLIENT_IS_BANNED_BY_SERVER = 123,
365
+    /** 124: Incorrect watermark file parameter.
366
+     */
367
+    ERR_WATERMARK_PARAM = 124,
368
+    /** 125: Incorrect watermark file path.
369
+     */
370
+    ERR_WATERMARK_PATH = 125,
371
+    /** 126: Incorrect watermark file format.
372
+     */
373
+    ERR_WATERMARK_PNG = 126,
374
+    /** 127: Incorrect watermark file information.
375
+     */
376
+    ERR_WATERMARKR_INFO = 127,
377
+    /** 128: Incorrect watermark file data format.
378
+     */
379
+    ERR_WATERMARK_ARGB = 128,
380
+    /** 129: An error occurs in reading the watermark file.
381
+     */
382
+    ERR_WATERMARK_READ = 129,
383
+    /** 130: Encryption is enabled when the user calls the \ref agora::rtc::IRtcEngine::addPublishStreamUrl "addPublishStreamUrl" method (CDN live streaming does not support encrypted streams).
384
+     */
385
+    ERR_ENCRYPTED_STREAM_NOT_ALLOWED_PUBLISH = 130,
386
+    /** 134: The user account is invalid. */
387
+    ERR_INVALID_USER_ACCOUNT = 134,
388
+
389
+    /** 151: CDN related errors. Remove the original URL address and add a new one by calling the \ref agora::rtc::IRtcEngine::removePublishStreamUrl "removePublishStreamUrl" and \ref agora::rtc::IRtcEngine::addPublishStreamUrl "addPublishStreamUrl" methods.
390
+     */
391
+    ERR_PUBLISH_STREAM_CDN_ERROR = 151,
392
+    /** 152: The host publishes more than 10 URLs. Delete the unnecessary URLs before adding new ones.
393
+     */
394
+    ERR_PUBLISH_STREAM_NUM_REACH_LIMIT = 152,
395
+    /** 153: The host manipulates other hosts' URLs. Check your app logic.
396
+     */
397
+    ERR_PUBLISH_STREAM_NOT_AUTHORIZED = 153,
398
+    /** 154: An error occurs in Agora's streaming server. Call the addPublishStreamUrl method to publish the streaming again.
399
+     */
400
+    ERR_PUBLISH_STREAM_INTERNAL_SERVER_ERROR = 154,
401
+    /** 155: The server fails to find the stream.
402
+     */
403
+    ERR_PUBLISH_STREAM_NOT_FOUND = 155,
404
+    /** 156: The format of the RTMP stream URL is not supported. Check whether the URL format is correct.
405
+     */
406
+    ERR_PUBLISH_STREAM_FORMAT_NOT_SUPPORTED = 156,
407
+
408
+    //signaling: 400~600
409
+    /**
410
+    */
411
+    ERR_LOGOUT_OTHER = 400,  //
412
+    /** 401: The user logged out.
413
+     */
414
+    ERR_LOGOUT_USER = 401,  // logout by user
415
+    /** 402: Network failure.
416
+     */
417
+    ERR_LOGOUT_NET = 402,  // network failure
418
+    /** 403: Logged in another device.
419
+     */
420
+    ERR_LOGOUT_KICKED = 403,  // login in other device
421
+    /**
422
+     */
423
+    ERR_LOGOUT_PACKET = 404,  //
424
+    /** 405: The token expired.
425
+     */
426
+    ERR_LOGOUT_TOKEN_EXPIRED = 405,  // token expired
427
+    /**
428
+     */
429
+    ERR_LOGOUT_OLDVERSION = 406,  //
430
+    /**
431
+     */
432
+    ERR_LOGOUT_TOKEN_WRONG = 407,
433
+    /**
434
+    */
435
+    ERR_LOGOUT_ALREADY_LOGOUT = 408,
436
+    /**
437
+     */
438
+    ERR_LOGIN_OTHER = 420,
439
+    /**
440
+    */
441
+    ERR_LOGIN_NET = 421,
442
+    /**
443
+     */
444
+    ERR_LOGIN_FAILED = 422,
445
+    /**
446
+     */
447
+    ERR_LOGIN_CANCELED = 423,
448
+    /**
449
+     */
450
+    ERR_LOGIN_TOKEN_EXPIRED = 424,
451
+    /**
452
+     */
453
+    ERR_LOGIN_OLD_VERSION = 425,
454
+    /**
455
+     */
456
+    ERR_LOGIN_TOKEN_WRONG = 426,
457
+    /**
458
+     */
459
+    ERR_LOGIN_TOKEN_KICKED = 427,
460
+    /**
461
+     */
462
+    ERR_LOGIN_ALREADY_LOGIN = 428,
463
+    /**
464
+    */
465
+    ERR_JOIN_CHANNEL_OTHER = 440,
466
+    /**
467
+     */
468
+    ERR_SEND_MESSAGE_OTHER = 440,
469
+    /**
470
+     */
471
+    ERR_SEND_MESSAGE_TIMEOUT = 441,
472
+    /**
473
+     */
474
+    ERR_QUERY_USERNUM_OTHER = 450,
475
+    /**
476
+     */
477
+    ERR_QUERY_USERNUM_TIMEOUT = 451,
478
+    /**
479
+     */
480
+    ERR_QUERY_USERNUM_BYUSER = 452,
481
+    /**
482
+     */
483
+    ERR_LEAVE_CHANNEL_OTHER = 460,
484
+    /**
485
+     */
486
+    ERR_LEAVE_CHANNEL_KICKED = 461,
487
+    /**
488
+     */
489
+    ERR_LEAVE_CHANNEL_BYUSER = 462,
490
+    /**
491
+     */
492
+    ERR_LEAVE_CHANNEL_LOGOUT = 463,
493
+    /**
494
+     */
495
+    ERR_LEAVE_CHANNEL_DISCONNECTED = 464,
496
+    /**
497
+     */
498
+    ERR_INVITE_OTHER = 470,
499
+    /**
500
+     */
501
+    ERR_INVITE_REINVITE = 471,
502
+    /**
503
+     */
504
+    ERR_INVITE_NET = 472,
505
+    /**
506
+     */
507
+    ERR_INVITE_PEER_OFFLINE = 473,
508
+    ERR_INVITE_TIMEOUT = 474,
509
+    ERR_INVITE_CANT_RECV = 475,
510
+
511
+
512
+    //1001~2000
513
+    /** 1001: Fails to load the media engine.
514
+     */
515
+    ERR_LOAD_MEDIA_ENGINE = 1001,
516
+    /** 1002: Fails to start the call after enabling the media engine.
517
+     */
518
+    ERR_START_CALL = 1002,
519
+    /** **DEPRECATED** 1003: Fails to start the camera.
520
+     
521
+    Deprecated as of v2.4.1. Use LOCAL_VIDEO_STREAM_ERROR_CAPTURE_FAILURE(4) in the \ref agora::rtc::IRtcEngineEventHandler::onConnectionStateChanged "onConnectionStateChanged" callback instead.
522
+     */
523
+    ERR_START_CAMERA = 1003,
524
+    /** 1004: Fails to start the video rendering module.
525
+     */
526
+    ERR_START_VIDEO_RENDER = 1004,
527
+    /** 1005: A general error occurs in the Audio Device Module (no specified reason). Check if the audio device is used by another application, or try rejoining the channel.
528
+     */
529
+    ERR_ADM_GENERAL_ERROR = 1005,
530
+    /** 1006: Audio Device Module: An error occurs in using the Java resources.
531
+     */
532
+    ERR_ADM_JAVA_RESOURCE = 1006,
533
+    /** 1007: Audio Device Module: An error occurs in setting the sampling frequency.
534
+     */
535
+    ERR_ADM_SAMPLE_RATE = 1007,
536
+    /** 1008: Audio Device Module: An error occurs in initializing the playback device.
537
+     */
538
+    ERR_ADM_INIT_PLAYOUT = 1008,
539
+    /** 1009: Audio Device Module: An error occurs in starting the playback device.
540
+     */
541
+    ERR_ADM_START_PLAYOUT = 1009,
542
+    /** 1010: Audio Device Module: An error occurs in stopping the playback device.
543
+     */
544
+    ERR_ADM_STOP_PLAYOUT = 1010,
545
+    /** 1011: Audio Device Module: An error occurs in initializing the recording device.
546
+     */
547
+    ERR_ADM_INIT_RECORDING = 1011,
548
+    /** 1012: Audio Device Module: An error occurs in starting the recording device.
549
+     */
550
+    ERR_ADM_START_RECORDING = 1012,
551
+    /** 1013: Audio Device Module: An error occurs in stopping the recording device.
552
+     */
553
+    ERR_ADM_STOP_RECORDING = 1013,
554
+    /** 1015: Audio Device Module: A playback error occurs. Check your playback device and try rejoining the channel.
555
+     */
556
+    ERR_ADM_RUNTIME_PLAYOUT_ERROR = 1015,
557
+    /** 1017: Audio Device Module: A recording error occurs.
558
+     */
559
+    ERR_ADM_RUNTIME_RECORDING_ERROR = 1017,
560
+    /** 1018: Audio Device Module: Fails to record.
561
+     */
562
+    ERR_ADM_RECORD_AUDIO_FAILED = 1018,
563
+    /** 1022: Audio Device Module: An error occurs in initializing the 
564
+     * loopback device.
565
+     */
566
+    ERR_ADM_INIT_LOOPBACK = 1022,
567
+    /** 1023: Audio Device Module: An error occurs in starting the loopback 
568
+     * device.
569
+     */
570
+    ERR_ADM_START_LOOPBACK = 1023,
571
+    /** 1027: Audio Device Module: No recording permission exists. Check if the
572
+     *  recording permission is granted.
573
+     */
574
+    ERR_ADM_NO_PERMISSION = 1027,
575
+    /** 1033: Audio device module: The device is occupied. 
576
+    */
577
+    ERR_ADM_RECORD_AUDIO_IS_ACTIVE = 1033,
578
+    /** 1101: Audio device module: A fatal exception occurs.
579
+    */
580
+    ERR_ADM_ANDROID_JNI_JAVA_RESOURCE = 1101,
581
+    /** 1108: Audio device module: The recording frequency is lower than 50. 
582
+     * 0 indicates that the recording is not yet started. We recommend 
583
+     * checking your recording permission.
584
+    */
585
+    ERR_ADM_ANDROID_JNI_NO_RECORD_FREQUENCY = 1108,
586
+    /** 1109: The playback frequency is lower than 50. 0 indicates that the 
587
+     * playback is not yet started. We recommend checking if you have created 
588
+     * too many AudioTrack instances. 
589
+    */
590
+    ERR_ADM_ANDROID_JNI_NO_PLAYBACK_FREQUENCY = 1109,
591
+    /** 1111: Audio device module: AudioRecord fails to start up. A ROM system 
592
+     * error occurs. We recommend the following options to debug: 
593
+     * - Restart your App.
594
+     * - Restart your cellphone. 
595
+     * - Check your recording permission.
596
+     */
597
+    ERR_ADM_ANDROID_JNI_JAVA_START_RECORD = 1111,
598
+    /** 1112: Audio device module: AudioTrack fails to start up. A ROM system 
599
+     * error occurs. We recommend the following options to debug: 
600
+     * - Restart your App.
601
+     * - Restart your cellphone. 
602
+     * - Check your playback permission.
603
+    */
604
+    ERR_ADM_ANDROID_JNI_JAVA_START_PLAYBACK = 1112,
605
+    /** 1115: Audio device module: AudioRecord returns error. The SDK will 
606
+     * automatically restart AudioRecord. */
607
+    ERR_ADM_ANDROID_JNI_JAVA_RECORD_ERROR = 1115,
608
+    /** **DEPRECATED** */
609
+    ERR_ADM_ANDROID_OPENSL_CREATE_ENGINE = 1151,
610
+    /** **DEPRECATED** */
611
+    ERR_ADM_ANDROID_OPENSL_CREATE_AUDIO_RECORDER = 1153,
612
+    /** **DEPRECATED** */
613
+    ERR_ADM_ANDROID_OPENSL_START_RECORDER_THREAD = 1156,
614
+    /** **DEPRECATED** */
615
+    ERR_ADM_ANDROID_OPENSL_CREATE_AUDIO_PLAYER = 1157,
616
+    /** **DEPRECATED** */
617
+    ERR_ADM_ANDROID_OPENSL_START_PLAYER_THREAD = 1160,
618
+    /** 1201: Audio device module: The current device does not support audio 
619
+     * input, possibly because you have mistakenly configured the audio session
620
+     *  category, or because some other app is occupying the input device. We 
621
+     * recommend terminating all background apps and re-joining the channel. */
622
+    ERR_ADM_IOS_INPUT_NOT_AVAILABLE = 1201,
623
+    /** 1206: Audio device module: Cannot activate the Audio Session.*/
624
+    ERR_ADM_IOS_ACTIVATE_SESSION_FAIL = 1206,
625
+    /** 1210: Audio device module: Fails to initialize the audio device, 
626
+     * normally because the audio device parameters are wrongly set.*/
627
+    ERR_ADM_IOS_VPIO_INIT_FAIL = 1210,
628
+    /** 1213: Audio device module: Fails to re-initialize the audio device, 
629
+     * normally because the audio device parameters are wrongly set.*/
630
+    ERR_ADM_IOS_VPIO_REINIT_FAIL = 1213,
631
+    /** 1214: Fails to re-start up the Audio Unit, possibly because the audio 
632
+     * session category is not compatible with the settings of the Audio Unit.
633
+    */
634
+    ERR_ADM_IOS_VPIO_RESTART_FAIL = 1214,
635
+    ERR_ADM_IOS_SET_RENDER_CALLBACK_FAIL = 1219,
636
+    /** **DEPRECATED** */
637
+    ERR_ADM_IOS_SESSION_SAMPLERATR_ZERO = 1221,
638
+    /** 1301: Audio device module: An audio driver abnomality or a 
639
+     * compatibility issue occurs. Solutions: Disable and restart the audio 
640
+     * device, or reboot the system.*/
641
+    ERR_ADM_WIN_CORE_INIT = 1301,
642
+    /** 1303: Audio device module: A recording driver abnomality or a 
643
+     * compatibility issue occurs. Solutions: Disable and restart the audio 
644
+     * device, or reboot the system. */
645
+    ERR_ADM_WIN_CORE_INIT_RECORDING = 1303,
646
+    /** 1306: Audio device module: A playout driver abnomality or a 
647
+     * compatibility issue occurs. Solutions: Disable and restart the audio 
648
+     * device, or reboot the system. */
649
+    ERR_ADM_WIN_CORE_INIT_PLAYOUT = 1306,
650
+    /** 1307: Audio device module: No audio device is available. Solutions: 
651
+     * Plug in a proper audio device. */
652
+    ERR_ADM_WIN_CORE_INIT_PLAYOUT_NULL = 1307,
653
+    /** 1309: Audio device module: An audio driver abnomality or a 
654
+     * compatibility issue occurs. Solutions: Disable and restart the audio 
655
+     * device, or reboot the system. */
656
+    ERR_ADM_WIN_CORE_START_RECORDING = 1309,
657
+    /** 1311: Audio device module: Insufficient system memory or poor device 
658
+     * performance. Solutions: Reboot the system or replace the device.
659
+    */
660
+    ERR_ADM_WIN_CORE_CREATE_REC_THREAD = 1311,
661
+    /** 1314: Audio device module: An audio driver abnormality occurs. 
662
+     * Solutions:
663
+     * - Disable and then re-enable the audio device.
664
+     * - Reboot the system.
665
+     * - Upgrade your audio card driver.*/
666
+    ERR_ADM_WIN_CORE_CAPTURE_NOT_STARTUP = 1314,
667
+    /** 1319: Audio device module: Insufficient system memory or poor device 
668
+     * performance. Solutions: Reboot the system or replace the device. */
669
+    ERR_ADM_WIN_CORE_CREATE_RENDER_THREAD = 1319,
670
+    /** 1320: Audio device module: An audio driver abnormality occurs. 
671
+     * Solutions:
672
+     * - Disable and then re-enable the audio device.
673
+     * - Reboot the system.
674
+     * - Replace the device. */
675
+    ERR_ADM_WIN_CORE_RENDER_NOT_STARTUP = 1320,
676
+    /** 1322: Audio device module: No audio sampling device is available. 
677
+     * Solutions: Plug in a proper recording device. */
678
+    ERR_ADM_WIN_CORE_NO_RECORDING_DEVICE = 1322,
679
+    /** 1323: Audio device module: No audio playout device is available. 
680
+     * Solutions: Plug in a proper playback device.*/
681
+    ERR_ADM_WIN_CORE_NO_PLAYOUT_DEVICE = 1323,
682
+    /** 1351: Audio device module: An audio driver abnormality or a 
683
+     * compatibility issue occurs. Solutions:
684
+     * - Disable and then re-enable the audio device.
685
+     * - Reboot the system.
686
+     * - Upgrade your audio card driver. */
687
+    ERR_ADM_WIN_WAVE_INIT = 1351,
688
+    /** 1353: Audio device module: An audio driver abnormality occurs. 
689
+     * Solutions:
690
+     * - Disable and then re-enable the audio device.
691
+     * - Reboot the system.
692
+     * - Upgrade your audio card driver. */
693
+    ERR_ADM_WIN_WAVE_INIT_RECORDING = 1353,
694
+    /** 1354: Audio device module: An audio driver abnormality occurs. 
695
+     * Solutions:
696
+     * - Disable and then re-enable the audio device.
697
+     * - Reboot the system.
698
+     * - Upgrade your audio card driver. */
699
+    ERR_ADM_WIN_WAVE_INIT_MICROPHONE = 1354,
700
+    /** 1355: Audio device module: An audio driver abnormality occurs. 
701
+     * Solutions:
702
+     * - Disable and then re-enable the audio device.
703
+     * - Reboot the system.
704
+     * - Upgrade your audio card driver. */
705
+    ERR_ADM_WIN_WAVE_INIT_PLAYOUT = 1355,
706
+    /** 1356: Audio device module: An audio driver abnormality occurs. 
707
+     * Solutions:
708
+     * - Disable and then re-enable the audio device.
709
+     * - Reboot the system.
710
+     * - Upgrade your audio card driver. */
711
+    ERR_ADM_WIN_WAVE_INIT_SPEAKER = 1356,
712
+    /** 1357: Audio device module: An audio driver abnormality occurs. 
713
+     * Solutions:
714
+     * - Disable and then re-enable the audio device.
715
+     * - Reboot the system.
716
+     * - Upgrade your audio card driver. */
717
+    ERR_ADM_WIN_WAVE_START_RECORDING = 1357,
718
+    /** 1358: Audio device module: An audio driver abnormality occurs. 
719
+     * Solutions:
720
+     * - Disable and then re-enable the audio device.
721
+     * - Reboot the system.
722
+     * - Upgrade your audio card driver.*/
723
+    ERR_ADM_WIN_WAVE_START_PLAYOUT = 1358,
724
+    /** 1359: Audio Device Module: No recording device exists.
725
+     */
726
+    ERR_ADM_NO_RECORDING_DEVICE = 1359,
727
+    /** 1360: Audio Device Module: No playback device exists.
728
+     */
729
+    ERR_ADM_NO_PLAYOUT_DEVICE = 1360,
730
+
731
+    // VDM error code starts from 1500
732
+    /** 1501: Video Device Module: The camera is unauthorized.
733
+     */
734
+    ERR_VDM_CAMERA_NOT_AUTHORIZED = 1501,
735
+
736
+	// VDM error code starts from 1500
737
+	/** **DEPRECATED** 1502: Video Device Module: The camera in use.
738
+     
739
+     Deprecated as of v2.4.1. Use LOCAL_VIDEO_STREAM_ERROR_DEVICE_BUSY(3) in the \ref agora::rtc::IRtcEngineEventHandler::onConnectionStateChanged "onConnectionStateChanged" callback instead.
740
+	 */
741
+	ERR_VDM_WIN_DEVICE_IN_USE = 1502,
742
+
743
+    // VCM error code starts from 1600
744
+    /** 1600: Video Device Module: An unknown error occurs.
745
+     */
746
+    ERR_VCM_UNKNOWN_ERROR = 1600,
747
+    /** 1601: Video Device Module: An error occurs in initializing the video encoder.
748
+    */
749
+    ERR_VCM_ENCODER_INIT_ERROR = 1601,
750
+    /** 1602: Video Device Module: An error occurs in encoding.
751
+     */
752
+    ERR_VCM_ENCODER_ENCODE_ERROR = 1602,
753
+    /** 1603: Video Device Module: An error occurs in setting the video encoder.
754
+     */
755
+    ERR_VCM_ENCODER_SET_ERROR = 1603,
756
+};
757
+
758
+    /** Output log filter level. */
759
+enum LOG_FILTER_TYPE
760
+{
761
+/** 0: Do not output any log information. */
762
+    LOG_FILTER_OFF = 0,
763
+     /** 0x080f: Output all log information.
764
+      Set your log filter as debug if you want to get the most complete log file.      */
765
+    LOG_FILTER_DEBUG = 0x080f,
766
+     /** 0x000f: Output CRITICAL, ERROR, WARNING, and INFO level log information.
767
+      We recommend setting your log filter as this level.
768
+      */
769
+    LOG_FILTER_INFO = 0x000f,
770
+     /** 0x000e: Outputs CRITICAL, ERROR, and WARNING level log information.
771
+      */
772
+    LOG_FILTER_WARN = 0x000e,
773
+     /** 0x000c: Outputs CRITICAL and ERROR level log information. */
774
+    LOG_FILTER_ERROR = 0x000c,
775
+     /** 0x0008: Outputs CRITICAL level log information. */
776
+    LOG_FILTER_CRITICAL = 0x0008,
777
+    LOG_FILTER_MASK = 0x80f,
778
+};
779
+} // namespace agora
780
+
781
+#endif

+ 215
- 0
android/src/main/cpp/include/IAgoraMediaEngine.h View File

1
+#ifndef AGORA_MEDIA_ENGINE_H
2
+#define AGORA_MEDIA_ENGINE_H
3
+#if defined _WIN32 || defined __CYGWIN__
4
+typedef __int64 int64_t;
5
+typedef unsigned __int64 uint64_t;
6
+#else
7
+#include <stdint.h>
8
+#endif
9
+
10
+namespace agora
11
+{
12
+namespace media
13
+{
14
+
15
+enum MEDIA_SOURCE_TYPE {
16
+    AUDIO_PLAYOUT_SOURCE = 0,
17
+    AUDIO_RECORDING_SOURCE = 1,
18
+};
19
+
20
+class IAudioFrameObserver
21
+{
22
+public:
23
+  enum AUDIO_FRAME_TYPE {
24
+    FRAME_TYPE_PCM16 = 0,  //PCM 16bit little endian
25
+  };
26
+  struct AudioFrame {
27
+    AUDIO_FRAME_TYPE type;
28
+    int samples;  //number of samples in this frame
29
+    int bytesPerSample;  //number of bytes per sample: 2 for PCM16
30
+    int channels;  //number of channels (data are interleaved if stereo)
31
+    int samplesPerSec;  //sampling rate
32
+    void* buffer;  //data buffer
33
+    int64_t renderTimeMs;
34
+    int avsync_type;
35
+  };
36
+public:
37
+  virtual bool onRecordAudioFrame(AudioFrame& audioFrame) = 0;
38
+  virtual bool onPlaybackAudioFrame(AudioFrame& audioFrame) = 0;
39
+  virtual bool onMixedAudioFrame(AudioFrame& audioFrame) = 0;
40
+  virtual bool onPlaybackAudioFrameBeforeMixing(unsigned int uid, AudioFrame& audioFrame) = 0;
41
+};
42
+
43
+class IVideoFrameObserver
44
+{
45
+public:
46
+  enum VIDEO_FRAME_TYPE {
47
+    FRAME_TYPE_YUV420 = 0,  //YUV 420 format
48
+  };
49
+  struct VideoFrame {
50
+    VIDEO_FRAME_TYPE type;
51
+    int width;  //width of video frame
52
+    int height;  //height of video frame
53
+    int yStride;  //stride of Y data buffer
54
+    int uStride;  //stride of U data buffer
55
+    int vStride;  //stride of V data buffer
56
+    void* yBuffer;  //Y data buffer
57
+    void* uBuffer;  //U data buffer
58
+    void* vBuffer;  //V data buffer
59
+    int rotation; // rotation of this frame (0, 90, 180, 270)
60
+    int64_t renderTimeMs;
61
+    int avsync_type;
62
+  };
63
+public:
64
+  virtual bool onCaptureVideoFrame(VideoFrame& videoFrame) = 0;
65
+  virtual bool onRenderVideoFrame(unsigned int uid, VideoFrame& videoFrame) = 0;
66
+};
67
+
68
+class IVideoFrame
69
+{
70
+public:
71
+  enum PLANE_TYPE {
72
+    Y_PLANE = 0,
73
+    U_PLANE = 1,
74
+    V_PLANE = 2,
75
+    NUM_OF_PLANES = 3
76
+  };
77
+  enum VIDEO_TYPE {
78
+    VIDEO_TYPE_UNKNOWN = 0,
79
+    VIDEO_TYPE_I420 = 1,
80
+    VIDEO_TYPE_IYUV = 2,
81
+    VIDEO_TYPE_RGB24 = 3,
82
+    VIDEO_TYPE_ABGR = 4,
83
+    VIDEO_TYPE_ARGB = 5,
84
+    VIDEO_TYPE_ARGB4444 = 6,
85
+    VIDEO_TYPE_RGB565 = 7,
86
+    VIDEO_TYPE_ARGB1555 = 8,
87
+    VIDEO_TYPE_YUY2 = 9,
88
+    VIDEO_TYPE_YV12 = 10,
89
+    VIDEO_TYPE_UYVY = 11,
90
+    VIDEO_TYPE_MJPG = 12,
91
+    VIDEO_TYPE_NV21 = 13,
92
+    VIDEO_TYPE_NV12 = 14,
93
+    VIDEO_TYPE_BGRA = 15,
94
+    VIDEO_TYPE_RGBA = 16,
95
+  };
96
+  virtual void release() = 0;
97
+  virtual const unsigned char* buffer(PLANE_TYPE type) const = 0;
98
+
99
+  // Copy frame: If required size is bigger than allocated one, new buffers of
100
+  // adequate size will be allocated.
101
+  // Return value: 0 on success ,-1 on error.
102
+  virtual int copyFrame(IVideoFrame** dest_frame) const = 0;
103
+
104
+  // Convert frame
105
+  // Input:
106
+  //   - src_frame        : Reference to a source frame.
107
+  //   - dst_video_type   : Type of output video.
108
+  //   - dst_sample_size  : Required only for the parsing of MJPG.
109
+  //   - dst_frame        : Pointer to a destination frame.
110
+  // Return value: 0 if OK, < 0 otherwise.
111
+  // It is assumed that source and destination have equal height.
112
+  virtual int convertFrame(VIDEO_TYPE dst_video_type, int dst_sample_size, unsigned char* dst_frame) const = 0;
113
+
114
+  // Get allocated size per plane.
115
+  virtual int allocated_size(PLANE_TYPE type) const = 0;
116
+
117
+  // Get allocated stride per plane.
118
+  virtual int stride(PLANE_TYPE type) const = 0;
119
+
120
+  // Get frame width.
121
+  virtual int width() const = 0;
122
+
123
+  // Get frame height.
124
+  virtual int height() const = 0;
125
+
126
+  // Get frame timestamp (90kHz).
127
+  virtual unsigned int timestamp() const = 0;
128
+
129
+  // Get render time in milliseconds.
130
+  virtual int64_t render_time_ms() const = 0;
131
+
132
+  // Return true if underlying plane buffers are of zero size, false if not.
133
+  virtual bool IsZeroSize() const = 0;
134
+};
135
+
136
+class IExternalVideoRenderCallback
137
+{
138
+public:
139
+  virtual void onViewSizeChanged(int width, int height) = 0;
140
+  virtual void onViewDestroyed() = 0;
141
+};
142
+
143
+struct ExternalVideoRenerContext
144
+{
145
+  IExternalVideoRenderCallback* renderCallback;
146
+  void* view;
147
+  int renderMode;
148
+  int zOrder;
149
+  float left;
150
+  float top;
151
+  float right;
152
+  float bottom;
153
+};
154
+
155
+class IExternalVideoRender
156
+{
157
+public:
158
+  virtual void release() = 0;
159
+  virtual int initialize() = 0;
160
+  virtual int deliverFrame(const IVideoFrame& videoFrame, int rotation, bool mirrored) = 0;
161
+};
162
+
163
+class IExternalVideoRenderFactory
164
+{
165
+public:
166
+  virtual IExternalVideoRender* createRenderInstance(const ExternalVideoRenerContext& context) = 0;
167
+};
168
+
169
+struct ExternalVideoFrame
170
+{
171
+  enum VIDEO_BUFFER_TYPE
172
+  {
173
+    VIDEO_BUFFER_RAW_DATA = 1,
174
+  };
175
+
176
+  enum VIDEO_PIXEL_FORMAT
177
+  {
178
+    VIDEO_PIXEL_UNKNOWN = 0,
179
+    VIDEO_PIXEL_I420 = 1,
180
+    VIDEO_PIXEL_BGRA = 2,
181
+    VIDEO_PIXEL_NV12 = 8,
182
+  };
183
+
184
+  VIDEO_BUFFER_TYPE type;
185
+  VIDEO_PIXEL_FORMAT format;
186
+  void* buffer;
187
+  int stride;
188
+  int height;
189
+  int cropLeft;
190
+  int cropTop;
191
+  int cropRight;
192
+  int cropBottom;
193
+  int rotation;
194
+  long long timestamp;
195
+};
196
+
197
+class IMediaEngine {
198
+public:
199
+  virtual void release() = 0;
200
+  virtual int registerAudioFrameObserver(IAudioFrameObserver* observer) = 0;
201
+  virtual int registerVideoFrameObserver(IVideoFrameObserver* observer) = 0;
202
+  virtual int registerVideoRenderFactory(IExternalVideoRenderFactory* factory) = 0;
203
+  virtual int pushAudioFrame(MEDIA_SOURCE_TYPE type, IAudioFrameObserver::AudioFrame *frame, bool wrap) = 0;
204
+  virtual int pushAudioFrame(IAudioFrameObserver::AudioFrame *frame) = 0;
205
+  virtual int pullAudioFrame(IAudioFrameObserver::AudioFrame *frame) = 0;
206
+
207
+  virtual int setExternalVideoSource(bool enable, bool useTexture) = 0;
208
+  virtual int pushVideoFrame(ExternalVideoFrame *frame) = 0;
209
+};
210
+
211
+} //media
212
+
213
+} //agora
214
+
215
+#endif //AGORA_MEDIA_ENGINE_H

+ 7473
- 0
android/src/main/cpp/include/IAgoraRtcEngine.h
File diff suppressed because it is too large
View File


+ 76
- 0
android/src/main/cpp/include/IAgoraService.h View File

1
+//  Agora SDK
2
+//
3
+//  Copyright (c) 2019 Agora.io. All rights reserved.
4
+//
5
+
6
+#ifndef AGORA_SERVICE_H
7
+#define AGORA_SERVICE_H
8
+#include "AgoraBase.h"
9
+
10
+namespace agora {
11
+    namespace rtc {
12
+        class IRtcEngine;
13
+    }
14
+    namespace rtm {
15
+        class IRtmService;
16
+    }
17
+namespace base {
18
+
19
+struct AgoraServiceContext
20
+{
21
+};
22
+
23
+
24
+class IAgoraService
25
+{
26
+protected:
27
+    virtual ~IAgoraService(){}
28
+public:
29
+    virtual void release() = 0;
30
+
31
+	/** Initializes the engine.
32
+     
33
+    @param context RtcEngine context.
34
+    @return
35
+     - 0: Success.
36
+     - < 0: Failure.
37
+    */
38
+    virtual int initialize(const AgoraServiceContext& context) = 0;
39
+
40
+    /** Retrieves the SDK version number.
41
+    * @param build Build number.
42
+    * @return The current SDK version in the string format. For example, 2.4.0
43
+    */
44
+    virtual const char* getVersion(int* build) = 0;
45
+
46
+    virtual rtm::IRtmService* createRtmService() = 0;
47
+};
48
+
49
+} //namespace base
50
+} // namespace agora
51
+
52
+/** Gets the SDK version number.
53
+ 
54
+ @param build Build number of the Agora SDK.
55
+ @return
56
+ - 0: Success.
57
+ - < 0: Failure.
58
+*/
59
+AGORA_API const char* AGORA_CALL getAgoraSdkVersion(int* build);
60
+
61
+/**
62
+* Creates the RtcEngine object and returns the pointer.
63
+* @param err Error code
64
+* @return returns Description of the error code
65
+*/
66
+AGORA_API const char* AGORA_CALL getAgoraSdkErrorDescription(int err);
67
+
68
+/**
69
+* Creates the Agora Service object and returns the pointer.
70
+* @return returns Pointer of the Agora Service object
71
+*/
72
+AGORA_API agora::base::IAgoraService* AGORA_CALL createAgoraService();
73
+
74
+AGORA_API int AGORA_CALL setAgoraSdkExternalSymbolLoader(void* (*func)(const char* symname));
75
+
76
+#endif

+ 53
- 0
android/src/main/cpp/include/VMUtil.h View File

1
+#ifndef __VM_UTIL_H__
2
+#define __VM_UTIL_H__
3
+
4
+#include <jni.h>
5
+#include <stddef.h>
6
+
7
+#include <assert.h>
8
+
9
+#include <pthread.h>
10
+#include <android/log.h>
11
+
12
+#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "AG_EX_AV", __VA_ARGS__)
13
+#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "AG_EX_AV", __VA_ARGS__)
14
+#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "AG_EX_AV", __VA_ARGS__)
15
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "AG_EX_AV", __VA_ARGS__)
16
+
17
+#define TRUE true
18
+#define FALSE false
19
+
20
+#define CHECK_POINTER(pValue, rValue, ...) 	if (NULL == pValue) {  \
21
+					                           LOGE(__VA_ARGS__); \
22
+					                           return rValue; }
23
+
24
+class AttachThreadScoped
25
+{
26
+public:
27
+    explicit AttachThreadScoped(JavaVM* jvm)
28
+        : attached_(false), jvm_(jvm), env_(nullptr) {
29
+        jint ret_val = jvm->GetEnv(reinterpret_cast<void**>(&env_),
30
+            JNI_VERSION_1_6);
31
+        if (ret_val == JNI_EDETACHED) {
32
+            // Attach the thread to the Java VM.
33
+            ret_val = jvm_->AttachCurrentThread(&env_, nullptr);
34
+            attached_ = ret_val >= 0;
35
+            assert(attached_);
36
+        }
37
+	}
38
+
39
+    ~AttachThreadScoped() {
40
+        if (attached_ && (jvm_->DetachCurrentThread() < 0)) {
41
+            assert(false);
42
+        }
43
+    }
44
+
45
+    JNIEnv* env() { return env_; }
46
+
47
+private:
48
+    bool attached_;
49
+    JavaVM* jvm_;
50
+    JNIEnv* env_;
51
+};
52
+
53
+#endif  // __VM_UTIL_H__

+ 327
- 0
android/src/main/cpp/src/agora_media_pre_processing.cpp View File

1
+//
2
+// Created by LY on 2019-08-21.
3
+//
4
+
5
+#include <jni.h>
6
+#include <android/log.h>
7
+#include <cstring>
8
+#include "../include/IAgoraMediaEngine.h"
9
+
10
+#include "../include/IAgoraRtcEngine.h"
11
+#include <string.h>
12
+#include "agora_media_pre_processing.h"
13
+#include "../include/VMUtil.h"
14
+
15
+#include <map>
16
+
17
+using namespace std;
18
+
19
+jobject gCallBack = nullptr;
20
+jclass gCallbackClass = nullptr;
21
+jmethodID recordAudioMethodId = nullptr;
22
+jmethodID playbackAudioMethodId = nullptr;
23
+jmethodID playBeforeMixAudioMethodId = nullptr;
24
+jmethodID mixAudioMethodId = nullptr;
25
+jmethodID captureVideoMethodId = nullptr;
26
+jmethodID renderVideoMethodId = nullptr;
27
+void *_javaDirectPlayBufferCapture = nullptr;
28
+void *_javaDirectPlayBufferRecordAudio = nullptr;
29
+void *_javaDirectPlayBufferPlayAudio = nullptr;
30
+void *_javaDirectPlayBufferBeforeMixAudio = nullptr;
31
+void *_javaDirectPlayBufferMixAudio = nullptr;
32
+map<int, void *> decodeBufferMap;
33
+
34
+static JavaVM *gJVM = nullptr;
35
+
36
+class AgoraVideoFrameObserver : public agora::media::IVideoFrameObserver {
37
+
38
+public:
39
+    AgoraVideoFrameObserver() {
40
+
41
+    }
42
+
43
+    ~AgoraVideoFrameObserver() {
44
+
45
+    }
46
+
47
+    void
48
+    getVideoFrame(VideoFrame &videoFrame, _jmethodID *jmethodID, void *_byteBufferObject, unsigned int uid) {
49
+
50
+        if (_byteBufferObject) {
51
+            int width = videoFrame.width;
52
+            int height = videoFrame.height;
53
+            size_t widthAndHeight = (size_t) videoFrame.yStride * height;
54
+            size_t length = widthAndHeight * 3 / 2;
55
+
56
+            AttachThreadScoped ats(gJVM);
57
+            JNIEnv *env = ats.env();
58
+
59
+            memcpy(_byteBufferObject, videoFrame.yBuffer, widthAndHeight);
60
+            memcpy((uint8_t *) _byteBufferObject + widthAndHeight, videoFrame.uBuffer,
61
+                   widthAndHeight / 4);
62
+            memcpy((uint8_t *) _byteBufferObject + widthAndHeight * 5 / 4, videoFrame.vBuffer,
63
+                   widthAndHeight / 4);
64
+
65
+            if (uid == 0) {
66
+                env->CallVoidMethod(gCallBack, jmethodID, videoFrame.type, width, height, length,
67
+                                    videoFrame.yStride, videoFrame.uStride,
68
+                                    videoFrame.vStride, videoFrame.rotation,
69
+                                    videoFrame.renderTimeMs);
70
+            } else {
71
+                env->CallVoidMethod(gCallBack, jmethodID, uid, videoFrame.type, width, height,
72
+                                    length,
73
+                                    videoFrame.yStride, videoFrame.uStride,
74
+                                    videoFrame.vStride, videoFrame.rotation,
75
+                                    videoFrame.renderTimeMs);
76
+            }
77
+        }
78
+
79
+    }
80
+
81
+    void writebackVideoFrame(VideoFrame &videoFrame, void *byteBuffer) {
82
+        if (byteBuffer == nullptr) {
83
+            return;
84
+        }
85
+
86
+        int width = videoFrame.width;
87
+        int height = videoFrame.height;
88
+        size_t widthAndHeight = (size_t) videoFrame.yStride * height;
89
+
90
+        memcpy(videoFrame.yBuffer, byteBuffer, widthAndHeight);
91
+        memcpy(videoFrame.uBuffer, (uint8_t *) byteBuffer + widthAndHeight, widthAndHeight / 4);
92
+        memcpy(videoFrame.vBuffer, (uint8_t *) byteBuffer + widthAndHeight * 5 / 4,
93
+               widthAndHeight / 4);
94
+    }
95
+
96
+public:
97
+    virtual bool onCaptureVideoFrame(VideoFrame &videoFrame) override {
98
+        getVideoFrame(videoFrame, captureVideoMethodId, _javaDirectPlayBufferCapture, 0);
99
+        writebackVideoFrame(videoFrame, _javaDirectPlayBufferCapture);
100
+        return true;
101
+    }
102
+
103
+    virtual bool onRenderVideoFrame(unsigned int uid, VideoFrame &videoFrame) override {
104
+        map<int, void *>::iterator it_find;
105
+        it_find = decodeBufferMap.find(uid);
106
+
107
+        if (it_find != decodeBufferMap.end()) {
108
+            if (it_find->second != nullptr) {
109
+                getVideoFrame(videoFrame, renderVideoMethodId, it_find->second, uid);
110
+                writebackVideoFrame(videoFrame, it_find->second);
111
+            }
112
+        }
113
+
114
+        return true;
115
+    }
116
+
117
+};
118
+
119
+
120
+class AgoraAudioFrameObserver : public agora::media::IAudioFrameObserver {
121
+
122
+public:
123
+    AgoraAudioFrameObserver() {
124
+        gCallBack = nullptr;
125
+    }
126
+
127
+    ~AgoraAudioFrameObserver() {
128
+    }
129
+
130
+    void getAudioFrame(AudioFrame &audioFrame, _jmethodID *jmethodID, void *_byteBufferObject, unsigned int uid) {
131
+        if (_byteBufferObject) {
132
+            AttachThreadScoped ats(gJVM);
133
+            JNIEnv *env = ats.env();
134
+            if (env == nullptr) {
135
+                return;
136
+            }
137
+            int len = audioFrame.samples * audioFrame.bytesPerSample;
138
+            memcpy(_byteBufferObject, audioFrame.buffer, (size_t) len); // * sizeof(int16_t)
139
+
140
+            if (uid == 0) {
141
+                env->CallVoidMethod(gCallBack, jmethodID, audioFrame.type, audioFrame.samples,
142
+                                    audioFrame.bytesPerSample,
143
+                                    audioFrame.channels, audioFrame.samplesPerSec,
144
+                                    audioFrame.renderTimeMs, len);
145
+            } else {
146
+                env->CallVoidMethod(gCallBack, jmethodID, uid, audioFrame.type, audioFrame.samples,
147
+                                    audioFrame.bytesPerSample,
148
+                                    audioFrame.channels, audioFrame.samplesPerSec,
149
+                                    audioFrame.renderTimeMs, len);
150
+            }
151
+        }
152
+
153
+    }
154
+
155
+    void writebackAudioFrame(AudioFrame &audioFrame, void *byteBuffer) {
156
+        if (byteBuffer == nullptr) {
157
+            return;
158
+        }
159
+
160
+        int len = audioFrame.samples * audioFrame.bytesPerSample;
161
+        memcpy(audioFrame.buffer, byteBuffer, (size_t) len);
162
+    }
163
+
164
+public:
165
+    virtual bool onRecordAudioFrame(AudioFrame &audioFrame) override {
166
+        getAudioFrame(audioFrame, recordAudioMethodId, _javaDirectPlayBufferRecordAudio, 0);
167
+        writebackAudioFrame(audioFrame, _javaDirectPlayBufferRecordAudio);
168
+        return true;
169
+    }
170
+
171
+    virtual bool onPlaybackAudioFrame(AudioFrame &audioFrame) override {
172
+        getAudioFrame(audioFrame, playbackAudioMethodId, _javaDirectPlayBufferPlayAudio, 0);
173
+        writebackAudioFrame(audioFrame, _javaDirectPlayBufferPlayAudio);
174
+        return true;
175
+    }
176
+
177
+    virtual bool
178
+    onPlaybackAudioFrameBeforeMixing(unsigned int uid, AudioFrame &audioFrame) override {
179
+        getAudioFrame(audioFrame, playBeforeMixAudioMethodId, _javaDirectPlayBufferBeforeMixAudio, uid);
180
+        writebackAudioFrame(audioFrame, _javaDirectPlayBufferBeforeMixAudio);
181
+        return true;
182
+    }
183
+
184
+    virtual bool onMixedAudioFrame(AudioFrame &audioFrame) override {
185
+        getAudioFrame(audioFrame, mixAudioMethodId, _javaDirectPlayBufferMixAudio, 0);
186
+        writebackAudioFrame(audioFrame, _javaDirectPlayBufferMixAudio);
187
+        return true;
188
+    }
189
+};
190
+
191
+
192
+static AgoraAudioFrameObserver s_audioFrameObserver;
193
+
194
+static AgoraVideoFrameObserver s_videoFrameObserver;
195
+static agora::rtc::IRtcEngine *rtcEngine = nullptr;
196
+
197
+#ifdef __cplusplus
198
+extern "C" {
199
+#endif
200
+
201
+int __attribute__((visibility("default")))
202
+loadAgoraRtcEnginePlugin(agora::rtc::IRtcEngine *engine) {
203
+    __android_log_print(ANDROID_LOG_DEBUG, "agora-raw-data-plugin", "loadAgoraRtcEnginePlugin");
204
+    rtcEngine = engine;
205
+    return 0;
206
+}
207
+
208
+void __attribute__((visibility("default")))
209
+unloadAgoraRtcEnginePlugin(agora::rtc::IRtcEngine *engine) {
210
+    __android_log_print(ANDROID_LOG_DEBUG, "agora-raw-data-plugin", "unloadAgoraRtcEnginePlugin");
211
+
212
+    rtcEngine = nullptr;
213
+}
214
+
215
+JNIEXPORT void JNICALL
216
+Java_com_syan_agora_media_MediaPreProcessing_setCallback(JNIEnv *env, jclass obj,
217
+                                                                jobject callback) {
218
+    if (!rtcEngine) return;
219
+
220
+    env->GetJavaVM(&gJVM);
221
+
222
+    agora::util::AutoPtr<agora::media::IMediaEngine> mediaEngine;
223
+    mediaEngine.queryInterface(rtcEngine, agora::INTERFACE_ID_TYPE::AGORA_IID_MEDIA_ENGINE);
224
+    if (mediaEngine) {
225
+        mediaEngine->registerVideoFrameObserver(&s_videoFrameObserver);
226
+        mediaEngine->registerAudioFrameObserver(&s_audioFrameObserver);
227
+    }
228
+
229
+    if (gCallBack == nullptr) {
230
+        gCallBack = env->NewGlobalRef(callback);
231
+        gCallbackClass = env->GetObjectClass(gCallBack);
232
+
233
+        recordAudioMethodId = env->GetMethodID(gCallbackClass, "onRecordAudioFrame", "(IIIIIJI)V");
234
+        playbackAudioMethodId = env->GetMethodID(gCallbackClass, "onPlaybackAudioFrame",
235
+                                                 "(IIIIIJI)V");
236
+        playBeforeMixAudioMethodId = env->GetMethodID(gCallbackClass,
237
+                                                      "onPlaybackAudioFrameBeforeMixing",
238
+                                                      "(IIIIIIJI)V");
239
+        mixAudioMethodId = env->GetMethodID(gCallbackClass, "onMixedAudioFrame", "(IIIIIJI)V");
240
+
241
+        captureVideoMethodId = env->GetMethodID(gCallbackClass, "onCaptureVideoFrame",
242
+                                                "(IIIIIIIIJ)V");
243
+        renderVideoMethodId = env->GetMethodID(gCallbackClass, "onRenderVideoFrame",
244
+                                               "(IIIIIIIIIJ)V");
245
+
246
+        __android_log_print(ANDROID_LOG_DEBUG, "setCallback", "setCallback done successfully");
247
+    }
248
+}
249
+
250
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_setVideoCaptureByteBuffer
251
+        (JNIEnv *env, jclass obj, jobject bytebuffer) {
252
+    _javaDirectPlayBufferCapture = env->GetDirectBufferAddress(bytebuffer);
253
+}
254
+
255
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_setAudioRecordByteBuffer
256
+        (JNIEnv *env, jclass obj, jobject bytebuffer) {
257
+    _javaDirectPlayBufferRecordAudio = env->GetDirectBufferAddress(bytebuffer);
258
+}
259
+
260
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_setAudioPlayByteBuffer
261
+        (JNIEnv *env, jclass obj, jobject bytebuffer) {
262
+    _javaDirectPlayBufferPlayAudio = env->GetDirectBufferAddress(bytebuffer);
263
+}
264
+
265
+JNIEXPORT void JNICALL
266
+Java_com_syan_agora_media_MediaPreProcessing_setBeforeAudioMixByteBuffer
267
+        (JNIEnv *env, jclass obj, jobject bytebuffer) {
268
+    _javaDirectPlayBufferBeforeMixAudio = env->GetDirectBufferAddress(bytebuffer);
269
+}
270
+
271
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_setAudioMixByteBuffer
272
+        (JNIEnv *env, jclass obj, jobject bytebuffer) {
273
+    _javaDirectPlayBufferMixAudio = env->GetDirectBufferAddress(bytebuffer);
274
+}
275
+
276
+JNIEXPORT void JNICALL
277
+Java_com_syan_agora_media_MediaPreProcessing_setVideoDecodeByteBuffer(JNIEnv *env,
278
+                                                                             jclass type,
279
+                                                                             jint uid,
280
+                                                                             jobject byteBuffer) {
281
+    if (byteBuffer == nullptr) {
282
+        decodeBufferMap.erase(uid);
283
+    } else {
284
+        void *_javaDirectDecodeBuffer = env->GetDirectBufferAddress(byteBuffer);
285
+        decodeBufferMap.insert(make_pair(uid, _javaDirectDecodeBuffer));
286
+        __android_log_print(ANDROID_LOG_DEBUG, "agora-raw-data-plugin",
287
+                            "setVideoDecodeByteBuffer uid: %u, _javaDirectDecodeBuffer: %p",
288
+                            uid, _javaDirectDecodeBuffer);
289
+    }
290
+}
291
+
292
+JNIEXPORT void JNICALL
293
+Java_com_syan_agora_media_MediaPreProcessing_releasePoint(JNIEnv *env, jclass type) {
294
+    agora::util::AutoPtr<agora::media::IMediaEngine> mediaEngine;
295
+    mediaEngine.queryInterface(rtcEngine, agora::INTERFACE_ID_TYPE::AGORA_IID_MEDIA_ENGINE);
296
+
297
+    if (mediaEngine) {
298
+        mediaEngine->registerVideoFrameObserver(NULL);
299
+        mediaEngine->registerAudioFrameObserver(NULL);
300
+    }
301
+
302
+    if (gCallBack != nullptr) {
303
+        env->DeleteGlobalRef(gCallBack);
304
+        gCallBack = nullptr;
305
+    }
306
+    gCallbackClass = nullptr;
307
+
308
+    recordAudioMethodId = nullptr;
309
+    playbackAudioMethodId = nullptr;
310
+    playBeforeMixAudioMethodId = nullptr;
311
+    mixAudioMethodId = nullptr;
312
+    captureVideoMethodId = nullptr;
313
+    renderVideoMethodId = nullptr;
314
+
315
+    _javaDirectPlayBufferCapture = nullptr;
316
+    _javaDirectPlayBufferRecordAudio = nullptr;
317
+    _javaDirectPlayBufferPlayAudio = nullptr;
318
+    _javaDirectPlayBufferBeforeMixAudio = nullptr;
319
+    _javaDirectPlayBufferMixAudio = nullptr;
320
+
321
+    decodeBufferMap.clear();
322
+}
323
+
324
+
325
+#ifdef __cplusplus
326
+}
327
+#endif

+ 77
- 0
android/src/main/cpp/src/agora_media_pre_processing.h View File

1
+/* DO NOT EDIT THIS FILE - it is machine generated */
2
+#include <jni.h>
3
+/* Header for class com_syan_agora_media_MediaPreProcessing */
4
+
5
+#ifndef _Included_com_syan_agora_media_MediaPreProcessing
6
+#define _Included_com_syan_agora_media_MediaPreProcessing
7
+#ifdef __cplusplus
8
+extern "C" {
9
+#endif
10
+/*
11
+ * Class:     com_syan_agora_media_MediaPreProcessing
12
+ * Method:    setCallback
13
+ * Signature: (Lcom/syan/agora/media/MediaPreProcessing/ProgressCallback;)V
14
+ */
15
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_setCallback
16
+  (JNIEnv *, jclass, jobject);
17
+
18
+/*
19
+ * Class:     com_syan_agora_media_MediaPreProcessing
20
+ * Method:    setVideoCaptureByteBuffer
21
+ * Signature: (Ljava/nio/ByteBuffer;)V
22
+ */
23
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_setVideoCaptureByteBuffer
24
+  (JNIEnv *, jclass, jobject);
25
+
26
+/*
27
+ * Class:     com_syan_agora_media_MediaPreProcessing
28
+ * Method:    setAudioRecordByteBuffer
29
+ * Signature: (Ljava/nio/ByteBuffer;)V
30
+ */
31
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_setAudioRecordByteBuffer
32
+  (JNIEnv *, jclass, jobject);
33
+
34
+/*
35
+ * Class:     com_syan_agora_media_MediaPreProcessing
36
+ * Method:    setAudioPlayByteBuffer
37
+ * Signature: (Ljava/nio/ByteBuffer;)V
38
+ */
39
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_setAudioPlayByteBuffer
40
+  (JNIEnv *, jclass, jobject);
41
+
42
+/*
43
+ * Class:     com_syan_agora_media_MediaPreProcessing
44
+ * Method:    setBeforeAudioMixByteBuffer
45
+ * Signature: (Ljava/nio/ByteBuffer;)V
46
+ */
47
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_setBeforeAudioMixByteBuffer
48
+  (JNIEnv *, jclass, jobject);
49
+
50
+/*
51
+ * Class:     com_syan_agora_media_MediaPreProcessing
52
+ * Method:    setAudioMixByteBuffer
53
+ * Signature: (Ljava/nio/ByteBuffer;)V
54
+ */
55
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_setAudioMixByteBuffer
56
+  (JNIEnv *, jclass, jobject);
57
+
58
+/*
59
+ * Class:     com_syan_agora_media_MediaPreProcessing
60
+ * Method:    setVideoDecodeByteBuffer
61
+ * Signature: (ILjava/nio/ByteBuffer;)V
62
+ */
63
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_setVideoDecodeByteBuffer
64
+  (JNIEnv *, jclass, jint, jobject);
65
+
66
+/*
67
+ * Class:     com_syan_agora_media_MediaPreProcessing
68
+ * Method:    releasePoint
69
+ * Signature: ()V
70
+ */
71
+JNIEXPORT void JNICALL Java_com_syan_agora_media_MediaPreProcessing_releasePoint
72
+  (JNIEnv *, jclass);
73
+
74
+#ifdef __cplusplus
75
+}
76
+#endif
77
+#endif

+ 5
- 7
android/src/main/java/com/syan/agora/AgoraConst.java View File

19
     public final static String AGTokenPrivilegeWillExpire = "tokenPrivilegeWillExpire";
19
     public final static String AGTokenPrivilegeWillExpire = "tokenPrivilegeWillExpire";
20
     public final static String AGRequestToken = "requestToken";
20
     public final static String AGRequestToken = "requestToken";
21
 
21
 
22
-    public final static String AGMicrophoneEnabled = "microphoneEnabled";
23
     public final static String AGAudioVolumeIndication = "audioVolumeIndication";
22
     public final static String AGAudioVolumeIndication = "audioVolumeIndication";
24
     public final static String AGActiveSpeaker = "activeSpeaker";
23
     public final static String AGActiveSpeaker = "activeSpeaker";
25
     public final static String AGFirstLocalAudioFrame = "firstLocalAudioFrame";
24
     public final static String AGFirstLocalAudioFrame = "firstLocalAudioFrame";
26
     public final static String AGFirstRemoteAudioFrame = "firstRemoteAudioFrame";
25
     public final static String AGFirstRemoteAudioFrame = "firstRemoteAudioFrame";
27
     public final static String AGFirstLocalVideoFrame = "firstLocalVideoFrame";
26
     public final static String AGFirstLocalVideoFrame = "firstLocalVideoFrame";
28
-    public final static String AGFirstRemoteVideoDecoded = "firstRemoteVideoDecoded";
29
     public final static String AGFirstRemoteVideoFrame = "firstRemoteVideoFrame";
27
     public final static String AGFirstRemoteVideoFrame = "firstRemoteVideoFrame";
30
     public final static String AGUserMuteAudio = "userMuteAudio";
28
     public final static String AGUserMuteAudio = "userMuteAudio";
31
-    public final static String AGUserMuteVideo = "userMuteVideo";
32
-    public final static String AGUserEnableVideo = "userEnableVideo";
33
-    public final static String AGUserEnableLocalVideo = "userEnableLocalVideo";
34
     public final static String AGVideoSizeChanged = "videoSizeChanged";
29
     public final static String AGVideoSizeChanged = "videoSizeChanged";
35
     public final static String AGRtmpStreamingStateChanged = "rtmpStreamingStateChanged";
30
     public final static String AGRtmpStreamingStateChanged = "rtmpStreamingStateChanged";
36
     public final static String AGNetworkTypeChanged = "networkTypeChanged";
31
     public final static String AGNetworkTypeChanged = "networkTypeChanged";
44
     public final static String AGAudioRouteChanged = "audioRouteChanged";
39
     public final static String AGAudioRouteChanged = "audioRouteChanged";
45
     public final static String AGCameraFocusAreaChanged = "cameraFocusAreaChanged";
40
     public final static String AGCameraFocusAreaChanged = "cameraFocusAreaChanged";
46
     public final static String AGCameraExposureAreaChanged = "cameraExposureAreaChanged";
41
     public final static String AGCameraExposureAreaChanged = "cameraExposureAreaChanged";
42
+    public final static String AGRemoteAudioStateChanged = "remoteAudioStateChanged";
43
+    public final static String AGLocalAudioStateChanged = "localAudioStateChanged";
44
+    public final static String AGLocalAudioStats = "localAudioStats";
45
+    public final static String AGMediaRelayStateChanged = "mediaRelayStateChanged";
46
+    public final static String AGReceivedChannelMediaRelay = "receivedChannelMediaRelay";
47
 
47
 
48
     public final static String AGRtcStats = "rtcStats";
48
     public final static String AGRtcStats = "rtcStats";
49
     public final static String AGLastmileQuality = "lastmileQuality";
49
     public final static String AGLastmileQuality = "lastmileQuality";
51
     public final static String AGLocalVideoStats = "localVideoStats";
51
     public final static String AGLocalVideoStats = "localVideoStats";
52
     public final static String AGRemoteVideoStats = "remoteVideoStats";
52
     public final static String AGRemoteVideoStats = "remoteVideoStats";
53
     public final static String AGRemoteAudioStats = "remoteAudioStats";
53
     public final static String AGRemoteAudioStats = "remoteAudioStats";
54
-    public final static String AGAudioTransportStatsOfUid = "audioTransportStatsOfUid";
55
-    public final static String AGVideoTransportStatsOfUid = "videoTransportStatsOfUid";
56
 
54
 
57
     public final static String AGRemoteAudioMixingStart = "remoteAudioMixingStart";
55
     public final static String AGRemoteAudioMixingStart = "remoteAudioMixingStart";
58
     public final static String AGRemoteAudioMixingFinish = "remoteAudioMixingFinish";
56
     public final static String AGRemoteAudioMixingFinish = "remoteAudioMixingFinish";

+ 329
- 172
android/src/main/java/com/syan/agora/AgoraModule.java View File

2
 
2
 
3
 import android.graphics.Rect;
3
 import android.graphics.Rect;
4
 import android.support.annotation.Nullable;
4
 import android.support.annotation.Nullable;
5
+import android.view.SurfaceView;
5
 
6
 
6
 import com.facebook.react.bridge.Arguments;
7
 import com.facebook.react.bridge.Arguments;
7
 import com.facebook.react.bridge.Callback;
8
 import com.facebook.react.bridge.Callback;
34
 import io.agora.rtc.video.AgoraImage;
35
 import io.agora.rtc.video.AgoraImage;
35
 import io.agora.rtc.video.BeautyOptions;
36
 import io.agora.rtc.video.BeautyOptions;
36
 import io.agora.rtc.video.CameraCapturerConfiguration;
37
 import io.agora.rtc.video.CameraCapturerConfiguration;
38
+import io.agora.rtc.video.ChannelMediaInfo;
39
+import io.agora.rtc.video.ChannelMediaRelayConfiguration;
37
 import io.agora.rtc.video.VideoEncoderConfiguration;
40
 import io.agora.rtc.video.VideoEncoderConfiguration;
38
 
41
 
39
 import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread;
42
 import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread;
276
                 public void run() {
279
                 public void run() {
277
                     WritableMap map = Arguments.createMap();
280
                     WritableMap map = Arguments.createMap();
278
                     map.putString("message", "AgoraWarning");
281
                     map.putString("message", "AgoraWarning");
279
-                    map.putInt("code", code);
282
+                    map.putInt("errorCode", code);
280
                     sendEvent(getReactApplicationContext(), AGWarning, map);
283
                     sendEvent(getReactApplicationContext(), AGWarning, map);
281
                 }
284
                 }
282
             });
285
             });
289
                 public void run() {
292
                 public void run() {
290
                     WritableMap map = Arguments.createMap();
293
                     WritableMap map = Arguments.createMap();
291
                     map.putString("message", "AgoraError");
294
                     map.putString("message", "AgoraError");
292
-                    map.putInt("code", code);
295
+                    map.putInt("errorCode", code);
293
                     sendEvent(getReactApplicationContext(), AGError, map);
296
                     sendEvent(getReactApplicationContext(), AGError, map);
294
                 }
297
                 }
295
             });
298
             });
301
                 @Override
304
                 @Override
302
                 public void run() {
305
                 public void run() {
303
                     WritableMap map = Arguments.createMap();
306
                     WritableMap map = Arguments.createMap();
304
-                    map.putInt("error", code);
307
+                    map.putInt("errorCode", code);
305
                     map.putString("api", api);
308
                     map.putString("api", api);
306
                     map.putString("result", result);
309
                     map.putString("result", result);
307
                     if (code != 0) {
310
                     if (code != 0) {
350
                     statsMap.putInt("duration", stats.totalDuration);
353
                     statsMap.putInt("duration", stats.totalDuration);
351
                     statsMap.putInt("txBytes", stats.txBytes);
354
                     statsMap.putInt("txBytes", stats.txBytes);
352
                     statsMap.putInt("rxBytes", stats.rxBytes);
355
                     statsMap.putInt("rxBytes", stats.rxBytes);
353
-                    // statsMap.putInt("txKBitRate", stats.txKBitRate);
354
-                    // statsMap.putInt("rxKBitRate", stats.rxKBitRate);
356
+                    statsMap.putInt("txAudioBytes", stats.txAudioBytes);
357
+                    statsMap.putInt("txVideoBytes", stats.txVideoBytes);
358
+                    statsMap.putInt("rxAudioBytes", stats.rxAudioBytes);
359
+                    statsMap.putInt("rxVideoBytes", stats.rxVideoBytes);
360
+                    statsMap.putInt("txKBitRate", stats.txKBitRate);
361
+                    statsMap.putInt("rxKBitRate", stats.rxKBitRate);
355
                     statsMap.putInt("txAudioKBitRate", stats.txAudioKBitRate);
362
                     statsMap.putInt("txAudioKBitRate", stats.txAudioKBitRate);
356
                     statsMap.putInt("rxAudioKBitRate", stats.rxAudioKBitRate);
363
                     statsMap.putInt("rxAudioKBitRate", stats.rxAudioKBitRate);
357
                     statsMap.putInt("txVideoKBitRate", stats.txVideoKBitRate);
364
                     statsMap.putInt("txVideoKBitRate", stats.txVideoKBitRate);
488
             });
495
             });
489
         }
496
         }
490
 
497
 
491
-        @Override
492
-        public void onMicrophoneEnabled(final boolean enabled) {
493
-            runOnUiThread(new Runnable() {
494
-                @Override
495
-                public void run() {
496
-                    WritableMap map = Arguments.createMap();
497
-                    map.putBoolean("enabled", enabled);
498
-                    sendEvent(getReactApplicationContext(), AGMicrophoneEnabled, map);
499
-                }
500
-
501
-            });
502
-        }
503
-
504
         @Override
498
         @Override
505
         public void onAudioVolumeIndication(final AudioVolumeInfo [] speakers, final int totalVolume) {
499
         public void onAudioVolumeIndication(final AudioVolumeInfo [] speakers, final int totalVolume) {
506
             runOnUiThread(new Runnable() {
500
             runOnUiThread(new Runnable() {
574
             });
568
             });
575
         }
569
         }
576
 
570
 
577
-        /**
578
-         * onFirstRemoteVideoDecoded
579
-         */
580
-        @Override
581
-        public void onFirstRemoteVideoDecoded(final int uid, final int width, final int height, final int elapsed) {
582
-            runOnUiThread(new Runnable() {
583
-                @Override
584
-                public void run() {
585
-                    WritableMap map = Arguments.createMap();
586
-                    map.putInt("uid", uid);
587
-                    map.putInt("width", width);
588
-                    map.putInt("height", height);
589
-                    map.putInt("elapsed", elapsed);
590
-                    sendEvent(getReactApplicationContext(), AGFirstRemoteVideoDecoded, map);
591
-                }
592
-            });
593
-        }
594
-
595
         @Override
571
         @Override
596
         public void onFirstRemoteVideoFrame(final int uid, final int width, final int height, final int elapsed) {
572
         public void onFirstRemoteVideoFrame(final int uid, final int width, final int height, final int elapsed) {
597
             runOnUiThread(new Runnable() {
573
             runOnUiThread(new Runnable() {
621
         }
597
         }
622
 
598
 
623
         @Override
599
         @Override
624
-        public void onUserMuteVideo(final int uid, final boolean muted) {
600
+        public void onVideoSizeChanged(final int uid, final int width, final int height, final int rotation) {
625
             runOnUiThread(new Runnable() {
601
             runOnUiThread(new Runnable() {
626
                 @Override
602
                 @Override
627
                 public void run() {
603
                 public void run() {
628
                     WritableMap map = Arguments.createMap();
604
                     WritableMap map = Arguments.createMap();
629
-                    map.putBoolean("muted", muted);
630
                     map.putInt("uid", uid);
605
                     map.putInt("uid", uid);
631
-                    sendEvent(getReactApplicationContext(), AGUserMuteVideo, map);
606
+                    map.putInt("width", width);
607
+                    map.putInt("height", height);
608
+                    map.putInt("rotation", rotation);
609
+                    sendEvent(getReactApplicationContext(), AGVideoSizeChanged, map);
632
                 }
610
                 }
633
             });
611
             });
634
         }
612
         }
635
 
613
 
636
         @Override
614
         @Override
637
-        public void onUserEnableVideo(final int uid, final boolean enabled) {
615
+        public void onRtmpStreamingStateChanged(final String url, final int state, final int errCode) {
638
             runOnUiThread(new Runnable() {
616
             runOnUiThread(new Runnable() {
639
                 @Override
617
                 @Override
640
                 public void run() {
618
                 public void run() {
641
                     WritableMap map = Arguments.createMap();
619
                     WritableMap map = Arguments.createMap();
642
-                    map.putBoolean("enabled", enabled);
643
-                    map.putInt("uid", uid);
644
-                    sendEvent(getReactApplicationContext(), AGUserEnableVideo, map);
620
+                    map.putString("url", url);
621
+                    map.putInt("state", state);
622
+                    map.putInt("errorCode", errCode);
623
+                    sendEvent(getReactApplicationContext(), AGRtmpStreamingStateChanged, map);
645
                 }
624
                 }
646
             });
625
             });
647
         }
626
         }
648
 
627
 
649
         @Override
628
         @Override
650
-        public void onUserEnableLocalVideo(final int uid, final boolean enabled) {
629
+        public void onNetworkTypeChanged(final int type) {
651
             runOnUiThread(new Runnable() {
630
             runOnUiThread(new Runnable() {
652
                 @Override
631
                 @Override
653
                 public void run() {
632
                 public void run() {
654
                     WritableMap map = Arguments.createMap();
633
                     WritableMap map = Arguments.createMap();
655
-                    map.putBoolean("enabled", enabled);
656
-                    map.putInt("uid", uid);
657
-                    sendEvent(getReactApplicationContext(), AGUserEnableLocalVideo, map);
634
+                    map.putInt("type", type);
635
+                    sendEvent(getReactApplicationContext(), AGNetworkTypeChanged, map);
658
                 }
636
                 }
659
             });
637
             });
660
         }
638
         }
661
 
639
 
662
-        @Override
663
-        public void onVideoSizeChanged(final int uid, final int width, final int height, final int rotation) {
664
-            runOnUiThread(new Runnable() {
665
-                @Override
666
-                public void run() {
667
-                    WritableMap map = Arguments.createMap();
668
-                    map.putInt("uid", uid);
669
-                    map.putInt("width", width);
670
-                    map.putInt("height", height);
671
-                    map.putInt("rotation", rotation);
672
-                    sendEvent(getReactApplicationContext(), AGVideoSizeChanged, map);
673
-                }
674
-            });
675
-        }
676
 
640
 
677
         @Override
641
         @Override
678
-        public void onRtmpStreamingStateChanged(final String url, final int state, final int errCode) {
642
+        public void onLocalAudioStateChanged(final int state, final int errCode) {
679
             runOnUiThread(new Runnable() {
643
             runOnUiThread(new Runnable() {
680
                 @Override
644
                 @Override
681
                 public void run() {
645
                 public void run() {
682
                     WritableMap map = Arguments.createMap();
646
                     WritableMap map = Arguments.createMap();
683
-                    map.putString("url", url);
684
                     map.putInt("state", state);
647
                     map.putInt("state", state);
685
                     map.putInt("errorCode", errCode);
648
                     map.putInt("errorCode", errCode);
686
-                    sendEvent(getReactApplicationContext(), AGRtmpStreamingStateChanged, map);
649
+                    sendEvent(getReactApplicationContext(), AGLocalAudioStateChanged, map);
687
                 }
650
                 }
688
             });
651
             });
689
         }
652
         }
690
-
691
         @Override
653
         @Override
692
-        public void onNetworkTypeChanged(final int type) {
654
+        public void onRemoteAudioStateChanged(final int uid,
655
+                                              final int state,
656
+                                              final int reason,
657
+                                              final int elapsed) {
693
             runOnUiThread(new Runnable() {
658
             runOnUiThread(new Runnable() {
694
                 @Override
659
                 @Override
695
                 public void run() {
660
                 public void run() {
696
                     WritableMap map = Arguments.createMap();
661
                     WritableMap map = Arguments.createMap();
697
-                    map.putInt("type", type);
698
-                    sendEvent(getReactApplicationContext(), AGNetworkTypeChanged, map);
662
+                    map.putInt("uid", uid);
663
+                    map.putInt("state", state);
664
+                    map.putInt("uid", reason);
665
+                    map.putInt("elapsed", elapsed);
666
+                    sendEvent(getReactApplicationContext(), AGRemoteAudioStateChanged, map);
699
                 }
667
                 }
700
             });
668
             });
701
         }
669
         }
714
         }
682
         }
715
 
683
 
716
         @Override
684
         @Override
717
-        public void onRemoteVideoStateChanged(final int uid, final int state) {
685
+        public void onRemoteVideoStateChanged(final int uid,
686
+                                              final int state,
687
+                                              final int reason,
688
+                                              final int elapsed)  {
718
             runOnUiThread(new Runnable() {
689
             runOnUiThread(new Runnable() {
719
                 @Override
690
                 @Override
720
                 public void run() {
691
                 public void run() {
721
                     WritableMap map = Arguments.createMap();
692
                     WritableMap map = Arguments.createMap();
722
                     map.putInt("uid", uid);
693
                     map.putInt("uid", uid);
723
                     map.putInt("state", state);
694
                     map.putInt("state", state);
695
+                    map.putInt("reason", reason);
696
+                    map.putInt("elapsed", elapsed);
724
                     sendEvent(getReactApplicationContext(), AGRemoteVideoStateChanged, map);
697
                     sendEvent(getReactApplicationContext(), AGRemoteVideoStateChanged, map);
725
                 }
698
                 }
726
             });
699
             });
829
                     statsMap.putInt("duration", stats.totalDuration);
802
                     statsMap.putInt("duration", stats.totalDuration);
830
                     statsMap.putInt("txBytes", stats.txBytes);
803
                     statsMap.putInt("txBytes", stats.txBytes);
831
                     statsMap.putInt("rxBytes", stats.rxBytes);
804
                     statsMap.putInt("rxBytes", stats.rxBytes);
832
-                    statsMap.putInt("txAudioKBitRate", stats.txAudioKBitRate);
805
+                    statsMap.putInt("txAudioBytes", stats.txAudioBytes);
806
+                    statsMap.putInt("txVideoBytes", stats.txVideoBytes);
807
+                    statsMap.putInt("rxAudioBytes", stats.rxAudioBytes);
808
+                    statsMap.putInt("rxVideoBytes", stats.rxVideoBytes);
809
+                    statsMap.putInt("txKBitRate", stats.txKBitRate);
810
+                    statsMap.putInt("rxKBitRate", stats.rxKBitRate);
811
+                    statsMap.putInt("rxVideoKBitRate", stats.rxVideoKBitRate);
833
                     statsMap.putInt("rxAudioKBitRate", stats.rxAudioKBitRate);
812
                     statsMap.putInt("rxAudioKBitRate", stats.rxAudioKBitRate);
834
                     statsMap.putInt("txVideoKBitRate", stats.txVideoKBitRate);
813
                     statsMap.putInt("txVideoKBitRate", stats.txVideoKBitRate);
835
                     statsMap.putInt("rxVideoKBitRate", stats.rxVideoKBitRate);
814
                     statsMap.putInt("rxVideoKBitRate", stats.rxVideoKBitRate);
884
                     statsMap.putInt("sentFrameRate", stats.sentFrameRate);
863
                     statsMap.putInt("sentFrameRate", stats.sentFrameRate);
885
                     statsMap.putInt("encoderOutputFrameRate", stats.encoderOutputFrameRate);
864
                     statsMap.putInt("encoderOutputFrameRate", stats.encoderOutputFrameRate);
886
                     statsMap.putInt("rendererOutputFrameRate", stats.rendererOutputFrameRate);
865
                     statsMap.putInt("rendererOutputFrameRate", stats.rendererOutputFrameRate);
866
+                    statsMap.putInt("targetBitrate", stats.targetBitrate);
867
+                    statsMap.putInt("targetFrameRate", stats.targetFrameRate);
868
+                    statsMap.putInt("qualityAdaptIndication", stats.qualityAdaptIndication);
869
+                    statsMap.putInt("encodedBitrate", stats.encodedBitrate);
870
+                    statsMap.putInt("encodedFrameWidth", stats.encodedFrameWidth);
871
+                    statsMap.putInt("encodedFrameHeight", stats.encodedFrameHeight);
872
+                    statsMap.putInt("encodedFrameCount", stats.encodedFrameCount);
873
+                    statsMap.putInt("codecType", stats.codecType);
887
                     WritableMap map = Arguments.createMap();
874
                     WritableMap map = Arguments.createMap();
888
                     map.putMap("stats", statsMap);
875
                     map.putMap("stats", statsMap);
889
                     sendEvent(getReactApplicationContext(), AGLocalVideoStats, map);
876
                     sendEvent(getReactApplicationContext(), AGLocalVideoStats, map);
901
                     statsMap.putInt("width", stats.width);
888
                     statsMap.putInt("width", stats.width);
902
                     statsMap.putInt("height", stats.height);
889
                     statsMap.putInt("height", stats.height);
903
                     statsMap.putInt("receivedBitrate", stats.receivedBitrate);
890
                     statsMap.putInt("receivedBitrate", stats.receivedBitrate);
891
+                    statsMap.putInt("decoderOutputFrameRate", stats.decoderOutputFrameRate);
904
                     statsMap.putInt("rendererOutputFrameRate", stats.rendererOutputFrameRate);
892
                     statsMap.putInt("rendererOutputFrameRate", stats.rendererOutputFrameRate);
893
+                    statsMap.putInt("packetLossRate", stats.packetLossRate);
905
                     statsMap.putInt("rxStreamType", stats.rxStreamType);
894
                     statsMap.putInt("rxStreamType", stats.rxStreamType);
906
                     statsMap.putInt("totalFrozenTime", stats.totalFrozenTime);
895
                     statsMap.putInt("totalFrozenTime", stats.totalFrozenTime);
907
                     statsMap.putInt("frozenRate", stats.frozenRate);
896
                     statsMap.putInt("frozenRate", stats.frozenRate);
912
             });
901
             });
913
         }
902
         }
914
 
903
 
915
-        @Override
916
-        public void onRemoteAudioTransportStats(final int uid,
917
-                                                final int delay,
918
-                                                final int lost,
919
-                                                final int rxKBitRate) {
920
-            runOnUiThread(new Runnable() {
921
-                @Override
922
-                public void run() {
923
-                    WritableMap statsMap = Arguments.createMap();
924
-                    statsMap.putInt("uid", uid);
925
-                    statsMap.putInt("delay", delay);
926
-                    statsMap.putInt("lost", lost);
927
-                    statsMap.putInt("rxKBitRate", rxKBitRate);
928
-                    WritableMap map = Arguments.createMap();
929
-                    map.putMap("stats", statsMap);
930
-                    sendEvent(getReactApplicationContext(), AGAudioTransportStatsOfUid, map);
931
-                }
932
-            });
933
-        }
934
-
935
-        @Override
936
-        public void onRemoteVideoTransportStats(final int uid,
937
-                                                final int delay,
938
-                                                final int lost,
939
-                                                final int rxKBitRate) {
940
-            runOnUiThread(new Runnable() {
941
-                @Override
942
-                public void run() {
943
-                    WritableMap statsMap = Arguments.createMap();
944
-                    statsMap.putInt("uid", uid);
945
-                    statsMap.putInt("delay", delay);
946
-                    statsMap.putInt("lost", lost);
947
-                    statsMap.putInt("rxKBitRate", rxKBitRate);
948
-                    WritableMap map = Arguments.createMap();
949
-                    map.putMap("stats", statsMap);
950
-                    sendEvent(getReactApplicationContext(), AGVideoTransportStatsOfUid, map);
951
-                }
952
-            });
953
-        }
954
-
955
         @Override
904
         @Override
956
         public void onAudioMixingStateChanged(final int state, final int errorCode) {
905
         public void onAudioMixingStateChanged(final int state, final int errorCode) {
957
             runOnUiThread(new Runnable() {
906
             runOnUiThread(new Runnable() {
984
                 public void run() {
933
                 public void run() {
985
                     WritableMap map = Arguments.createMap();
934
                     WritableMap map = Arguments.createMap();
986
                     map.putString("url", url);
935
                     map.putString("url", url);
987
-                    map.putInt("code", errorCode);
936
+                    map.putInt("errorCode", errorCode);
988
                     sendEvent(getReactApplicationContext(), AGStreamPublished, map);
937
                     sendEvent(getReactApplicationContext(), AGStreamPublished, map);
989
                 }
938
                 }
990
             });
939
             });
1054
                     WritableMap map = Arguments.createMap();
1003
                     WritableMap map = Arguments.createMap();
1055
                     map.putInt("uid", uid);
1004
                     map.putInt("uid", uid);
1056
                     map.putInt("streamId", streamId);
1005
                     map.putInt("streamId", streamId);
1057
-                    map.putInt("error", error);
1006
+                    map.putInt("errorCode", error);
1058
                     map.putInt("missed", missed);
1007
                     map.putInt("missed", missed);
1059
                     map.putInt("cached", cached);
1008
                     map.putInt("cached", cached);
1060
                     sendEvent(getReactApplicationContext(), AGOccurStreamMessageError, map);
1009
                     sendEvent(getReactApplicationContext(), AGOccurStreamMessageError, map);
1112
                 }
1061
                 }
1113
             });
1062
             });
1114
         }
1063
         }
1064
+
1065
+        @Override
1066
+        public void onChannelMediaRelayEvent(final int code) {
1067
+            super.onChannelMediaRelayEvent(code);
1068
+            runOnUiThread(new Runnable() {
1069
+                @Override
1070
+                public void run() {
1071
+                    WritableMap map = Arguments.createMap();
1072
+                    map.putInt("errorCode", code);
1073
+                    sendEvent(getReactApplicationContext(), AGReceivedChannelMediaRelay, map);
1074
+                }
1075
+            });
1076
+        }
1077
+
1078
+        @Override
1079
+        public void onChannelMediaRelayStateChanged(final int state, final int code) {
1080
+            super.onChannelMediaRelayStateChanged(state, code);
1081
+            runOnUiThread(new Runnable() {
1082
+                @Override
1083
+                public void run() {
1084
+                    WritableMap map = Arguments.createMap();
1085
+                    map.putInt("state", state);
1086
+                    map.putInt("errorCode", code);
1087
+                    sendEvent(getReactApplicationContext(), AGMediaRelayStateChanged, map);
1088
+                }
1089
+            });
1090
+        }
1091
+
1092
+        @Override
1093
+        public void onLocalAudioStats(final LocalAudioStats rtcStats) {
1094
+            super.onLocalAudioStats(rtcStats);
1095
+            runOnUiThread(new Runnable() {
1096
+                @Override
1097
+                public void run() {
1098
+                    WritableMap map = Arguments.createMap();
1099
+                    map.putInt("numChannels", rtcStats.numChannels);
1100
+                    map.putInt("sentSampleRate", rtcStats.sentSampleRate);
1101
+                    map.putInt("sentBitrate", rtcStats.sentBitrate);
1102
+                    sendEvent(getReactApplicationContext(), AGLocalAudioStats, map);
1103
+                }
1104
+            });
1105
+        }
1115
     };
1106
     };
1116
 
1107
 
1117
     @ReactMethod
1108
     @ReactMethod
1162
         }
1153
         }
1163
     }
1154
     }
1164
 
1155
 
1156
+    private String channelName = null;
1157
+
1165
     @ReactMethod
1158
     @ReactMethod
1166
     public void joinChannel(ReadableMap options, Promise promise) {
1159
     public void joinChannel(ReadableMap options, Promise promise) {
1167
         Integer res = AgoraManager.getInstance().joinChannel(options);
1160
         Integer res = AgoraManager.getInstance().joinChannel(options);
1168
         if (res == 0) {
1161
         if (res == 0) {
1162
+            String channelName = options.getString("channelName");
1163
+            this.channelName = channelName;
1169
             promise.resolve(null);
1164
             promise.resolve(null);
1170
         } else {
1165
         } else {
1171
             promise.reject("-1", res.toString());
1166
             promise.reject("-1", res.toString());
1188
         if (options.hasKey("token")) {
1183
         if (options.hasKey("token")) {
1189
             token = options.getString("token");
1184
             token = options.getString("token");
1190
         }
1185
         }
1186
+        String channelName = options.getString("channelName");
1191
         Integer res = rtcEngine.joinChannelWithUserAccount(token, options.getString("channelName"), options.getString("userAccount"));
1187
         Integer res = rtcEngine.joinChannelWithUserAccount(token, options.getString("channelName"), options.getString("userAccount"));
1192
         if (res == 0) {
1188
         if (res == 0) {
1189
+            this.channelName = channelName;
1193
             promise.resolve(null);
1190
             promise.resolve(null);
1194
         } else {
1191
         } else {
1195
             promise.reject("-1", res.toString());
1192
             promise.reject("-1", res.toString());
1224
         }
1221
         }
1225
     }
1222
     }
1226
 
1223
 
1224
+    @ReactMethod
1225
+    public void switchChannel(ReadableMap options, Promise promise) {
1226
+        String token = null;
1227
+        String channel = null;
1228
+        if (options.hasKey("token")) {
1229
+            token = options.getString("token");
1230
+        }
1231
+        if (options.hasKey("channelName")) {
1232
+            channel = options.getString("channelName");
1233
+        }
1234
+        Integer res = AgoraManager.getInstance().mRtcEngine.switchChannel(token, channel);
1235
+        if (res == 0) {
1236
+            promise.resolve(null);
1237
+        } else {
1238
+            promise.reject("-1", res.toString());
1239
+        }
1240
+    }
1241
+
1227
     @ReactMethod
1242
     @ReactMethod
1228
     public void leaveChannel(Promise promise) {
1243
     public void leaveChannel(Promise promise) {
1229
         Integer res = AgoraManager.getInstance().leaveChannel();
1244
         Integer res = AgoraManager.getInstance().leaveChannel();
1239
         RtcEngine.destroy();
1254
         RtcEngine.destroy();
1240
     }
1255
     }
1241
 
1256
 
1257
+    @ReactMethod
1258
+    public void startChannelMediaRelay(ReadableMap options, Promise promise) {
1259
+        ChannelMediaRelayConfiguration config = new ChannelMediaRelayConfiguration();
1260
+        ChannelMediaInfo src = config.getSrcChannelMediaInfo();
1261
+        if (options.hasKey("src")) {
1262
+            ReadableMap srcOption = options.getMap("src");
1263
+            if (srcOption.hasKey("token")) {
1264
+                src.token = srcOption.getString("token");
1265
+            }
1266
+            if (srcOption.hasKey("channelName")) {
1267
+                src.channelName = srcOption.getString("channelName");
1268
+            }
1269
+        }
1270
+        ReadableArray dstMediaInfo = options.getArray("channels");
1271
+        for (int i = 0; i < dstMediaInfo.size(); i++) {
1272
+            ReadableMap dst = dstMediaInfo.getMap(i);
1273
+            String channelName = null;
1274
+            String token = null;
1275
+            Integer uid = 0;
1276
+            if (dst.hasKey("token")) {
1277
+                token = token;
1278
+            }
1279
+            if (dst.hasKey("channelName")) {
1280
+                channelName = dst.getString("channelName");
1281
+            }
1282
+            if (dst.hasKey("uid")) {
1283
+                uid = dst.getInt("uid");
1284
+            }
1285
+            config.setDestChannelInfo(channelName, new ChannelMediaInfo(channelName, token, uid));
1286
+        }
1287
+        Integer res = AgoraManager.getInstance().mRtcEngine.startChannelMediaRelay(config);
1288
+        if (res == 0) {
1289
+            promise.resolve(null);
1290
+        } else {
1291
+            promise.reject("-1", res.toString());
1292
+        }
1293
+    }
1294
+
1295
+    @ReactMethod
1296
+    public void removeChannelMediaRelay(ReadableMap options, Promise promise) {
1297
+        ChannelMediaRelayConfiguration config = new ChannelMediaRelayConfiguration();
1298
+        ChannelMediaInfo src = config.getSrcChannelMediaInfo();
1299
+        if (options.hasKey("src")) {
1300
+            ReadableMap srcOption = options.getMap("src");
1301
+            if (srcOption.hasKey("token")) {
1302
+                src.token = srcOption.getString("token");
1303
+            }
1304
+            if (srcOption.hasKey("channelName")) {
1305
+                src.channelName = srcOption.getString("channelName");
1306
+            }
1307
+        }
1308
+        ReadableArray dstMediaInfo = options.getArray("channels");
1309
+        for (int i = 0; i < dstMediaInfo.size(); i++) {
1310
+            ReadableMap dst = dstMediaInfo.getMap(i);
1311
+            if (dst.hasKey("channelName")) {
1312
+                channelName = dst.getString("channelName");
1313
+                config.removeDestChannelInfo(channelName);
1314
+            }
1315
+        }
1316
+        Integer res = AgoraManager.getInstance().mRtcEngine.updateChannelMediaRelay(config);
1317
+        if (res == 0) {
1318
+            promise.resolve(null);
1319
+        } else {
1320
+            promise.reject("-1", res.toString());
1321
+        }
1322
+    }
1323
+
1324
+    @ReactMethod
1325
+    public void updateChannelMediaRelay(ReadableMap options, Promise promise) {
1326
+        ChannelMediaRelayConfiguration config = new ChannelMediaRelayConfiguration();
1327
+        ChannelMediaInfo src = config.getSrcChannelMediaInfo();
1328
+        if (options.hasKey("src")) {
1329
+            ReadableMap srcOption = options.getMap("src");
1330
+            if (srcOption.hasKey("token")) {
1331
+                src.token = srcOption.getString("token");
1332
+            }
1333
+            if (srcOption.hasKey("channelName")) {
1334
+                src.channelName = srcOption.getString("channelName");
1335
+            }
1336
+        }
1337
+        ReadableArray dstMediaInfo = options.getArray("channels");
1338
+        for (int i = 0; i < dstMediaInfo.size(); i++) {
1339
+            ReadableMap dst = dstMediaInfo.getMap(i);
1340
+            String channelName = null;
1341
+            String token = null;
1342
+            Integer uid = 0;
1343
+            if (dst.hasKey("token")) {
1344
+                token = token;
1345
+            }
1346
+            if (dst.hasKey("channelName")) {
1347
+                channelName = dst.getString("channelName");
1348
+            }
1349
+            if (dst.hasKey("uid")) {
1350
+                uid = dst.getInt("uid");
1351
+            }
1352
+            config.setDestChannelInfo(src.channelName, new ChannelMediaInfo(channelName, token, uid));
1353
+        }
1354
+        Integer res = AgoraManager.getInstance().mRtcEngine.updateChannelMediaRelay(config);
1355
+        if (res == 0) {
1356
+            promise.resolve(null);
1357
+        } else {
1358
+            promise.reject("-1", res.toString());
1359
+        }
1360
+    }
1361
+
1362
+    @ReactMethod
1363
+    public void stopChannelMediaRelay(Promise promise) {
1364
+        Integer res = AgoraManager.getInstance().mRtcEngine.stopChannelMediaRelay();
1365
+        if (res == 0) {
1366
+            promise.resolve(null);
1367
+        } else {
1368
+            promise.reject("-1", res.toString());
1369
+        }
1370
+    }
1371
+
1242
     @ReactMethod
1372
     @ReactMethod
1243
     public void startPreview(Promise promise) {
1373
     public void startPreview(Promise promise) {
1244
         Integer res = AgoraManager.getInstance().startPreview();
1374
         Integer res = AgoraManager.getInstance().startPreview();
1385
     @ReactMethod
1515
     @ReactMethod
1386
     public void setCameraFocusPositionInPreview(ReadableMap options, Promise promise) {
1516
     public void setCameraFocusPositionInPreview(ReadableMap options, Promise promise) {
1387
         Integer res = AgoraManager.getInstance().mRtcEngine.setCameraFocusPositionInPreview(
1517
         Integer res = AgoraManager.getInstance().mRtcEngine.setCameraFocusPositionInPreview(
1388
-                    (float)options.getDouble("x"),
1389
-                    (float)options.getDouble("y")
1390
-            );
1518
+                (float)options.getDouble("x"),
1519
+                (float)options.getDouble("y")
1520
+        );
1391
         if (res == 0) {
1521
         if (res == 0) {
1392
             promise.resolve(null);
1522
             promise.resolve(null);
1393
         } else {
1523
         } else {
1560
     @ReactMethod
1690
     @ReactMethod
1561
     public void createDataStream(ReadableMap options, Promise promise) {
1691
     public void createDataStream(ReadableMap options, Promise promise) {
1562
         Integer res = AgoraManager.getInstance().mRtcEngine
1692
         Integer res = AgoraManager.getInstance().mRtcEngine
1563
-                    .createDataStream(
1564
-                            options.getBoolean("ordered"),
1565
-                            options.getBoolean("reliable")
1566
-                            );
1693
+                .createDataStream(
1694
+                        options.getBoolean("ordered"),
1695
+                        options.getBoolean("reliable")
1696
+                );
1567
         if (res == 0) {
1697
         if (res == 0) {
1568
             promise.resolve(null);
1698
             promise.resolve(null);
1569
         } else {
1699
         } else {
1631
     @ReactMethod
1761
     @ReactMethod
1632
     public void startAudioMixing(ReadableMap options, Promise promise) {
1762
     public void startAudioMixing(ReadableMap options, Promise promise) {
1633
         Integer res = AgoraManager.getInstance().mRtcEngine.startAudioMixing(
1763
         Integer res = AgoraManager.getInstance().mRtcEngine.startAudioMixing(
1634
-                    options.getString("filepath"),
1635
-                    options.getBoolean("loopback"),
1636
-                    options.getBoolean("replace"),
1637
-                    options.getInt("cycle")
1764
+                options.getString("filepath"),
1765
+                options.getBoolean("loopback"),
1766
+                options.getBoolean("replace"),
1767
+                options.getInt("cycle")
1638
         );
1768
         );
1639
         if (res == 0) {
1769
         if (res == 0) {
1640
             promise.resolve(null);
1770
             promise.resolve(null);
1756
     @ReactMethod
1886
     @ReactMethod
1757
     public void startAudioRecording(ReadableMap options, Promise promise) {
1887
     public void startAudioRecording(ReadableMap options, Promise promise) {
1758
         Integer res = AgoraManager.getInstance().mRtcEngine
1888
         Integer res = AgoraManager.getInstance().mRtcEngine
1759
-                    .startAudioRecording(
1760
-                            options.getString("filepath"),
1761
-                            options.getInt("quality")
1762
-        );
1889
+                .startAudioRecording(
1890
+                        options.getString("filepath"),
1891
+                        options.getInt("quality")
1892
+                );
1763
         if (res == 0) {
1893
         if (res == 0) {
1764
             promise.resolve(null);
1894
             promise.resolve(null);
1765
         } else {
1895
         } else {
1770
     @ReactMethod
1900
     @ReactMethod
1771
     public void stopAudioRecording(Promise promise) {
1901
     public void stopAudioRecording(Promise promise) {
1772
         Integer res = AgoraManager.getInstance().mRtcEngine
1902
         Integer res = AgoraManager.getInstance().mRtcEngine
1773
-                    .stopAudioRecording();
1903
+                .stopAudioRecording();
1774
         if (res == 0) {
1904
         if (res == 0) {
1775
             promise.resolve(null);
1905
             promise.resolve(null);
1776
         } else {
1906
         } else {
1781
     @ReactMethod
1911
     @ReactMethod
1782
     public void stopEchoTest(Promise promise) {
1912
     public void stopEchoTest(Promise promise) {
1783
         Integer res = AgoraManager.getInstance().mRtcEngine
1913
         Integer res = AgoraManager.getInstance().mRtcEngine
1784
-                    .stopEchoTest();
1914
+                .stopEchoTest();
1785
         if (res == 0) {
1915
         if (res == 0) {
1786
             promise.resolve(null);
1916
             promise.resolve(null);
1787
         } else {
1917
         } else {
1792
     @ReactMethod
1922
     @ReactMethod
1793
     public void enableLastmileTest(Promise promise) {
1923
     public void enableLastmileTest(Promise promise) {
1794
         Integer res = AgoraManager.getInstance().mRtcEngine
1924
         Integer res = AgoraManager.getInstance().mRtcEngine
1795
-                    .enableLastmileTest();
1925
+                .enableLastmileTest();
1796
         if (res == 0) {
1926
         if (res == 0) {
1797
             promise.resolve(null);
1927
             promise.resolve(null);
1798
         } else {
1928
         } else {
1803
     @ReactMethod
1933
     @ReactMethod
1804
     public void disableLastmileTest(Promise promise) {
1934
     public void disableLastmileTest(Promise promise) {
1805
         Integer res = AgoraManager.getInstance().mRtcEngine
1935
         Integer res = AgoraManager.getInstance().mRtcEngine
1806
-                    .disableLastmileTest();
1936
+                .disableLastmileTest();
1807
         if (res == 0) {
1937
         if (res == 0) {
1808
             promise.resolve(null);
1938
             promise.resolve(null);
1809
         } else {
1939
         } else {
1814
     @ReactMethod
1944
     @ReactMethod
1815
     public void setRecordingAudioFrameParameters(ReadableMap options, Promise promise) {
1945
     public void setRecordingAudioFrameParameters(ReadableMap options, Promise promise) {
1816
         Integer res = AgoraManager.getInstance().mRtcEngine
1946
         Integer res = AgoraManager.getInstance().mRtcEngine
1817
-                    .setRecordingAudioFrameParameters(
1818
-                            options.getInt("sampleRate"),
1819
-                            options.getInt("channel"),
1820
-                            options.getInt("mode"),
1821
-                            options.getInt("samplesPerCall")
1822
-        );
1947
+                .setRecordingAudioFrameParameters(
1948
+                        options.getInt("sampleRate"),
1949
+                        options.getInt("channel"),
1950
+                        options.getInt("mode"),
1951
+                        options.getInt("samplesPerCall")
1952
+                );
1823
         if (res == 0) {
1953
         if (res == 0) {
1824
             promise.resolve(null);
1954
             promise.resolve(null);
1825
         } else {
1955
         } else {
1830
     @ReactMethod
1960
     @ReactMethod
1831
     public void setPlaybackAudioFrameParameters(ReadableMap options, Promise promise) {
1961
     public void setPlaybackAudioFrameParameters(ReadableMap options, Promise promise) {
1832
         Integer res = AgoraManager.getInstance().mRtcEngine
1962
         Integer res = AgoraManager.getInstance().mRtcEngine
1833
-                    .setPlaybackAudioFrameParameters(
1834
-                            options.getInt("sampleRate"),
1835
-                            options.getInt("channel"),
1836
-                            options.getInt("mode"),
1837
-                            options.getInt("samplesPerCall")
1838
-        );
1963
+                .setPlaybackAudioFrameParameters(
1964
+                        options.getInt("sampleRate"),
1965
+                        options.getInt("channel"),
1966
+                        options.getInt("mode"),
1967
+                        options.getInt("samplesPerCall")
1968
+                );
1839
         if (res == 0) {
1969
         if (res == 0) {
1840
             promise.resolve(null);
1970
             promise.resolve(null);
1841
         } else {
1971
         } else {
1846
     @ReactMethod
1976
     @ReactMethod
1847
     public void setMixedAudioFrameParameters(WritableMap options, Promise promise) {
1977
     public void setMixedAudioFrameParameters(WritableMap options, Promise promise) {
1848
         Integer res = AgoraManager.getInstance().mRtcEngine
1978
         Integer res = AgoraManager.getInstance().mRtcEngine
1849
-                    .setMixedAudioFrameParameters(
1850
-                            options.getInt("sampleRate"),
1851
-                            options.getInt("samplesPerCall")
1852
-                    );
1979
+                .setMixedAudioFrameParameters(
1980
+                        options.getInt("sampleRate"),
1981
+                        options.getInt("samplesPerCall")
1982
+                );
1853
         if (res == 0) {
1983
         if (res == 0) {
1854
             promise.resolve(null);
1984
             promise.resolve(null);
1855
         } else {
1985
         } else {
1870
     @ReactMethod
2000
     @ReactMethod
1871
     public void addVideoWatermark(ReadableMap options, Promise promise) {
2001
     public void addVideoWatermark(ReadableMap options, Promise promise) {
1872
         Integer res = AgoraManager.getInstance().mRtcEngine
2002
         Integer res = AgoraManager.getInstance().mRtcEngine
1873
-                    .addVideoWatermark(createAgoraImage(options));
2003
+                .addVideoWatermark(createAgoraImage(options));
1874
         if (res == 0) {
2004
         if (res == 0) {
1875
             promise.resolve(null);
2005
             promise.resolve(null);
1876
         } else {
2006
         } else {
1881
     @ReactMethod
2011
     @ReactMethod
1882
     public void clearVideoWatermarks(Promise promise) {
2012
     public void clearVideoWatermarks(Promise promise) {
1883
         Integer res = AgoraManager.getInstance().mRtcEngine
2013
         Integer res = AgoraManager.getInstance().mRtcEngine
1884
-                    .clearVideoWatermarks();
2014
+                .clearVideoWatermarks();
1885
         if (res == 0) {
2015
         if (res == 0) {
1886
             promise.resolve(null);
2016
             promise.resolve(null);
1887
         } else {
2017
         } else {
1892
     @ReactMethod
2022
     @ReactMethod
1893
     public void setLocalPublishFallbackOption(int option, Promise promise) {
2023
     public void setLocalPublishFallbackOption(int option, Promise promise) {
1894
         Integer res = AgoraManager.getInstance().mRtcEngine
2024
         Integer res = AgoraManager.getInstance().mRtcEngine
1895
-                    .setLocalPublishFallbackOption(option);
2025
+                .setLocalPublishFallbackOption(option);
1896
         if (res == 0) {
2026
         if (res == 0) {
1897
             promise.resolve(null);
2027
             promise.resolve(null);
1898
         } else {
2028
         } else {
1903
     @ReactMethod
2033
     @ReactMethod
1904
     public void setRemoteSubscribeFallbackOption(int option, Promise promise) {
2034
     public void setRemoteSubscribeFallbackOption(int option, Promise promise) {
1905
         Integer res = AgoraManager.getInstance().mRtcEngine
2035
         Integer res = AgoraManager.getInstance().mRtcEngine
1906
-                    .setRemoteSubscribeFallbackOption(option);
2036
+                .setRemoteSubscribeFallbackOption(option);
1907
         if (res == 0) {
2037
         if (res == 0) {
1908
             promise.resolve(null);
2038
             promise.resolve(null);
1909
         } else {
2039
         } else {
1914
     @ReactMethod
2044
     @ReactMethod
1915
     public void enableDualStreamMode(boolean enabled, Promise promise) {
2045
     public void enableDualStreamMode(boolean enabled, Promise promise) {
1916
         Integer res = AgoraManager.getInstance().mRtcEngine
2046
         Integer res = AgoraManager.getInstance().mRtcEngine
1917
-                    .enableDualStreamMode(enabled);
2047
+                .enableDualStreamMode(enabled);
1918
         if (res == 0) {
2048
         if (res == 0) {
1919
             promise.resolve(null);
2049
             promise.resolve(null);
1920
         } else {
2050
         } else {
1926
     @ReactMethod
2056
     @ReactMethod
1927
     public void setRemoteVideoStreamType(ReadableMap options, Promise promise) {
2057
     public void setRemoteVideoStreamType(ReadableMap options, Promise promise) {
1928
         Integer res = AgoraManager.getInstance().mRtcEngine
2058
         Integer res = AgoraManager.getInstance().mRtcEngine
1929
-                    .setRemoteVideoStreamType(
1930
-                            options.getInt("uid"),
1931
-                            options.getInt("streamType")
1932
-                        );
2059
+                .setRemoteVideoStreamType(
2060
+                        options.getInt("uid"),
2061
+                        options.getInt("streamType")
2062
+                );
1933
         if (res == 0) {
2063
         if (res == 0) {
1934
             promise.resolve(null);
2064
             promise.resolve(null);
1935
         } else {
2065
         } else {
1940
     @ReactMethod
2070
     @ReactMethod
1941
     public void setRemoteDefaultVideoStreamType(ReadableMap options, Promise promise) {
2071
     public void setRemoteDefaultVideoStreamType(ReadableMap options, Promise promise) {
1942
         Integer res = AgoraManager.getInstance().mRtcEngine
2072
         Integer res = AgoraManager.getInstance().mRtcEngine
1943
-                    .setRemoteDefaultVideoStreamType(
1944
-                            options.getInt("streamType")
1945
-                    );
2073
+                .setRemoteDefaultVideoStreamType(
2074
+                        options.getInt("streamType")
2075
+                );
1946
         if (res == 0) {
2076
         if (res == 0) {
1947
             promise.resolve(null);
2077
             promise.resolve(null);
1948
         } else {
2078
         } else {
1972
         }
2102
         }
1973
     }
2103
     }
1974
 
2104
 
2105
+    private static boolean recording = false;
2106
+
2107
+    // TODO: need implementation
2108
+    @ReactMethod
2109
+    public void startAVRecording(final ReadableMap option, final Promise promise) {
2110
+        String path = option.getString("path");
2111
+        Integer uid = option.getInt("uid");
2112
+        String format = option.getString("format");
2113
+        if (true == recording) {
2114
+            promise.reject("-1", "recording already started");
2115
+        }
2116
+        SurfaceView view = AgoraManager.getInstance().getSurfaceView(uid);
2117
+        if (null == view) {
2118
+            promise.reject("-1", "recording already started");
2119
+        }
2120
+    }
2121
+
2122
+    // TODO: need implementation
2123
+    @ReactMethod
2124
+    public void stopAVRecording(final Promise promise) {
2125
+        if (false == recording) {
2126
+            promise.reject("-1", "recording didn't start");
2127
+        } else {
2128
+            promise.resolve(null);
2129
+        }
2130
+    }
2131
+
1975
     public LiveInjectStreamConfig.AudioSampleRateType getAudioSampleRateEnum (int val) {
2132
     public LiveInjectStreamConfig.AudioSampleRateType getAudioSampleRateEnum (int val) {
1976
         LiveInjectStreamConfig.AudioSampleRateType type = LiveInjectStreamConfig.AudioSampleRateType.TYPE_32000;
2133
         LiveInjectStreamConfig.AudioSampleRateType type = LiveInjectStreamConfig.AudioSampleRateType.TYPE_32000;
1977
         switch (Integer.valueOf(val)) {
2134
         switch (Integer.valueOf(val)) {
2065
     @ReactMethod
2222
     @ReactMethod
2066
     public void removeInjectStreamUrl(ReadableMap options, Promise promise) {
2223
     public void removeInjectStreamUrl(ReadableMap options, Promise promise) {
2067
         Integer res = AgoraManager.getInstance().mRtcEngine
2224
         Integer res = AgoraManager.getInstance().mRtcEngine
2068
-                    .removeInjectStreamUrl(options.getString("url"));
2225
+                .removeInjectStreamUrl(options.getString("url"));
2069
         if (res == 0) {
2226
         if (res == 0) {
2070
             promise.resolve(null);
2227
             promise.resolve(null);
2071
         } else {
2228
         } else {
2076
     @ReactMethod
2233
     @ReactMethod
2077
     public void addPublishStreamUrl(ReadableMap options, Promise promise) {
2234
     public void addPublishStreamUrl(ReadableMap options, Promise promise) {
2078
         Integer res = AgoraManager.getInstance().mRtcEngine
2235
         Integer res = AgoraManager.getInstance().mRtcEngine
2079
-                    .addPublishStreamUrl(
2080
-                            options.getString("url"),
2081
-                            options.getBoolean("enable")
2082
-                    );
2236
+                .addPublishStreamUrl(
2237
+                        options.getString("url"),
2238
+                        options.getBoolean("enable")
2239
+                );
2083
         if (res == 0) {
2240
         if (res == 0) {
2084
             promise.resolve(null);
2241
             promise.resolve(null);
2085
         } else {
2242
         } else {
2090
     @ReactMethod
2247
     @ReactMethod
2091
     public void removePublishStreamUrl(ReadableMap options, Promise promise) {
2248
     public void removePublishStreamUrl(ReadableMap options, Promise promise) {
2092
         Integer res = AgoraManager.getInstance().mRtcEngine
2249
         Integer res = AgoraManager.getInstance().mRtcEngine
2093
-                    .removePublishStreamUrl(options.getString("url"));
2250
+                .removePublishStreamUrl(options.getString("url"));
2094
         if (res == 0) {
2251
         if (res == 0) {
2095
             promise.resolve(null);
2252
             promise.resolve(null);
2096
         } else {
2253
         } else {
2222
     public void playEffect(ReadableMap options, Promise promise) {
2379
     public void playEffect(ReadableMap options, Promise promise) {
2223
         IAudioEffectManager manager = AgoraManager.getInstance().mRtcEngine.getAudioEffectManager();
2380
         IAudioEffectManager manager = AgoraManager.getInstance().mRtcEngine.getAudioEffectManager();
2224
         Integer res = manager.playEffect(
2381
         Integer res = manager.playEffect(
2225
-            options.getInt("soundid"),
2226
-            options.getString("filepath"),
2227
-            options.getInt("loopcount"),
2228
-            options.getDouble("pitch"),
2229
-            options.getDouble("pan"),
2230
-            options.getDouble("gain"),
2231
-            options.getBoolean("publish")
2382
+                options.getInt("soundid"),
2383
+                options.getString("filepath"),
2384
+                options.getInt("loopcount"),
2385
+                options.getDouble("pitch"),
2386
+                options.getDouble("pan"),
2387
+                options.getDouble("gain"),
2388
+                options.getBoolean("publish")
2232
         );
2389
         );
2233
         if (res == 0) {
2390
         if (res == 0) {
2234
             promise.resolve(null);
2391
             promise.resolve(null);

+ 53
- 5
android/src/main/java/com/syan/agora/AgoraVideoView.java View File

1
 package com.syan.agora;
1
 package com.syan.agora;
2
 
2
 
3
 import android.content.Context;
3
 import android.content.Context;
4
+import android.media.MediaCodec;
5
+import android.media.MediaCodecInfo;
6
+import android.media.MediaCodecList;
7
+import android.media.MediaFormat;
8
+import android.media.MediaMuxer;
9
+import android.os.Build;
10
+import android.support.annotation.RequiresApi;
4
 import android.util.AttributeSet;
11
 import android.util.AttributeSet;
5
-import android.view.SurfaceView;
12
+import android.util.Log;
6
 import android.view.View;
13
 import android.view.View;
7
 import android.widget.LinearLayout;
14
 import android.widget.LinearLayout;
8
 
15
 
9
-import io.agora.rtc.mediaio.AgoraSurfaceView;
16
+import com.syan.agora.media.MediaDataAudioObserver;
17
+import com.syan.agora.media.MediaDataVideoObserver;
18
+
19
+import java.io.IOException;
20
+import java.util.concurrent.ExecutorService;
21
+import java.util.concurrent.Executors;
22
+import java.util.concurrent.Future;
23
+
24
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
25
+import static android.media.MediaFormat.KEY_BIT_RATE;
26
+import static android.media.MediaFormat.KEY_COLOR_FORMAT;
27
+import static android.media.MediaFormat.KEY_FRAME_RATE;
28
+import static android.media.MediaFormat.KEY_I_FRAME_INTERVAL;
10
 
29
 
11
 /**
30
 /**
12
  * Created by DB on 2017/6/27.
31
  * Created by DB on 2017/6/27.
13
  */
32
  */
14
 
33
 
15
-public class AgoraVideoView extends LinearLayout {
34
+public class AgoraVideoView extends LinearLayout implements MediaDataAudioObserver, MediaDataVideoObserver {
35
+
16
     public boolean isShowLocalVideo() {
36
     public boolean isShowLocalVideo() {
17
         return showLocalVideo;
37
         return showLocalVideo;
18
     }
38
     }
27
 
47
 
28
     public void setRenderMode(Integer renderMode) {
48
     public void setRenderMode(Integer renderMode) {
29
         this.renderMode = renderMode;
49
         this.renderMode = renderMode;
30
-
31
     }
50
     }
32
 
51
 
33
     public Integer getRemoteUid() {
52
     public Integer getRemoteUid() {
50
     private Integer renderMode = 1;
69
     private Integer renderMode = 1;
51
     private Integer remoteUid;
70
     private Integer remoteUid;
52
     private boolean zOrderMediaOverlay;
71
     private boolean zOrderMediaOverlay;
53
-    private SurfaceView surfaceView;
54
 
72
 
55
     public AgoraVideoView(Context context) {
73
     public AgoraVideoView(Context context) {
56
         super(context);
74
         super(context);
75
             }
93
             }
76
         }
94
         }
77
     }
95
     }
96
+
97
+    @Override
98
+    public void onRecordAudioFrame(byte[] data, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
99
+
100
+    }
101
+
102
+    @Override
103
+    public void onPlaybackAudioFrame(byte[] data, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
104
+
105
+    }
106
+
107
+    @Override
108
+    public void onPlaybackAudioFrameBeforeMixing(int uid, byte[] data, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
109
+
110
+    }
111
+
112
+    @Override
113
+    public void onMixedAudioFrame(byte[] data, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
114
+
115
+    }
116
+
117
+    @Override
118
+    public void onCaptureVideoFrame(byte[] data, int frameType, int width, int height, int bufferLength, int yStride, int uStride, int vStride, int rotation, long renderTimeMs) {
119
+
120
+    }
121
+
122
+    @Override
123
+    public void onRenderVideoFrame(int uid, byte[] data, int frameType, int width, int height, int bufferLength, int yStride, int uStride, int vStride, int rotation, long renderTimeMs) {
124
+
125
+    }
78
 }
126
 }

+ 29
- 0
android/src/main/java/com/syan/agora/media/DecodeDataBuffer.java View File

1
+package com.syan.agora.media;
2
+
3
+import java.nio.ByteBuffer;
4
+
5
+public class DecodeDataBuffer {
6
+    private int uid;
7
+    private ByteBuffer byteBuffer;
8
+
9
+    public DecodeDataBuffer(int uid, ByteBuffer byteBuffer) {
10
+        this.uid = uid;
11
+        this.byteBuffer = byteBuffer;
12
+    }
13
+
14
+    public int getUid() {
15
+        return uid;
16
+    }
17
+
18
+    public void setUid(int uid) {
19
+        this.uid = uid;
20
+    }
21
+
22
+    public ByteBuffer getByteBuffer() {
23
+        return byteBuffer;
24
+    }
25
+
26
+    public void setByteBuffer(ByteBuffer byteBuffer) {
27
+        this.byteBuffer = byteBuffer;
28
+    }
29
+}

+ 13
- 0
android/src/main/java/com/syan/agora/media/MediaDataAudioObserver.java View File

1
+
2
+package com.syan.agora.media;
3
+
4
+public interface MediaDataAudioObserver {
5
+
6
+    void onRecordAudioFrame(byte[] data, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength);
7
+
8
+    void onPlaybackAudioFrame(byte[] data, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength);
9
+
10
+    void onPlaybackAudioFrameBeforeMixing(int uid, byte[] data,int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength);
11
+
12
+    void onMixedAudioFrame(byte[] data,int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength);
13
+}

+ 297
- 0
android/src/main/java/com/syan/agora/media/MediaDataObserverPlugin.java View File

1
+package com.syan.agora.media;
2
+
3
+import android.graphics.Bitmap;
4
+import android.graphics.BitmapFactory;
5
+import android.graphics.ImageFormat;
6
+import android.graphics.Matrix;
7
+import android.graphics.Rect;
8
+import android.graphics.YuvImage;
9
+
10
+import java.io.ByteArrayOutputStream;
11
+import java.io.File;
12
+import java.io.FileNotFoundException;
13
+import java.io.FileOutputStream;
14
+import java.io.IOException;
15
+import java.nio.ByteBuffer;
16
+import java.util.ArrayList;
17
+import java.util.Iterator;
18
+import java.util.concurrent.CopyOnWriteArrayList;
19
+
20
+public class MediaDataObserverPlugin implements MediaPreProcessing.ProgressCallback {
21
+
22
+    private final CopyOnWriteArrayList<MediaDataVideoObserver> videoObserverList = new CopyOnWriteArrayList<>();
23
+    private final CopyOnWriteArrayList<MediaDataAudioObserver> audioObserverList = new CopyOnWriteArrayList<>();
24
+
25
+    private static final int VIDEO_DEFAULT_BUFFER_SIZE = 3240 * 1080; // default maximum video size Full HD+
26
+    private static final int AUDIO_DEFAULT_BUFFER_SIZE = 2048;
27
+
28
+    public ByteBuffer byteBufferCapture = ByteBuffer.allocateDirect(VIDEO_DEFAULT_BUFFER_SIZE);
29
+    public ByteBuffer byteBufferRender = ByteBuffer.allocateDirect(VIDEO_DEFAULT_BUFFER_SIZE);
30
+    public ByteBuffer byteBufferAudioRecord = ByteBuffer.allocateDirect(AUDIO_DEFAULT_BUFFER_SIZE);
31
+    public ByteBuffer byteBufferAudioPlay = ByteBuffer.allocateDirect(AUDIO_DEFAULT_BUFFER_SIZE);
32
+    public ByteBuffer byteBufferBeforeAudioMix = ByteBuffer.allocateDirect(AUDIO_DEFAULT_BUFFER_SIZE);
33
+    public ByteBuffer byteBufferAudioMix = ByteBuffer.allocateDirect(AUDIO_DEFAULT_BUFFER_SIZE);
34
+
35
+    private final ArrayList<DecodeDataBuffer> decodeBufferList = new ArrayList<>();
36
+
37
+    private static MediaDataObserverPlugin myAgent = null;
38
+
39
+    private boolean beCaptureVideoShot = false;
40
+    private boolean beRenderVideoShot = false;
41
+    private String captureFilePath = null;
42
+    private String renderFilePath = null;
43
+    private int renderVideoShotUid;
44
+
45
+    public static MediaDataObserverPlugin the() {
46
+        if (myAgent == null) {
47
+            synchronized (MediaDataObserverPlugin.class) {
48
+                if (myAgent == null)
49
+                    myAgent = new MediaDataObserverPlugin();
50
+            }
51
+        }
52
+        return myAgent;
53
+    }
54
+
55
+    public void addVideoObserver(MediaDataVideoObserver observer) {
56
+        videoObserverList.add(observer);
57
+    }
58
+
59
+    public void removeVideoObserver(MediaDataVideoObserver observer) {
60
+        videoObserverList.remove(observer);
61
+    }
62
+
63
+    public void addAudioObserver(MediaDataAudioObserver observer) {
64
+        audioObserverList.add(observer);
65
+    }
66
+
67
+    public void removeAudioObserver(MediaDataAudioObserver observer) {
68
+        audioObserverList.remove(observer);
69
+    }
70
+
71
+    public void saveCaptureVideoSnapshot(String filePath) {
72
+        beCaptureVideoShot = true;
73
+        captureFilePath = filePath;
74
+    }
75
+
76
+    public void saveRenderVideoSnapshot(String filePath, int uid) {
77
+        beRenderVideoShot = true;
78
+        renderFilePath = filePath;
79
+        renderVideoShotUid = uid;
80
+    }
81
+
82
+    public void addDecodeBuffer(int uid) {
83
+        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(VIDEO_DEFAULT_BUFFER_SIZE);
84
+        decodeBufferList.add(new DecodeDataBuffer(uid, byteBuffer));
85
+        MediaPreProcessing.setVideoDecodeByteBuffer(uid, byteBuffer);
86
+    }
87
+
88
+    public void removeDecodeBuffer(int uid) {
89
+        Iterator<DecodeDataBuffer> it = decodeBufferList.iterator();
90
+        while (it.hasNext()) {
91
+            DecodeDataBuffer buffer = it.next();
92
+            if (buffer.getUid() == uid) {
93
+                it.remove();
94
+            }
95
+        }
96
+
97
+        MediaPreProcessing.setVideoDecodeByteBuffer(uid, null);
98
+    }
99
+
100
+    public void removeAllBuffer() {
101
+        decodeBufferList.removeAll(decodeBufferList);
102
+        releaseBuffer();
103
+    }
104
+
105
+    @Override
106
+    public void onCaptureVideoFrame(int videoFrameType, int width, int height, int bufferLength, int yStride, int uStride, int vStride, int rotation, long renderTimeMs) {
107
+
108
+        byte[] buf = new byte[bufferLength];
109
+        byteBufferCapture.limit(bufferLength);
110
+        byteBufferCapture.get(buf);
111
+        byteBufferCapture.flip();
112
+
113
+        for (MediaDataVideoObserver observer : videoObserverList) {
114
+            observer.onCaptureVideoFrame(buf, videoFrameType, width, height, bufferLength, yStride, uStride, vStride, rotation, renderTimeMs);
115
+        }
116
+
117
+        byteBufferCapture.put(buf);
118
+        byteBufferCapture.flip();
119
+
120
+        if (beCaptureVideoShot) {
121
+            beCaptureVideoShot = false;
122
+
123
+            getVideoSnapshot(width, height, rotation, bufferLength, buf, captureFilePath, yStride, uStride, vStride);
124
+        }
125
+    }
126
+
127
+    @Override
128
+    public void onRenderVideoFrame(int uid, int videoFrameType, int width, int height, int bufferLength, int yStride, int uStride, int vStride, int rotation, long renderTimeMs) {
129
+
130
+        for (MediaDataVideoObserver observer : videoObserverList) {
131
+            Iterator<DecodeDataBuffer> it = decodeBufferList.iterator();
132
+            while (it.hasNext()) {
133
+                DecodeDataBuffer tmp = it.next();
134
+                if (tmp.getUid() == uid) {
135
+                    byte[] buf = new byte[bufferLength];
136
+                    tmp.getByteBuffer().limit(bufferLength);
137
+                    tmp.getByteBuffer().get(buf);
138
+                    tmp.getByteBuffer().flip();
139
+
140
+                    observer.onRenderVideoFrame(uid, buf, videoFrameType, width, height, bufferLength, yStride, uStride, vStride, rotation, renderTimeMs);
141
+
142
+                    tmp.getByteBuffer().put(buf);
143
+                    tmp.getByteBuffer().flip();
144
+
145
+                    if (beRenderVideoShot) {
146
+                        if (uid == renderVideoShotUid) {
147
+                            beRenderVideoShot = false;
148
+
149
+                            getVideoSnapshot(width, height, rotation, bufferLength, buf, renderFilePath, yStride, uStride, vStride);
150
+                        }
151
+                    }
152
+                }
153
+            }
154
+        }
155
+    }
156
+
157
+    @Override
158
+    public void onRecordAudioFrame(int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
159
+        byte[] buf = new byte[bufferLength];
160
+        byteBufferAudioRecord.limit(bufferLength);
161
+        byteBufferAudioRecord.get(buf);
162
+        byteBufferAudioRecord.flip();
163
+
164
+        for (MediaDataAudioObserver observer : audioObserverList) {
165
+            observer.onRecordAudioFrame(buf, audioFrameType, samples, bytesPerSample, channels, samplesPerSec, renderTimeMs, bufferLength);
166
+        }
167
+
168
+        byteBufferAudioRecord.put(buf);
169
+        byteBufferAudioRecord.flip();
170
+    }
171
+
172
+    @Override
173
+    public void onPlaybackAudioFrame(int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
174
+        byte[] buf = new byte[bufferLength];
175
+        byteBufferAudioPlay.limit(bufferLength);
176
+        byteBufferAudioPlay.get(buf);
177
+        byteBufferAudioPlay.flip();
178
+
179
+        for (MediaDataAudioObserver observer : audioObserverList) {
180
+            observer.onPlaybackAudioFrame(buf, audioFrameType, samples, bytesPerSample, channels, samplesPerSec, renderTimeMs, bufferLength);
181
+        }
182
+
183
+        byteBufferAudioPlay.put(buf);
184
+        byteBufferAudioPlay.flip();
185
+    }
186
+
187
+    @Override
188
+    public void onPlaybackAudioFrameBeforeMixing(int uid, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
189
+        byte[] buf = new byte[bufferLength];
190
+        byteBufferBeforeAudioMix.limit(bufferLength);
191
+        byteBufferBeforeAudioMix.get(buf);
192
+        byteBufferBeforeAudioMix.flip();
193
+
194
+        for (MediaDataAudioObserver observer : audioObserverList) {
195
+            observer.onPlaybackAudioFrameBeforeMixing(uid, buf, audioFrameType, samples, bytesPerSample, channels, samplesPerSec, renderTimeMs, bufferLength);
196
+        }
197
+
198
+        byteBufferBeforeAudioMix.put(buf);
199
+        byteBufferBeforeAudioMix.flip();
200
+    }
201
+
202
+    @Override
203
+    public void onMixedAudioFrame(int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
204
+        byte[] buf = new byte[bufferLength];
205
+        byteBufferAudioMix.limit(bufferLength);
206
+        byteBufferAudioMix.get(buf);
207
+        byteBufferAudioMix.flip();
208
+
209
+        for (MediaDataAudioObserver observer : audioObserverList) {
210
+            observer.onMixedAudioFrame(buf, audioFrameType, samples, bytesPerSample, channels, samplesPerSec, renderTimeMs, bufferLength);
211
+        }
212
+
213
+        byteBufferAudioMix.put(buf);
214
+        byteBufferAudioMix.flip();
215
+    }
216
+
217
+    private void getVideoSnapshot(int width, int height, int rotation, int bufferLength, byte[] buffer, String filePath, int yStride, int uStride, int vStride) {
218
+        File file = new File(filePath);
219
+
220
+        byte[] NV21 = new byte[bufferLength];
221
+        swapYU12toYUV420SemiPlanar(buffer, NV21, width, height, yStride, uStride, vStride);
222
+
223
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
224
+
225
+        int[] strides = {yStride, yStride};
226
+        YuvImage image = new YuvImage(NV21, ImageFormat.NV21, width, height, strides);
227
+
228
+        image.compressToJpeg(
229
+                new Rect(0, 0, image.getWidth(), image.getHeight()),
230
+                100, baos);
231
+
232
+        // rotate picture when saving to file
233
+        Matrix matrix = new Matrix();
234
+        matrix.postRotate(rotation);
235
+        byte[] bytes = baos.toByteArray();
236
+        try {
237
+            baos.close();
238
+        } catch (IOException e) {
239
+            e.printStackTrace();
240
+        }
241
+        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
242
+        Bitmap target = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
243
+
244
+        File fileParent = file.getParentFile();
245
+        if (!fileParent.exists()) {
246
+            fileParent.mkdirs();
247
+        }
248
+        if (file.exists()) {
249
+            file.delete();
250
+        }
251
+
252
+        try {
253
+            file.createNewFile();
254
+        } catch (IOException e) {
255
+            e.printStackTrace();
256
+        }
257
+
258
+        FileOutputStream fos = null;
259
+        try {
260
+            fos = new FileOutputStream(file);
261
+        } catch (FileNotFoundException e) {
262
+            e.printStackTrace();
263
+        }
264
+
265
+        target.compress(Bitmap.CompressFormat.JPEG, 100, fos);
266
+
267
+        target.recycle();
268
+        bitmap.recycle();
269
+
270
+        try {
271
+            fos.close();
272
+        } catch (IOException e) {
273
+            e.printStackTrace();
274
+        }
275
+    }
276
+
277
+    private void swapYU12toYUV420SemiPlanar(byte[] yu12bytes, byte[] i420bytes, int width, int height, int yStride, int uStride, int vStride) {
278
+        System.arraycopy(yu12bytes, 0, i420bytes, 0, yStride * height);
279
+        int startPos = yStride * height;
280
+        int yv_start_pos_u = startPos;
281
+        int yv_start_pos_v = startPos + startPos / 4;
282
+        for (int i = 0; i < startPos / 4; i++) {
283
+            i420bytes[startPos + 2 * i + 0] = yu12bytes[yv_start_pos_v + i];
284
+            i420bytes[startPos + 2 * i + 1] = yu12bytes[yv_start_pos_u + i];
285
+        }
286
+    }
287
+
288
+    public void releaseBuffer() {
289
+        byteBufferCapture.clear();
290
+        byteBufferRender.clear();
291
+        byteBufferAudioRecord.clear();
292
+        byteBufferAudioPlay.clear();
293
+        byteBufferBeforeAudioMix.clear();
294
+        byteBufferAudioMix.clear();
295
+    }
296
+
297
+}

+ 8
- 0
android/src/main/java/com/syan/agora/media/MediaDataVideoObserver.java View File

1
+package com.syan.agora.media;
2
+
3
+public interface MediaDataVideoObserver {
4
+
5
+    void onCaptureVideoFrame(byte[] data, int frameType, int width, int height, int bufferLength, int yStride, int uStride, int vStride, int rotation, long renderTimeMs);
6
+
7
+    void onRenderVideoFrame(int uid, byte[] data, int frameType, int width, int height, int bufferLength, int yStride, int uStride, int vStride, int rotation, long renderTimeMs);
8
+}

+ 39
- 0
android/src/main/java/com/syan/agora/media/MediaPreProcessing.java View File

1
+package com.syan.agora.media;
2
+
3
+import java.nio.ByteBuffer;
4
+
5
+public class MediaPreProcessing {
6
+    static {
7
+        System.loadLibrary("apm-plugin-raw-data-api-java");
8
+    }
9
+
10
+    public interface ProgressCallback {
11
+        void onCaptureVideoFrame(int videoFrameType, int width, int height, int bufferLength, int yStride, int uStride, int vStride, int rotation, long renderTimeMs);
12
+
13
+        void onRenderVideoFrame(int uid, int videoFrameType, int width, int height, int bufferLength, int yStride, int uStride, int vStride, int rotation, long renderTimeMs);
14
+
15
+        void onRecordAudioFrame(int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength);
16
+
17
+        void onPlaybackAudioFrame(int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength);
18
+
19
+        void onPlaybackAudioFrameBeforeMixing(int uid, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength);
20
+
21
+        void onMixedAudioFrame(int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength);
22
+    }
23
+
24
+    public static native void setCallback(ProgressCallback callback);
25
+
26
+    public static native void setVideoCaptureByteBuffer(ByteBuffer byteBuffer);
27
+
28
+    public static native void setAudioRecordByteBuffer(ByteBuffer byteBuffer);
29
+
30
+    public static native void setAudioPlayByteBuffer(ByteBuffer byteBuffer);
31
+
32
+    public static native void setBeforeAudioMixByteBuffer(ByteBuffer byteBuffer);
33
+
34
+    public static native void setAudioMixByteBuffer(ByteBuffer byteBuffer);
35
+
36
+    public static native void setVideoDecodeByteBuffer(int uid, ByteBuffer byteBuffer);
37
+
38
+    public static native void releasePoint();
39
+}

+ 6
- 7
ios/RCTAgora/AgoraConst.h View File

28
 static NSString *AGTokenPrivilegeWillExpire = @"tokenPrivilegeWillExpire";
28
 static NSString *AGTokenPrivilegeWillExpire = @"tokenPrivilegeWillExpire";
29
 static NSString *AGRequestToken = @"requestToken";
29
 static NSString *AGRequestToken = @"requestToken";
30
 
30
 
31
-static NSString *AGMicrophoneEnabled = @"microphoneEnabled";
31
+static NSString *AGLocalAudioStateChanged = @"localAudioStateChanged";
32
+static NSString *AGRemoteAudioStateChanged = @"remoteAudioStateChanged";
33
+static NSString *AGLocalAudioStats = @"localAudioStats";
32
 static NSString *AGAudioVolumeIndication = @"audioVolumeIndication";
34
 static NSString *AGAudioVolumeIndication = @"audioVolumeIndication";
33
 static NSString *AGActiveSpeaker = @"activeSpeaker";
35
 static NSString *AGActiveSpeaker = @"activeSpeaker";
34
 static NSString *AGFirstLocalAudioFrame = @"firstLocalAudioFrame";
36
 static NSString *AGFirstLocalAudioFrame = @"firstLocalAudioFrame";
35
 static NSString *AGFirstRemoteAudioFrame = @"firstRemoteAudioFrame";
37
 static NSString *AGFirstRemoteAudioFrame = @"firstRemoteAudioFrame";
36
 static NSString *AGFirstRemoteAudioDecoded = @"firstRemoteAudioDecoded";
38
 static NSString *AGFirstRemoteAudioDecoded = @"firstRemoteAudioDecoded";
37
 static NSString *AGFirstLocalVideoFrame = @"firstLocalVideoFrame";
39
 static NSString *AGFirstLocalVideoFrame = @"firstLocalVideoFrame";
38
-static NSString *AGFirstRemoteVideoDecoded = @"firstRemoteVideoDecoded";
39
 static NSString *AGFirstRemoteVideoFrame = @"firstRemoteVideoFrame";
40
 static NSString *AGFirstRemoteVideoFrame = @"firstRemoteVideoFrame";
40
 static NSString *AGUserMuteAudio = @"userMuteAudio";
41
 static NSString *AGUserMuteAudio = @"userMuteAudio";
41
-static NSString *AGUserMuteVideo = @"userMuteVideo";
42
-static NSString *AGUserEnableVideo = @"userEnableVideo";
43
-static NSString *AGUserEnableLocalVideo = @"userEnableLocalVideo";
44
 static NSString *AGVideoSizeChanged = @"videoSizeChanged";
42
 static NSString *AGVideoSizeChanged = @"videoSizeChanged";
45
 static NSString *AGRemoteVideoStateChanged = @"remoteVideoStateChanged";
43
 static NSString *AGRemoteVideoStateChanged = @"remoteVideoStateChanged";
46
 static NSString *AGLocalPublishFallbackToAudioOnly = @"localPublishFallbackToAudioOnly";
44
 static NSString *AGLocalPublishFallbackToAudioOnly = @"localPublishFallbackToAudioOnly";
56
 static NSString *AGLocalVideoStats = @"localVideoStats";
54
 static NSString *AGLocalVideoStats = @"localVideoStats";
57
 static NSString *AGRemoteVideoStats = @"remoteVideoStats";
55
 static NSString *AGRemoteVideoStats = @"remoteVideoStats";
58
 static NSString *AGRemoteAudioStats = @"remoteAudioStats";
56
 static NSString *AGRemoteAudioStats = @"remoteAudioStats";
59
-static NSString *AGAudioTransportStatsOfUid = @"audioTransportStatsOfUid";
60
-static NSString *AGVideoTransportStatsOfUid = @"videoTransportStatsOfUid";
61
 
57
 
62
 static NSString *AGRemoteAudioMixingStart = @"remoteAudioMixingStart";
58
 static NSString *AGRemoteAudioMixingStart = @"remoteAudioMixingStart";
63
 static NSString *AGRemoteAudioMixingFinish = @"remoteAudioMixingFinish";
59
 static NSString *AGRemoteAudioMixingFinish = @"remoteAudioMixingFinish";
72
 static NSString *AGReceiveStreamMessage = @"receiveStreamMessage";
68
 static NSString *AGReceiveStreamMessage = @"receiveStreamMessage";
73
 static NSString *AGOccurStreamMessageError = @"occurStreamMessageError";
69
 static NSString *AGOccurStreamMessageError = @"occurStreamMessageError";
74
 
70
 
71
+static NSString *AGReceivedChannelMediaRelay = @"receivedChannelMediaRelay";
72
+static NSString *AGMediaRelayStateChanged = @"mediaRelayStateChanged";
73
+
75
 static NSString *AGMediaEngineLoaded = @"mediaEngineLoaded";
74
 static NSString *AGMediaEngineLoaded = @"mediaEngineLoaded";
76
 static NSString *AGMediaEngineStartCall = @"mediaEngineStartCall";
75
 static NSString *AGMediaEngineStartCall = @"mediaEngineStartCall";
77
 
76
 

+ 5
- 7
ios/RCTAgora/AgoraConst.m View File

44
                                   AGTokenPrivilegeWillExpire,
44
                                   AGTokenPrivilegeWillExpire,
45
                                   AGRequestToken,
45
                                   AGRequestToken,
46
                                   
46
                                   
47
-                                  AGMicrophoneEnabled,
48
                                   AGAudioVolumeIndication,
47
                                   AGAudioVolumeIndication,
49
                                   AGActiveSpeaker,
48
                                   AGActiveSpeaker,
50
                                   AGFirstLocalAudioFrame,
49
                                   AGFirstLocalAudioFrame,
51
                                   AGFirstRemoteAudioFrame,
50
                                   AGFirstRemoteAudioFrame,
52
                                   AGFirstRemoteAudioDecoded,
51
                                   AGFirstRemoteAudioDecoded,
53
                                   AGFirstLocalVideoFrame,
52
                                   AGFirstLocalVideoFrame,
54
-                                  AGFirstRemoteVideoDecoded,
55
                                   AGFirstRemoteVideoFrame,
53
                                   AGFirstRemoteVideoFrame,
56
                                   AGUserMuteAudio,
54
                                   AGUserMuteAudio,
57
-                                  AGUserMuteVideo,
58
-                                  AGUserEnableVideo,
59
-                                  AGUserEnableLocalVideo,
60
                                   AGVideoSizeChanged,
55
                                   AGVideoSizeChanged,
61
                                   AGRemoteVideoStateChanged,
56
                                   AGRemoteVideoStateChanged,
62
                                   AGLocalPublishFallbackToAudioOnly,
57
                                   AGLocalPublishFallbackToAudioOnly,
72
                                   AGLocalVideoStats,
67
                                   AGLocalVideoStats,
73
                                   AGRemoteVideoStats,
68
                                   AGRemoteVideoStats,
74
                                   AGRemoteAudioStats,
69
                                   AGRemoteAudioStats,
75
-                                  AGAudioTransportStatsOfUid,
76
-                                  AGVideoTransportStatsOfUid,
70
+                                  AGLocalAudioStateChanged,
71
+                                  AGRemoteAudioStateChanged,
72
+                                  AGLocalAudioStats,
73
+                                  AGMediaRelayStateChanged,
74
+                                  AGReceivedChannelMediaRelay,
77
                                   
75
                                   
78
                                   AGAudioMixingStateChanged,
76
                                   AGAudioMixingStateChanged,
79
                                   AGRemoteAudioMixingStart,
77
                                   AGRemoteAudioMixingStart,

+ 189
- 83
ios/RCTAgora/RCTAgora.m View File

48
   return toSend;
48
   return toSend;
49
 }
49
 }
50
 
50
 
51
-- (void)receiveMetadata:(NSData *_Nonnull)data fromUser:(NSUInteger)uid atTimestamp:(NSTimeInterval)timestamp {
51
+- (void)receiveMetadata:(NSData *_Nonnull)data fromUser:(NSInteger)uid atTimestamp:(NSTimeInterval)timestamp {
52
   NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
52
   NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
53
   [self sendEvent:AGMediaMetaDataReceived params:@{
53
   [self sendEvent:AGMediaMetaDataReceived params:@{
54
                                                    @"uid": @(uid),
54
                                                    @"uid": @(uid),
301
   }
301
   }
302
 }
302
 }
303
 
303
 
304
+// switch channel
305
+RCT_EXPORT_METHOD(switchChannel:(NSDictionary *)options
306
+                  resolve:(RCTPromiseResolveBlock)resolve
307
+                  reject:(RCTPromiseRejectBlock)reject) {
308
+  NSInteger res = [self.rtcEngine switchChannelByToken:options[@"token"] channelId:options[@"channelName"] joinSuccess:nil];
309
+  if (res == 0) {
310
+    resolve(nil);
311
+  } else {
312
+    reject(@(-1).stringValue, @(res).stringValue, nil);
313
+  }
314
+}
315
+
316
+// startChannelMediaRelay
317
+RCT_EXPORT_METHOD(startChannelMediaRelay:(NSDictionary *)options
318
+                  resolve:(RCTPromiseResolveBlock)resolve
319
+                  reject:(RCTPromiseRejectBlock)reject) {
320
+  AgoraChannelMediaRelayConfiguration *config = [[AgoraChannelMediaRelayConfiguration alloc] init];
321
+  AgoraChannelMediaRelayInfo *src = [config sourceInfo];
322
+  NSDictionary *srcOption = options[@"src"];
323
+  if (srcOption != nil) {
324
+    src.channelName = srcOption[@"channelName"];
325
+    src.uid = [srcOption[@"uid"] integerValue];
326
+    src.token = srcOption[@"token"];
327
+  }
328
+  NSArray *channels = options[@"channels"];
329
+  for (NSDictionary *channel in channels) {
330
+    AgoraChannelMediaRelayInfo *dst = [[AgoraChannelMediaRelayInfo alloc] init];
331
+    dst.channelName = channel[@"channelName"];
332
+    dst.uid = [channel[@"uid"] integerValue];
333
+    dst.token = channel[@"token"];
334
+    [config setDestinationInfo:dst forChannelName:dst.channelName];
335
+  }
336
+  NSInteger res = [self.rtcEngine startChannelMediaRelay:config];
337
+  if (res == 0) {
338
+    resolve(nil);
339
+  } else {
340
+    reject(@(-1).stringValue, @(res).stringValue, nil);
341
+  }
342
+}
343
+
344
+// updateChannelMediaRelay
345
+RCT_EXPORT_METHOD(updateChannelMediaRelay:(NSDictionary *)options
346
+                  resolve:(RCTPromiseResolveBlock)resolve
347
+                  reject:(RCTPromiseRejectBlock)reject) {
348
+  AgoraChannelMediaRelayConfiguration *config = [[AgoraChannelMediaRelayConfiguration alloc] init];
349
+  AgoraChannelMediaRelayInfo *src = [config sourceInfo];
350
+  NSDictionary *srcOption = options[@"src"];
351
+  if (srcOption != nil) {
352
+    src.channelName = srcOption[@"channelName"];
353
+    src.uid = [srcOption[@"uid"] integerValue];
354
+    src.token = srcOption[@"token"];
355
+  }
356
+  NSArray *channels = options[@"channels"];
357
+  for (NSDictionary *channel in channels) {
358
+    AgoraChannelMediaRelayInfo *dst = [[AgoraChannelMediaRelayInfo alloc] init];
359
+    dst.channelName = channel[@"channelName"];
360
+    dst.uid = [channel[@"uid"] integerValue];
361
+    dst.token = channel[@"token"];
362
+    [config setDestinationInfo:dst forChannelName:dst.channelName];
363
+  }
364
+  NSInteger res = [self.rtcEngine updateChannelMediaRelay:config];
365
+  if (res == 0) {
366
+    resolve(nil);
367
+  } else {
368
+    reject(@(-1).stringValue, @(res).stringValue, nil);
369
+  }
370
+}
371
+
372
+// removeChannelMediaRelay
373
+RCT_EXPORT_METHOD(removeChannelMediaRelay:(NSDictionary *)options
374
+                  resolve:(RCTPromiseResolveBlock)resolve
375
+                  reject:(RCTPromiseRejectBlock)reject) {
376
+  AgoraChannelMediaRelayConfiguration *config = [[AgoraChannelMediaRelayConfiguration alloc] init];
377
+  AgoraChannelMediaRelayInfo *src = [config sourceInfo];
378
+  NSDictionary *srcOption = options[@"src"];
379
+  if (srcOption != nil) {
380
+    src.channelName = srcOption[@"channelName"];
381
+    src.uid = [srcOption[@"uid"] integerValue];
382
+    src.token = srcOption[@"token"];
383
+  }
384
+  NSArray *channels = options[@"channels"];
385
+  for (NSDictionary *channel in channels) {
386
+    if (channel[@"channelName"] != nil) {
387
+      [config removeDestinationInfoForChannelName:channel[@"channelName"]];
388
+    }
389
+  }
390
+  NSInteger res = [self.rtcEngine updateChannelMediaRelay:config];
391
+  if (res == 0) {
392
+    resolve(nil);
393
+  } else {
394
+    reject(@(-1).stringValue, @(res).stringValue, nil);
395
+  }
396
+}
397
+
398
+// stopChannelMediaRelay
399
+RCT_EXPORT_METHOD(stopChannelMediaRelay:(RCTPromiseResolveBlock)resolve
400
+                  reject:(RCTPromiseRejectBlock)reject) {
401
+  NSInteger res = [self.rtcEngine stopChannelMediaRelay];
402
+  if (res == 0) {
403
+    resolve(nil);
404
+  } else {
405
+    reject(@(-1).stringValue, @(res).stringValue, nil);
406
+  }
407
+}
408
+
304
 // register user account
409
 // register user account
305
 RCT_EXPORT_METHOD(registerLocalUserAccount:(NSDictionary *)options
410
 RCT_EXPORT_METHOD(registerLocalUserAccount:(NSDictionary *)options
306
                   resolve:(RCTPromiseResolveBlock)resolve
411
                   resolve:(RCTPromiseResolveBlock)resolve
334
   AgoraUserInfo *info = [self.rtcEngine getUserInfoByUid:uid withError:&code];
439
   AgoraUserInfo *info = [self.rtcEngine getUserInfoByUid:uid withError:&code];
335
   if ((int)code == 0) {
440
   if ((int)code == 0) {
336
     resolve(@{
441
     resolve(@{
337
-        @"uid": @(info.uid),
338
-        @"userAccount": info.userAccount
339
-    });
442
+              @"uid": @(info.uid),
443
+              @"userAccount": info.userAccount
444
+              });
340
   } else {
445
   } else {
341
     reject(@(-1).stringValue, @((int)code).stringValue, nil);
446
     reject(@(-1).stringValue, @((int)code).stringValue, nil);
342
   }
447
   }
362
 RCT_EXPORT_METHOD(leaveChannel
467
 RCT_EXPORT_METHOD(leaveChannel
363
                   :(RCTPromiseResolveBlock) resolve
468
                   :(RCTPromiseResolveBlock) resolve
364
                   reject:(RCTPromiseRejectBlock) reject) {
469
                   reject:(RCTPromiseRejectBlock) reject) {
365
-  NSInteger res = [self.rtcEngine leaveChannel:^(AgoraChannelStats * _Nonnull stat) {
470
+  NSInteger res = [self.rtcEngine leaveChannel:^(AgoraChannelStats * _Nonnull stats) {
366
     [self sendEvent:AGLeaveChannel params:@{
471
     [self sendEvent:AGLeaveChannel params:@{
367
                                             @"message": @"leaveChannel",
472
                                             @"message": @"leaveChannel",
368
-                                            @"duration": @(stat.duration),
369
-                                            @"txBytes": @(stat.txBytes),
370
-                                            @"rxBytes": @(stat.rxBytes),
371
-                                            @"txAudioKBitrate": @(stat.txAudioKBitrate),
372
-                                            @"rxAudioKBitrate": @(stat.rxAudioKBitrate),
373
-                                            @"txVideoKBitrate": @(stat.txVideoKBitrate),
374
-                                            @"rxVideoKBitrate": @(stat.rxVideoKBitrate),
375
-                                            @"lastmileDelay": @(stat.lastmileDelay),
376
-                                            @"userCount": @(stat.userCount),
377
-                                            @"cpuAppUsage": @(stat.cpuAppUsage),
378
-                                            @"cpuTotalUsage": @(stat.cpuTotalUsage)
473
+                                            @"duration": @(stats.duration),
474
+                                            @"txBytes": @(stats.txBytes),
475
+                                            @"rxBytes": @(stats.rxBytes),
476
+                                            @"txAudioBytes": @(stats.txAudioBytes),
477
+                                            @"txVideoBytes": @(stats.txVideoBytes),
478
+                                            @"rxAudioBytes": @(stats.rxAudioBytes),
479
+                                            @"rxVideoBytes": @(stats.rxVideoBytes),
480
+                                            @"txPacketLossRate": @(stats.txPacketLossRate),
481
+                                            @"rxPacketLossRate": @(stats.rxPacketLossRate),
482
+                                            @"txAudioKBitrate": @(stats.txAudioKBitrate),
483
+                                            @"rxAudioKBitrate": @(stats.rxAudioKBitrate),
484
+                                            @"txVideoKBitrate": @(stats.txVideoKBitrate),
485
+                                            @"rxVideoKBitrate": @(stats.rxVideoKBitrate),
486
+                                            @"lastmileDelay": @(stats.lastmileDelay),
487
+                                            @"userCount": @(stats.userCount),
488
+                                            @"cpuAppUsage": @(stats.cpuAppUsage),
489
+                                            @"cpuTotalUsage": @(stats.cpuTotalUsage)
379
                                             }];
490
                                             }];
380
   }];
491
   }];
381
   if (res == 0) {
492
   if (res == 0) {
909
 
1020
 
910
 // set volume of effect
1021
 // set volume of effect
911
 RCT_EXPORT_METHOD(setVolumeOfEffect
1022
 RCT_EXPORT_METHOD(setVolumeOfEffect
912
-                  :(NSInteger) soundId
1023
+                  :(int) soundId
913
                   volume:(double)volume
1024
                   volume:(double)volume
914
                   resolve:(RCTPromiseResolveBlock)resolve
1025
                   resolve:(RCTPromiseResolveBlock)resolve
915
                   reject:(RCTPromiseRejectBlock)reject) {
1026
                   reject:(RCTPromiseRejectBlock)reject) {
1699
 #pragma mark - <AgoraRtcEngineDelegate>
1810
 #pragma mark - <AgoraRtcEngineDelegate>
1700
 // EVENT CALLBACKS
1811
 // EVENT CALLBACKS
1701
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didOccurWarning:(AgoraWarningCode)warningCode {
1812
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didOccurWarning:(AgoraWarningCode)warningCode {
1702
-  [self sendEvent:AGWarning params:@{@"message": @"AgoraWarning", @"code": @(warningCode)}];
1813
+  [self sendEvent:AGWarning params:@{@"message": @"AgoraWarning", @"errorCode": @(warningCode)}];
1703
 }
1814
 }
1704
 
1815
 
1705
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didOccurError:(AgoraErrorCode)errorCode {
1816
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didOccurError:(AgoraErrorCode)errorCode {
1706
-  [self sendEvent:AGError params:@{@"message": @"AgoraError", @"code": @(errorCode)}];
1817
+  [self sendEvent:AGError params:@{@"message": @"AgoraError", @"errorCode": @(errorCode)}];
1707
 }
1818
 }
1708
 
1819
 
1709
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didApiCallExecute:(NSInteger)error api:(NSString *_Nonnull)api result:(NSString *_Nonnull)result {
1820
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didApiCallExecute:(NSInteger)error api:(NSString *_Nonnull)api result:(NSString *_Nonnull)result {
1711
     [self sendEvent:AGError  params:@{
1822
     [self sendEvent:AGError  params:@{
1712
                                       @"api": api,
1823
                                       @"api": api,
1713
                                       @"result": result,
1824
                                       @"result": result,
1714
-                                      @"error": @(error)
1825
+                                      @"errorCode": @(error)
1715
                                       }];
1826
                                       }];
1716
   } else {
1827
   } else {
1717
     [self sendEvent:AGApiCallExecute  params:@{
1828
     [self sendEvent:AGApiCallExecute  params:@{
1718
                                                @"api": api,
1829
                                                @"api": api,
1719
                                                @"result": result,
1830
                                                @"result": result,
1720
-                                               @"error": @(error)
1831
+                                               @"errorCode": @(error)
1721
                                                }];
1832
                                                }];
1722
   }
1833
   }
1723
 }
1834
 }
1744
                                               @"duration": @(stats.duration),
1855
                                               @"duration": @(stats.duration),
1745
                                               @"txBytes": @(stats.txBytes),
1856
                                               @"txBytes": @(stats.txBytes),
1746
                                               @"rxBytes": @(stats.rxBytes),
1857
                                               @"rxBytes": @(stats.rxBytes),
1858
+                                              @"txAudioBytes": @(stats.txAudioBytes),
1859
+                                              @"txVideoBytes": @(stats.txVideoBytes),
1860
+                                              @"rxAudioBytes": @(stats.rxAudioBytes),
1861
+                                              @"rxVideoBytes": @(stats.rxVideoBytes),
1862
+                                              @"txPacketLossRate": @(stats.txPacketLossRate),
1863
+                                              @"rxPacketLossRate": @(stats.rxPacketLossRate),
1747
                                               @"txAudioKBitrate": @(stats.txAudioKBitrate),
1864
                                               @"txAudioKBitrate": @(stats.txAudioKBitrate),
1748
                                               @"rxAudioKBitrate": @(stats.rxVideoKBitrate),
1865
                                               @"rxAudioKBitrate": @(stats.rxVideoKBitrate),
1749
                                               @"txVideoKBitrate": @(stats.txVideoKBitrate),
1866
                                               @"txVideoKBitrate": @(stats.txVideoKBitrate),
1779
 
1896
 
1780
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didUpdatedUserInfo:(AgoraUserInfo *_Nonnull)userInfo withUid:(NSUInteger)uid {
1897
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didUpdatedUserInfo:(AgoraUserInfo *_Nonnull)userInfo withUid:(NSUInteger)uid {
1781
   [self sendEvent:AGUserInfoUpdated params:@{
1898
   [self sendEvent:AGUserInfoUpdated params:@{
1782
-                                                 @"uid": @(uid),
1783
-                                                 @"peer": @{
1784
-                                                     @"uid": @(userInfo.uid),
1785
-                                                     @"userAccount": userInfo.userAccount
1899
+                                             @"uid": @(uid),
1900
+                                             @"peer": @{
1901
+                                                 @"uid": @(userInfo.uid),
1902
+                                                 @"userAccount": userInfo.userAccount
1786
                                                  }}];
1903
                                                  }}];
1787
 }
1904
 }
1788
 
1905
 
1825
                                           }];
1942
                                           }];
1826
 }
1943
 }
1827
 
1944
 
1828
-- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didMicrophoneEnabled:(BOOL)enabled {
1829
-  [self sendEvent:AGMicrophoneEnabled params:@{
1830
-                                               @"enabled": @(enabled)
1831
-                                               }];
1945
+- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine localAudioStateChange:(AgoraAudioLocalState)state error:(AgoraAudioLocalError)error {
1946
+  [self sendEvent:AGLocalAudioStateChanged params:@{
1947
+                                                    @"state": @(state),
1948
+                                                    @"errorCode": @(error)
1949
+                                                    }];
1950
+}
1951
+
1952
+- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine remoteAudioStateChangedOfUid:(NSUInteger)uid state:(AgoraAudioRemoteState)state reason:(AgoraAudioRemoteStateReason)reason elapsed:(NSInteger)elapsed {
1953
+  [self sendEvent:AGRemoteAudioStateChanged params:@{
1954
+                                                     @"uid": @(uid),
1955
+                                                     @"state": @(state),
1956
+                                                     @"reason": @(reason),
1957
+                                                     @"elapsed": @(elapsed)
1958
+                                                     }];
1959
+}
1960
+
1961
+- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine localAudioStats:(AgoraRtcLocalAudioStats *_Nonnull)stats {
1962
+  [self sendEvent:AGLocalAudioStats params:@{
1963
+                                             @"numChannels": @(stats.numChannels),
1964
+                                             @"sentSampleRate": @(stats.sentSampleRate),
1965
+                                             @"sentBitrate": @(stats.sentBitrate),
1966
+                                             }];
1832
 }
1967
 }
1833
 
1968
 
1834
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine reportAudioVolumeIndicationOfSpeakers:(NSArray<AgoraRtcAudioVolumeInfo*> *_Nonnull)speakers totalVolume:(NSInteger)totalVolume {
1969
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine reportAudioVolumeIndicationOfSpeakers:(NSArray<AgoraRtcAudioVolumeInfo*> *_Nonnull)speakers totalVolume:(NSInteger)totalVolume {
1879
                                                   }];
2014
                                                   }];
1880
 }
2015
 }
1881
 
2016
 
1882
-- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine firstRemoteVideoDecodedOfUid:(NSUInteger)uid size:(CGSize)size elapsed:(NSInteger)elapsed {
1883
-  [self sendEvent:AGFirstRemoteVideoDecoded params:@{
1884
-                                                     @"uid": @(uid),
1885
-                                                     @"width": @(size.width),
1886
-                                                     @"height": @(size.height),
1887
-                                                     @"elapsed": @(elapsed)
1888
-                                                     }];
1889
-}
1890
-
1891
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine firstRemoteVideoFrameOfUid:(NSUInteger)uid size:(CGSize)size elapsed:(NSInteger)elapsed {
2017
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine firstRemoteVideoFrameOfUid:(NSUInteger)uid size:(CGSize)size elapsed:(NSInteger)elapsed {
1892
   [self sendEvent:AGFirstRemoteVideoFrame params:@{
2018
   [self sendEvent:AGFirstRemoteVideoFrame params:@{
1893
                                                    @"uid": @(uid),
2019
                                                    @"uid": @(uid),
1903
                                            }];
2029
                                            }];
1904
 }
2030
 }
1905
 
2031
 
1906
-- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didVideoMuted:(BOOL)muted byUid:(NSUInteger)uid {
1907
-  [self sendEvent:AGUserMuteVideo params:@{
1908
-                                           @"muted": @(muted),
1909
-                                           @"uid": @(uid)
1910
-                                           }];
1911
-}
1912
-
1913
-- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didVideoEnabled:(BOOL)enabled byUid:(NSUInteger)uid {
1914
-  [self sendEvent:AGUserEnableVideo params:@{
1915
-                                             @"enabled": @(enabled),
1916
-                                             @"uid": @(uid)
1917
-                                             }];
1918
-}
1919
-
1920
-- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didLocalVideoEnabled:(BOOL)enabled byUid:(NSUInteger)uid {
1921
-  [self sendEvent:AGUserEnableLocalVideo params:@{
1922
-                                                  @"enabled": @(enabled),
1923
-                                                  @"uid": @(uid)
1924
-                                                  }];
1925
-}
1926
-
1927
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine videoSizeChangedOfUid:(NSUInteger)uid size:(CGSize)size rotation:(NSInteger)rotation {
2032
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine videoSizeChangedOfUid:(NSUInteger)uid size:(CGSize)size rotation:(NSInteger)rotation {
1928
   [self sendEvent:AGVideoSizeChanged params:@{
2033
   [self sendEvent:AGVideoSizeChanged params:@{
1929
                                               @"uid": @(uid),
2034
                                               @"uid": @(uid),
1933
                                               }];
2038
                                               }];
1934
 }
2039
 }
1935
 
2040
 
1936
-- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine remoteVideoStateChangedOfUid:(NSUInteger)uid state:(AgoraVideoRemoteState)state {
2041
+- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine remoteVideoStateChangedOfUid:(NSUInteger)uid state:(AgoraVideoRemoteState)state reason:(AgoraVideoRemoteStateReason)reason elapsed:(NSInteger)elapsed {
1937
   [self sendEvent:AGRemoteVideoStateChanged params:@{
2042
   [self sendEvent:AGRemoteVideoStateChanged params:@{
1938
                                                      @"uid": @(uid),
2043
                                                      @"uid": @(uid),
1939
-                                                     @"state": @(state)
2044
+                                                     @"state": @(state),
2045
+                                                     @"reason": @(reason),
2046
+                                                     @"elapsed": @(elapsed)
1940
                                                      }];
2047
                                                      }];
1941
 }
2048
 }
1942
 
2049
 
1992
   [self sendEvent:AGRtcStats params:@{
2099
   [self sendEvent:AGRtcStats params:@{
1993
                                       @"stats": @{
2100
                                       @"stats": @{
1994
                                           @"duration": @(stats.duration),
2101
                                           @"duration": @(stats.duration),
1995
-                                          @"txPacketLossRate": @(stats.txPacketLossRate),
1996
-                                          @"rxPacketLossRate": @(stats.rxPacketLossRate),
1997
                                           @"txBytes": @(stats.txBytes),
2102
                                           @"txBytes": @(stats.txBytes),
1998
                                           @"rxBytes": @(stats.rxBytes),
2103
                                           @"rxBytes": @(stats.rxBytes),
2104
+                                          @"txAudioBytes": @(stats.txAudioBytes),
2105
+                                          @"txVideoBytes": @(stats.txVideoBytes),
2106
+                                          @"rxAudioBytes": @(stats.rxAudioBytes),
2107
+                                          @"rxVideoBytes": @(stats.rxVideoBytes),
2108
+                                          @"txPacketLossRate": @(stats.txPacketLossRate),
2109
+                                          @"rxPacketLossRate": @(stats.rxPacketLossRate),
1999
                                           @"txAudioKBitrate": @(stats.txAudioKBitrate),
2110
                                           @"txAudioKBitrate": @(stats.txAudioKBitrate),
2000
                                           @"rxAudioKBitrate": @(stats.rxAudioKBitrate),
2111
                                           @"rxAudioKBitrate": @(stats.rxAudioKBitrate),
2001
                                           @"txVideoKBitrate": @(stats.txVideoKBitrate),
2112
                                           @"txVideoKBitrate": @(stats.txVideoKBitrate),
2050
                                               }];
2161
                                               }];
2051
 }
2162
 }
2052
 
2163
 
2053
-- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine audioTransportStatsOfUid:(NSUInteger)uid delay:(NSUInteger)delay lost:(NSUInteger)lost rxKBitRate:(NSUInteger)rxKBitRate {
2054
-  [self sendEvent:AGAudioTransportStatsOfUid params:@{
2055
-                                                      @"uid": @(uid),
2056
-                                                      @"delay": @(delay),
2057
-                                                      @"lost": @(lost),
2058
-                                                      @"rxKBitrate": @(rxKBitRate)
2059
-                                                      }];
2060
-}
2061
-
2062
-- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine videoTransportStatsOfUid:(NSUInteger)uid delay:(NSUInteger)delay lost:(NSUInteger)lost rxKBitRate:(NSUInteger)rxKBitRate {
2063
-  [self sendEvent:AGVideoTransportStatsOfUid params:@{
2064
-                                                      @"uid": @(uid),
2065
-                                                      @"delay": @(delay),
2066
-                                                      @"lost": @(lost),
2067
-                                                      @"rxKBitrate": @(rxKBitRate)
2068
-                                                      }];
2069
-}
2070
-
2071
 - (void)rtcEngineRemoteAudioMixingDidStart:(AgoraRtcEngineKit *_Nonnull)engine {
2164
 - (void)rtcEngineRemoteAudioMixingDidStart:(AgoraRtcEngineKit *_Nonnull)engine {
2072
   [self sendEvent:AGRemoteAudioMixingStart params:@{
2165
   [self sendEvent:AGRemoteAudioMixingStart params:@{
2073
                                                     @"message": @"RemoteAudioMixingStarted"
2166
                                                     @"message": @"RemoteAudioMixingStarted"
2089
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine streamPublishedWithUrl:(NSString *_Nonnull)url errorCode:(AgoraErrorCode)errorCode {
2182
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine streamPublishedWithUrl:(NSString *_Nonnull)url errorCode:(AgoraErrorCode)errorCode {
2090
   [self sendEvent:AGStreamPublished params:@{
2183
   [self sendEvent:AGStreamPublished params:@{
2091
                                              @"url": url,
2184
                                              @"url": url,
2092
-                                             @"code": @(errorCode)
2185
+                                             @"errorCode": @(errorCode)
2093
                                              }];
2186
                                              }];
2094
 }
2187
 }
2095
 
2188
 
2128
                                                   }];
2221
                                                   }];
2129
 }
2222
 }
2130
 
2223
 
2224
+- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine channelMediaRelayStateDidChange:(AgoraChannelMediaRelayState)state error:(AgoraChannelMediaRelayError)error {
2225
+  [self sendEvent:AGMediaRelayStateChanged params:@{
2226
+                                                    @"state": @(state),
2227
+                                                    @"errorCode": @(error),
2228
+                                                    }];
2229
+}
2230
+
2231
+- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didReceiveChannelMediaRelayEvent:(AgoraChannelMediaRelayEvent)event {
2232
+  [self sendEvent:AGReceivedChannelMediaRelay params:@{
2233
+                                                       @"event": @(event),
2234
+                                                       }];
2235
+}
2236
+
2131
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine receiveStreamMessageFromUid:(NSUInteger)uid streamId:(NSInteger)streamId data:(NSData *_Nonnull)data {
2237
 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine receiveStreamMessageFromUid:(NSUInteger)uid streamId:(NSInteger)streamId data:(NSData *_Nonnull)data {
2132
   NSString *_data = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
2238
   NSString *_data = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
2133
   [self sendEvent:AGReceiveStreamMessage params:@{
2239
   [self sendEvent:AGReceiveStreamMessage params:@{
2140
   [self sendEvent:AGOccurStreamMessageError params:@{
2246
   [self sendEvent:AGOccurStreamMessageError params:@{
2141
                                                      @"uid": @(uid),
2247
                                                      @"uid": @(uid),
2142
                                                      @"streamId": @(streamId),
2248
                                                      @"streamId": @(streamId),
2143
-                                                     @"error": @(error),
2249
+                                                     @"errorCode": @(error),
2144
                                                      @"missed": @(missed),
2250
                                                      @"missed": @(missed),
2145
                                                      @"cached": @(cached)
2251
                                                      @"cached": @(cached)
2146
                                                      }];
2252
                                                      }];

+ 54
- 8
lib/RtcEngine.native.d.ts View File

1
-import { Option, Callback, AgoraUserInfo, AudioMixingOption, PlayEffectOption, AudioRecordingOption, AudioFrameOption, MixedAudioFrameOption, ImageOption, VideoStreamOption, DefaultVideoStreamOption, InjectStreamOption, RemoveInjectStreamOption, PublishStreamOption, RemovePublishStreamOption, LiveTranscodingOption, PositionOption, BeautyOption, LastmileProbeConfig, CameraCapturerConfiguration } from "./types";
1
+import { Option, Callback, AgoraUserInfo, AudioMixingOption, PlayEffectOption, AudioRecordingOption, AudioFrameOption, MixedAudioFrameOption, ImageOption, VideoStreamOption, DefaultVideoStreamOption, InjectStreamOption, RemoveInjectStreamOption, PublishStreamOption, RemovePublishStreamOption, LiveTranscodingOption, PositionOption, BeautyOption, LastmileProbeConfig, CameraCapturerConfiguration, ChannelMediaConfiguration } from "./types";
2
 /**
2
 /**
3
  * RtcEngine is the javascript object for control agora native sdk through react native bridge.
3
  * RtcEngine is the javascript object for control agora native sdk through react native bridge.
4
  *
4
  *
34
      * @param info
34
      * @param info
35
      */
35
      */
36
     static joinChannel(channelName: string, uid?: number, token?: string, info?: Object): Promise<any>;
36
     static joinChannel(channelName: string, uid?: number, token?: string, info?: Object): Promise<any>;
37
+    /**
38
+     * switch to specified channel
39
+     *
40
+     * This method will switch channel smoothly than you invoke leaveChannel & joinChannel.
41
+     * Otherwise, it will invoke error by the event
42
+     * It will occurs two events:
43
+     * Occurs leaveChannel when achieve leaving stage
44
+     * Occurs joinChannelSuccess when achieve joining stage
45
+     * @param channelName
46
+     * @param token
47
+     */
48
+    static switchChannel(channelName: string, token?: string): Promise<any>;
49
+    /**
50
+     * Starts to relay media streams across channels.
51
+     *
52
+     * This method will start relay media stream across specified channels. (maximum support 4 channels)
53
+     * It will occurs event:
54
+     *  Occurs onChannelMediaRelayStateChanged
55
+     * @param config
56
+     */
57
+    static startChannelMediaRelay(config: ChannelMediaConfiguration): Promise<any>;
58
+    /**
59
+     * Remove to relay media streams across channels.
60
+     *
61
+     * This method will remove & update relay media stream across specified channels. (maximum support relay 4 channels)
62
+     * It will occurs event:
63
+     *  Occurs onChannelMediaRelayStateChanged
64
+     * @param config
65
+     */
66
+    static removeChannelMediaRelay(config: ChannelMediaConfiguration): Promise<any>;
67
+    /**
68
+     * Updates to relay media streams across channels.
69
+     *
70
+     * This method will update relay media stream across specified channels. (maximum support 4 channels)
71
+     * It will occurs event:
72
+     *  Occurs onChannelMediaRelayStateChanged
73
+     * @param config
74
+     */
75
+    static updateChannelMediaRelay(config: ChannelMediaConfiguration): Promise<any>;
76
+    /**
77
+     * Stop to relay media streams across channels.
78
+     *
79
+     * This method will stop relay media stream across specified channels.
80
+     * It will occurs event:
81
+     *  Occurs onChannelMediaRelayStateChanged
82
+     * @param config
83
+     */
84
+    static stopChannelMediaRelay(): Promise<any>;
37
     /**
85
     /**
38
      * Registers a user account.
86
      * Registers a user account.
39
      *
87
      *
117
      * connectionLost | occurs when sdk connection lost | on("connectionLost", evt) |
165
      * connectionLost | occurs when sdk connection lost | on("connectionLost", evt) |
118
      * tokenPrivilegeWillExpire | occurs when token will expire | on("tokenPrivilegeWillExpire", evt) |
166
      * tokenPrivilegeWillExpire | occurs when token will expire | on("tokenPrivilegeWillExpire", evt) |
119
      * requestToken | occurs when token expired | on("requestToken") |
167
      * requestToken | occurs when token expired | on("requestToken") |
120
-     * microphoneEnabled | occurs when microphone enable state changed | on("microphoneEnabled", evt) |
168
+     * localAudioStateChanged | occurs when local audio device state changed | on("localAudioStateChanged", (state, errorCode) => {}) |
121
      * audioVolumeIndication | occurs when audio volume indication changed | on("audioVolumeIndication", evt) |
169
      * audioVolumeIndication | occurs when audio volume indication changed | on("audioVolumeIndication", evt) |
122
      * activeSpeaker | occurs when detect active speaker | on("activeSpeaker", evt) |
170
      * activeSpeaker | occurs when detect active speaker | on("activeSpeaker", evt) |
123
      * firstLocalAudioFrame | occurs when sent first audio frame on local | on("firstLocalAudioFrame", evt) |
171
      * firstLocalAudioFrame | occurs when sent first audio frame on local | on("firstLocalAudioFrame", evt) |
124
      * firstRemoteAudioFrame | occurs when received first audio frame from remote side | on("firstRemoteAudioFrame", evt) |
172
      * firstRemoteAudioFrame | occurs when received first audio frame from remote side | on("firstRemoteAudioFrame", evt) |
125
      * firstRemoteAudioDecoded | occurs when first remote audio decoded | on("firstRemoteAudioDecoded", evt) |
173
      * firstRemoteAudioDecoded | occurs when first remote audio decoded | on("firstRemoteAudioDecoded", evt) |
126
      * firstLocalVideoFrame | occurs when sent first video frame on local | on("firstLocalVideoFrame", evt) |
174
      * firstLocalVideoFrame | occurs when sent first video frame on local | on("firstLocalVideoFrame", evt) |
127
-     * firstRemoteVideoDecoded | occurs when received first video frame from remote side decoded | on("firstRemoteVideoDecoded", evt) |
128
      * firstRemoteVideoFrame | occurs when received first video frame from remote side | on("firstRemoteVideoFrame", evt) |
175
      * firstRemoteVideoFrame | occurs when received first video frame from remote side | on("firstRemoteVideoFrame", evt) |
129
      * userMuteAudio | occurs when user mute audio | on("userMuteAudio", evt) |
176
      * userMuteAudio | occurs when user mute audio | on("userMuteAudio", evt) |
130
-     * userMuteVideo | occurs when user mute video | on("userMuteVideo", evt) |
131
-     * userEnableVideo | occurs when remote side's user change video enable state | on("userEnableVideo", evt) |
132
-     * userEnableLocalVideo | occurs when user change video enable state on local | on("userEnableLocalVideo", evt) |
133
      * videoSizeChanged | occurs when change local or remote side video size or rotation | on("videoSizeChanged", evt) |
177
      * videoSizeChanged | occurs when change local or remote side video size or rotation | on("videoSizeChanged", evt) |
134
      * remoteVideoStateChanged | occurs when remote video state has any changed | on("remoteVideoStateChanged", evt) |
178
      * remoteVideoStateChanged | occurs when remote video state has any changed | on("remoteVideoStateChanged", evt) |
179
+     * remoteAudioStateChanged | occurs when remote audio state has any changed | on("remoteAudioStateChanged", evt) |
180
+     * localAudioStats | occurs when engine start to report local audio stats | on("localAudioStats", evt) |
135
      * localPublishFallbackToAudioOnly | occurs when published stream from local side fallback to audio stream | on("localPublishFallbackToAudioOnly", evt) |
181
      * localPublishFallbackToAudioOnly | occurs when published stream from local side fallback to audio stream | on("localPublishFallbackToAudioOnly", evt) |
136
      * remoteSubscribeFallbackToAudioOnly | occurs when subscribed side's stream fallback to audio stream | on("remoteSubscribeFallbackToAudioOnly", evt) |
182
      * remoteSubscribeFallbackToAudioOnly | occurs when subscribed side's stream fallback to audio stream | on("remoteSubscribeFallbackToAudioOnly", evt) |
137
      * audioRouteChanged | occurs when local audio route changed | on("audioRouteChanged", evt) |
183
      * audioRouteChanged | occurs when local audio route changed | on("audioRouteChanged", evt) |
143
      * localVideoStats | occurs when reports local video statistics | on("localVideoStats", evt) |
189
      * localVideoStats | occurs when reports local video statistics | on("localVideoStats", evt) |
144
      * remoteVideoStats | occurs when reports remote video statistics| on("remoteVideoStats", evt) |
190
      * remoteVideoStats | occurs when reports remote video statistics| on("remoteVideoStats", evt) |
145
      * remoteAudioStats | occurs when reports remote audio statistics| on("remoteAudioStats", evt) |
191
      * remoteAudioStats | occurs when reports remote audio statistics| on("remoteAudioStats", evt) |
146
-     * audioTransportStatsOfUid | occurs when reports  transport-layer statistics of each remote audio stream. | on("audioTransportStatsOfUid", evt) |
147
-     * videoTransportStatsOfUid | occurs when reports  transport-layer statistics of each remote video stream.| on("videoTransportStatsOfUid", evt) |
148
      * audioEffectFinish | occurs when the local audio effect playback finishes. | on("audioEffectFinish", evt) |
192
      * audioEffectFinish | occurs when the local audio effect playback finishes. | on("audioEffectFinish", evt) |
149
      * streamPublished | occurs when addPublishStreamUrl success| on("streamPublished", evt) |
193
      * streamPublished | occurs when addPublishStreamUrl success| on("streamPublished", evt) |
150
      * streamUnpublish | occurs when removePublishStreamUrl success| on("streamUnpublish", evt) |
194
      * streamUnpublish | occurs when removePublishStreamUrl success| on("streamUnpublish", evt) |
161
      * mediaMetaDataReceived | occurs when you received media meta data from the remote side through sendMediaData | on("mediaMetaDataReceived", evt) |
205
      * mediaMetaDataReceived | occurs when you received media meta data from the remote side through sendMediaData | on("mediaMetaDataReceived", evt) |
162
      * localUserRegistered | occurs when you register user account success | on("localUserRegistered", evt) |
206
      * localUserRegistered | occurs when you register user account success | on("localUserRegistered", evt) |
163
      * userInfoUpdated | occurs when you peer side using user account join channel | on("userInfoUpdated", evt) |
207
      * userInfoUpdated | occurs when you peer side using user account join channel | on("userInfoUpdated", evt) |
208
+     * receivedChannelMediaRelay | occurs when you received channel media relay | on('receivedChannelMediaRelay", evt)|
209
+     * mediaRelayStateChanged | occurs when you received remote media relay state changed | on('mediaRelayStateChanged", evt)|
164
      * ---
210
      * ---
165
      *
211
      *
166
      * @param eventType
212
      * @param eventType

+ 64
- 14
lib/RtcEngine.native.js View File

35
     static joinChannel(channelName, uid, token, info) {
35
     static joinChannel(channelName, uid, token, info) {
36
         return Agora.joinChannel({ channelName, uid, token, info });
36
         return Agora.joinChannel({ channelName, uid, token, info });
37
     }
37
     }
38
+    /**
39
+     * switch to specified channel
40
+     *
41
+     * This method will switch channel smoothly than you invoke leaveChannel & joinChannel.
42
+     * Otherwise, it will invoke error by the event
43
+     * It will occurs two events:
44
+     * Occurs leaveChannel when achieve leaving stage
45
+     * Occurs joinChannelSuccess when achieve joining stage
46
+     * @param channelName
47
+     * @param token
48
+     */
49
+    static switchChannel(channelName, token) {
50
+        return Agora.switchChannel({ channelName, token });
51
+    }
52
+    /**
53
+     * Starts to relay media streams across channels.
54
+     *
55
+     * This method will start relay media stream across specified channels. (maximum support 4 channels)
56
+     * It will occurs event:
57
+     *  Occurs onChannelMediaRelayStateChanged
58
+     * @param config
59
+     */
60
+    static startChannelMediaRelay(config) {
61
+        return Agora.startChannelMediaRelay(config);
62
+    }
63
+    /**
64
+     * Remove to relay media streams across channels.
65
+     *
66
+     * This method will remove & update relay media stream across specified channels. (maximum support relay 4 channels)
67
+     * It will occurs event:
68
+     *  Occurs onChannelMediaRelayStateChanged
69
+     * @param config
70
+     */
71
+    static removeChannelMediaRelay(config) {
72
+        return Agora.removeChannelMediaRelay(config);
73
+    }
74
+    /**
75
+     * Updates to relay media streams across channels.
76
+     *
77
+     * This method will update relay media stream across specified channels. (maximum support 4 channels)
78
+     * It will occurs event:
79
+     *  Occurs onChannelMediaRelayStateChanged
80
+     * @param config
81
+     */
82
+    static updateChannelMediaRelay(config) {
83
+        return Agora.updateChannelMediaRelay(config);
84
+    }
85
+    /**
86
+     * Stop to relay media streams across channels.
87
+     *
88
+     * This method will stop relay media stream across specified channels.
89
+     * It will occurs event:
90
+     *  Occurs onChannelMediaRelayStateChanged
91
+     * @param config
92
+     */
93
+    static stopChannelMediaRelay() {
94
+        return Agora.stopChannelMediaRelay();
95
+    }
38
     /**
96
     /**
39
      * Registers a user account.
97
      * Registers a user account.
40
      *
98
      *
141
      * connectionLost | occurs when sdk connection lost | on("connectionLost", evt) |
199
      * connectionLost | occurs when sdk connection lost | on("connectionLost", evt) |
142
      * tokenPrivilegeWillExpire | occurs when token will expire | on("tokenPrivilegeWillExpire", evt) |
200
      * tokenPrivilegeWillExpire | occurs when token will expire | on("tokenPrivilegeWillExpire", evt) |
143
      * requestToken | occurs when token expired | on("requestToken") |
201
      * requestToken | occurs when token expired | on("requestToken") |
144
-     * microphoneEnabled | occurs when microphone enable state changed | on("microphoneEnabled", evt) |
202
+     * localAudioStateChanged | occurs when local audio device state changed | on("localAudioStateChanged", (state, errorCode) => {}) |
145
      * audioVolumeIndication | occurs when audio volume indication changed | on("audioVolumeIndication", evt) |
203
      * audioVolumeIndication | occurs when audio volume indication changed | on("audioVolumeIndication", evt) |
146
      * activeSpeaker | occurs when detect active speaker | on("activeSpeaker", evt) |
204
      * activeSpeaker | occurs when detect active speaker | on("activeSpeaker", evt) |
147
      * firstLocalAudioFrame | occurs when sent first audio frame on local | on("firstLocalAudioFrame", evt) |
205
      * firstLocalAudioFrame | occurs when sent first audio frame on local | on("firstLocalAudioFrame", evt) |
148
      * firstRemoteAudioFrame | occurs when received first audio frame from remote side | on("firstRemoteAudioFrame", evt) |
206
      * firstRemoteAudioFrame | occurs when received first audio frame from remote side | on("firstRemoteAudioFrame", evt) |
149
      * firstRemoteAudioDecoded | occurs when first remote audio decoded | on("firstRemoteAudioDecoded", evt) |
207
      * firstRemoteAudioDecoded | occurs when first remote audio decoded | on("firstRemoteAudioDecoded", evt) |
150
      * firstLocalVideoFrame | occurs when sent first video frame on local | on("firstLocalVideoFrame", evt) |
208
      * firstLocalVideoFrame | occurs when sent first video frame on local | on("firstLocalVideoFrame", evt) |
151
-     * firstRemoteVideoDecoded | occurs when received first video frame from remote side decoded | on("firstRemoteVideoDecoded", evt) |
152
      * firstRemoteVideoFrame | occurs when received first video frame from remote side | on("firstRemoteVideoFrame", evt) |
209
      * firstRemoteVideoFrame | occurs when received first video frame from remote side | on("firstRemoteVideoFrame", evt) |
153
      * userMuteAudio | occurs when user mute audio | on("userMuteAudio", evt) |
210
      * userMuteAudio | occurs when user mute audio | on("userMuteAudio", evt) |
154
-     * userMuteVideo | occurs when user mute video | on("userMuteVideo", evt) |
155
-     * userEnableVideo | occurs when remote side's user change video enable state | on("userEnableVideo", evt) |
156
-     * userEnableLocalVideo | occurs when user change video enable state on local | on("userEnableLocalVideo", evt) |
157
      * videoSizeChanged | occurs when change local or remote side video size or rotation | on("videoSizeChanged", evt) |
211
      * videoSizeChanged | occurs when change local or remote side video size or rotation | on("videoSizeChanged", evt) |
158
      * remoteVideoStateChanged | occurs when remote video state has any changed | on("remoteVideoStateChanged", evt) |
212
      * remoteVideoStateChanged | occurs when remote video state has any changed | on("remoteVideoStateChanged", evt) |
213
+     * remoteAudioStateChanged | occurs when remote audio state has any changed | on("remoteAudioStateChanged", evt) |
214
+     * localAudioStats | occurs when engine start to report local audio stats | on("localAudioStats", evt) |
159
      * localPublishFallbackToAudioOnly | occurs when published stream from local side fallback to audio stream | on("localPublishFallbackToAudioOnly", evt) |
215
      * localPublishFallbackToAudioOnly | occurs when published stream from local side fallback to audio stream | on("localPublishFallbackToAudioOnly", evt) |
160
      * remoteSubscribeFallbackToAudioOnly | occurs when subscribed side's stream fallback to audio stream | on("remoteSubscribeFallbackToAudioOnly", evt) |
216
      * remoteSubscribeFallbackToAudioOnly | occurs when subscribed side's stream fallback to audio stream | on("remoteSubscribeFallbackToAudioOnly", evt) |
161
      * audioRouteChanged | occurs when local audio route changed | on("audioRouteChanged", evt) |
217
      * audioRouteChanged | occurs when local audio route changed | on("audioRouteChanged", evt) |
167
      * localVideoStats | occurs when reports local video statistics | on("localVideoStats", evt) |
223
      * localVideoStats | occurs when reports local video statistics | on("localVideoStats", evt) |
168
      * remoteVideoStats | occurs when reports remote video statistics| on("remoteVideoStats", evt) |
224
      * remoteVideoStats | occurs when reports remote video statistics| on("remoteVideoStats", evt) |
169
      * remoteAudioStats | occurs when reports remote audio statistics| on("remoteAudioStats", evt) |
225
      * remoteAudioStats | occurs when reports remote audio statistics| on("remoteAudioStats", evt) |
170
-     * audioTransportStatsOfUid | occurs when reports  transport-layer statistics of each remote audio stream. | on("audioTransportStatsOfUid", evt) |
171
-     * videoTransportStatsOfUid | occurs when reports  transport-layer statistics of each remote video stream.| on("videoTransportStatsOfUid", evt) |
172
      * audioEffectFinish | occurs when the local audio effect playback finishes. | on("audioEffectFinish", evt) |
226
      * audioEffectFinish | occurs when the local audio effect playback finishes. | on("audioEffectFinish", evt) |
173
      * streamPublished | occurs when addPublishStreamUrl success| on("streamPublished", evt) |
227
      * streamPublished | occurs when addPublishStreamUrl success| on("streamPublished", evt) |
174
      * streamUnpublish | occurs when removePublishStreamUrl success| on("streamUnpublish", evt) |
228
      * streamUnpublish | occurs when removePublishStreamUrl success| on("streamUnpublish", evt) |
185
      * mediaMetaDataReceived | occurs when you received media meta data from the remote side through sendMediaData | on("mediaMetaDataReceived", evt) |
239
      * mediaMetaDataReceived | occurs when you received media meta data from the remote side through sendMediaData | on("mediaMetaDataReceived", evt) |
186
      * localUserRegistered | occurs when you register user account success | on("localUserRegistered", evt) |
240
      * localUserRegistered | occurs when you register user account success | on("localUserRegistered", evt) |
187
      * userInfoUpdated | occurs when you peer side using user account join channel | on("userInfoUpdated", evt) |
241
      * userInfoUpdated | occurs when you peer side using user account join channel | on("userInfoUpdated", evt) |
242
+     * receivedChannelMediaRelay | occurs when you received channel media relay | on('receivedChannelMediaRelay", evt)|
243
+     * mediaRelayStateChanged | occurs when you received remote media relay state changed | on('mediaRelayStateChanged", evt)|
188
      * ---
244
      * ---
189
      *
245
      *
190
      * @param eventType
246
      * @param eventType
203
             'receiveStreamMessage',
259
             'receiveStreamMessage',
204
             'activeSpeaker',
260
             'activeSpeaker',
205
             'firstRemoteAudioFrame',
261
             'firstRemoteAudioFrame',
206
-            'firstRemoteVideoDecoded',
207
             'firstRemoteVideoFrame',
262
             'firstRemoteVideoFrame',
208
             'userMuteAudio',
263
             'userMuteAudio',
209
-            'userMuteVideo',
210
-            'userEnableVideo',
211
-            'userEnableLocalVideo',
212
             'videoSizeChanged',
264
             'videoSizeChanged',
213
-            'firstRemoteAudioDecoded',
214
             'remoteVideoStateChanged',
265
             'remoteVideoStateChanged',
266
+            'remoteAudioStateChanged',
215
             'remoteSubscribeFallbackToAudioOnly',
267
             'remoteSubscribeFallbackToAudioOnly',
216
             'networkQuality',
268
             'networkQuality',
217
             'streamInjectedStatus',
269
             'streamInjectedStatus',
248
         if ([
300
         if ([
249
             'remoteAudioStats',
301
             'remoteAudioStats',
250
             'remoteVideoStats',
302
             'remoteVideoStats',
251
-            'audioTransportStatsOfUid',
252
-            'videoTransportStatsOfUid',
253
         ].indexOf(eventType) != -1) {
303
         ].indexOf(eventType) != -1) {
254
             AgoraEventEmitter.addListener(`${RtcEngine.AG_PREFIX}${eventType}`, (args) => {
304
             AgoraEventEmitter.addListener(`${RtcEngine.AG_PREFIX}${eventType}`, (args) => {
255
                 args.stats.uid = this.Int32ToUint32(args.stats.uid);
305
                 args.stats.uid = this.Int32ToUint32(args.stats.uid);

+ 1
- 1
lib/RtcEngine.native.js.map
File diff suppressed because it is too large
View File


+ 28
- 0
lib/types.d.ts View File

1
 import { ViewProps } from 'react-native';
1
 import { ViewProps } from 'react-native';
2
+/**
3
+ * ChannelMediaInfo
4
+ * @property channelName: string
5
+ * @property token: string
6
+ * @property uid: number
7
+ */
8
+export interface ChannelMediaInfo {
9
+    channelName: string;
10
+    token?: string;
11
+    uid?: number;
12
+}
13
+/**
14
+ * ChannelMediaConfiguration
15
+ * @property src: {
16
+ *    @member channelName,
17
+ *    @member token,
18
+ *    @member uid,
19
+ * }
20
+ * @property channels: {@link Array<ChannelMediaInfo>}
21
+ */
22
+export interface ChannelMediaConfiguration {
23
+    src?: {
24
+        channelName: string;
25
+        token?: string;
26
+        uid?: number;
27
+    };
28
+    channels: Array<ChannelMediaInfo>;
29
+}
2
 /**
30
 /**
3
  * AgoraViewMode
31
  * AgoraViewMode
4
  * @mode hidden Uniformly scale the video until it fills the visible boundaries (cropped). One dimension of the video may have clipped contents.
32
  * @mode hidden Uniformly scale the video until it fills the visible boundaries (cropped). One dimension of the video may have clipped contents.

+ 1
- 1
lib/types.js.map View File

1
-{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;AAEA;;;;GAIG;AACH,IAAY,aAGX;AAHD,WAAY,aAAa;IACvB,qDAAU,CAAA;IACV,+CAAO,CAAA;AACT,CAAC,EAHW,aAAa,GAAb,qBAAa,KAAb,qBAAa,QAGxB;AAUA,CAAC;AAuGF,IAAY,iBAIX;AAJD,WAAY,iBAAiB;IAC3B,kEAAa,CAAA;IACb,0DAAS,CAAA;IACT,2DAAU,CAAA;AACZ,CAAC,EAJW,iBAAiB,GAAjB,yBAAiB,KAAjB,yBAAiB,QAI5B;AAED,IAAY,iBAGX;AAHD,WAAY,iBAAiB;IAC3B,6DAAU,CAAA;IACV,6DAAU,CAAA;AACZ,CAAC,EAHW,iBAAiB,GAAjB,yBAAiB,KAAjB,yBAAiB,QAG5B;AAED,IAAY,eAIX;AAJD,WAAY,eAAe;IACzB,qEAAkB,CAAA;IAClB,qEAAkB,CAAA;IAClB,qEAAkB,CAAA;AACpB,CAAC,EAJW,eAAe,GAAf,uBAAe,KAAf,uBAAe,QAI1B;AAED;;;GAGG;AACH,IAAY,kBAMX;AAND,WAAY,kBAAkB;IAC5B,yDAAO,CAAA;IACP,yDAAO,CAAA;IACP,6DAAS,CAAA;IACT,2DAAQ,CAAA;IACR,2DAAQ,CAAA;AACV,CAAC,EANW,kBAAkB,GAAlB,0BAAkB,KAAlB,0BAAkB,QAM7B"}
1
+{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;AA+BA;;;;GAIG;AACH,IAAY,aAGX;AAHD,WAAY,aAAa;IACvB,qDAAU,CAAA;IACV,+CAAO,CAAA;AACT,CAAC,EAHW,aAAa,GAAb,qBAAa,KAAb,qBAAa,QAGxB;AAUA,CAAC;AAuGF,IAAY,iBAIX;AAJD,WAAY,iBAAiB;IAC3B,kEAAa,CAAA;IACb,0DAAS,CAAA;IACT,2DAAU,CAAA;AACZ,CAAC,EAJW,iBAAiB,GAAjB,yBAAiB,KAAjB,yBAAiB,QAI5B;AAED,IAAY,iBAGX;AAHD,WAAY,iBAAiB;IAC3B,6DAAU,CAAA;IACV,6DAAU,CAAA;AACZ,CAAC,EAHW,iBAAiB,GAAjB,yBAAiB,KAAjB,yBAAiB,QAG5B;AAED,IAAY,eAIX;AAJD,WAAY,eAAe;IACzB,qEAAkB,CAAA;IAClB,qEAAkB,CAAA;IAClB,qEAAkB,CAAA;AACpB,CAAC,EAJW,eAAe,GAAf,uBAAe,KAAf,uBAAe,QAI1B;AAED;;;GAGG;AACH,IAAY,kBAMX;AAND,WAAY,kBAAkB;IAC5B,yDAAO,CAAA;IACP,yDAAO,CAAA;IACP,6DAAS,CAAA;IACT,2DAAQ,CAAA;IACR,2DAAQ,CAAA;AACV,CAAC,EANW,kBAAkB,GAAlB,0BAAkB,KAAlB,0BAAkB,QAM7B"}

+ 1
- 1
package.json View File

1
 {
1
 {
2
   "name": "react-native-agora",
2
   "name": "react-native-agora",
3
-  "version": "2.8.0-alpha.2",
3
+  "version": "2.9.0-alpha.1",
4
   "description": "React Native around the Agora RTC SDKs for Android and iOS agora",
4
   "description": "React Native around the Agora RTC SDKs for Android and iOS agora",
5
   "summary": "agora native sdk for react-native",
5
   "summary": "agora native sdk for react-native",
6
   "main": "lib/index.js",
6
   "main": "lib/index.js",

+ 1
- 1
react-native-agora.podspec View File

20
     end
20
     end
21
 
21
 
22
     s.dependency 'React'
22
     s.dependency 'React'
23
-    s.dependency "AgoraRtcEngine_iOS", "2.8"
23
+    s.dependency "AgoraRtcEngine_iOS", "2.9"
24
 end
24
 end

+ 72
- 16
src/RtcEngine.native.ts View File

25
     PositionOption,
25
     PositionOption,
26
     BeautyOption,
26
     BeautyOption,
27
     LastmileProbeConfig,
27
     LastmileProbeConfig,
28
-    CameraCapturerConfiguration
28
+    CameraCapturerConfiguration,
29
+    ChannelMediaConfiguration
29
 } from "./types";
30
 } from "./types";
30
 
31
 
31
 
32
 
76
         return Agora.joinChannel({channelName, uid, token, info});
77
         return Agora.joinChannel({channelName, uid, token, info});
77
     }
78
     }
78
 
79
 
80
+    /**
81
+     * switch to specified channel
82
+     *
83
+     * This method will switch channel smoothly than you invoke leaveChannel & joinChannel.
84
+     * Otherwise, it will invoke error by the event
85
+     * It will occurs two events:
86
+     * Occurs leaveChannel when achieve leaving stage
87
+     * Occurs joinChannelSuccess when achieve joining stage
88
+     * @param channelName
89
+     * @param token
90
+     */
91
+    public static switchChannel(channelName: string, token?: string): Promise<any> {
92
+        return Agora.switchChannel({channelName, token});
93
+    }
94
+    
95
+    /**
96
+     * Starts to relay media streams across channels.
97
+     * 
98
+     * This method will start relay media stream across specified channels. (maximum support 4 channels)
99
+     * It will occurs event:
100
+     *  Occurs onChannelMediaRelayStateChanged
101
+     * @param config
102
+     */
103
+    public static startChannelMediaRelay(config: ChannelMediaConfiguration): Promise<any> {
104
+        return Agora.startChannelMediaRelay(config);
105
+    }
106
+
107
+    /**
108
+     * Remove to relay media streams across channels.
109
+     * 
110
+     * This method will remove & update relay media stream across specified channels. (maximum support relay 4 channels)
111
+     * It will occurs event:
112
+     *  Occurs onChannelMediaRelayStateChanged
113
+     * @param config
114
+     */
115
+    public static removeChannelMediaRelay(config: ChannelMediaConfiguration): Promise<any> {
116
+        return Agora.removeChannelMediaRelay(config);
117
+    }
118
+
119
+    /**
120
+     * Updates to relay media streams across channels.
121
+     * 
122
+     * This method will update relay media stream across specified channels. (maximum support 4 channels)
123
+     * It will occurs event:
124
+     *  Occurs onChannelMediaRelayStateChanged
125
+     * @param config
126
+     */
127
+    public static updateChannelMediaRelay(config: ChannelMediaConfiguration): Promise<any> {
128
+        return Agora.updateChannelMediaRelay(config);
129
+    }
130
+
131
+    /**
132
+     * Stop to relay media streams across channels.
133
+     * 
134
+     * This method will stop relay media stream across specified channels.
135
+     * It will occurs event:
136
+     *  Occurs onChannelMediaRelayStateChanged
137
+     * @param config
138
+     */
139
+    public static stopChannelMediaRelay(): Promise<any> {
140
+        return Agora.stopChannelMediaRelay();
141
+    }
142
+
79
     /**
143
     /**
80
      * Registers a user account.
144
      * Registers a user account.
81
      * 
145
      * 
182
      * connectionLost | occurs when sdk connection lost | on("connectionLost", evt) |
246
      * connectionLost | occurs when sdk connection lost | on("connectionLost", evt) |
183
      * tokenPrivilegeWillExpire | occurs when token will expire | on("tokenPrivilegeWillExpire", evt) |
247
      * tokenPrivilegeWillExpire | occurs when token will expire | on("tokenPrivilegeWillExpire", evt) |
184
      * requestToken | occurs when token expired | on("requestToken") |
248
      * requestToken | occurs when token expired | on("requestToken") |
185
-     * microphoneEnabled | occurs when microphone enable state changed | on("microphoneEnabled", evt) |
249
+     * localAudioStateChanged | occurs when local audio device state changed | on("localAudioStateChanged", (state, errorCode) => {}) |
186
      * audioVolumeIndication | occurs when audio volume indication changed | on("audioVolumeIndication", evt) |
250
      * audioVolumeIndication | occurs when audio volume indication changed | on("audioVolumeIndication", evt) |
187
      * activeSpeaker | occurs when detect active speaker | on("activeSpeaker", evt) |
251
      * activeSpeaker | occurs when detect active speaker | on("activeSpeaker", evt) |
188
      * firstLocalAudioFrame | occurs when sent first audio frame on local | on("firstLocalAudioFrame", evt) |
252
      * firstLocalAudioFrame | occurs when sent first audio frame on local | on("firstLocalAudioFrame", evt) |
189
      * firstRemoteAudioFrame | occurs when received first audio frame from remote side | on("firstRemoteAudioFrame", evt) |
253
      * firstRemoteAudioFrame | occurs when received first audio frame from remote side | on("firstRemoteAudioFrame", evt) |
190
      * firstRemoteAudioDecoded | occurs when first remote audio decoded | on("firstRemoteAudioDecoded", evt) |
254
      * firstRemoteAudioDecoded | occurs when first remote audio decoded | on("firstRemoteAudioDecoded", evt) |
191
      * firstLocalVideoFrame | occurs when sent first video frame on local | on("firstLocalVideoFrame", evt) |
255
      * firstLocalVideoFrame | occurs when sent first video frame on local | on("firstLocalVideoFrame", evt) |
192
-     * firstRemoteVideoDecoded | occurs when received first video frame from remote side decoded | on("firstRemoteVideoDecoded", evt) |
193
      * firstRemoteVideoFrame | occurs when received first video frame from remote side | on("firstRemoteVideoFrame", evt) |
256
      * firstRemoteVideoFrame | occurs when received first video frame from remote side | on("firstRemoteVideoFrame", evt) |
194
      * userMuteAudio | occurs when user mute audio | on("userMuteAudio", evt) |
257
      * userMuteAudio | occurs when user mute audio | on("userMuteAudio", evt) |
195
-     * userMuteVideo | occurs when user mute video | on("userMuteVideo", evt) |
196
-     * userEnableVideo | occurs when remote side's user change video enable state | on("userEnableVideo", evt) |
197
-     * userEnableLocalVideo | occurs when user change video enable state on local | on("userEnableLocalVideo", evt) |
198
      * videoSizeChanged | occurs when change local or remote side video size or rotation | on("videoSizeChanged", evt) |
258
      * videoSizeChanged | occurs when change local or remote side video size or rotation | on("videoSizeChanged", evt) |
199
      * remoteVideoStateChanged | occurs when remote video state has any changed | on("remoteVideoStateChanged", evt) |
259
      * remoteVideoStateChanged | occurs when remote video state has any changed | on("remoteVideoStateChanged", evt) |
260
+     * remoteAudioStateChanged | occurs when remote audio state has any changed | on("remoteAudioStateChanged", evt) |
261
+     * localAudioStats | occurs when engine start to report local audio stats | on("localAudioStats", evt) |
200
      * localPublishFallbackToAudioOnly | occurs when published stream from local side fallback to audio stream | on("localPublishFallbackToAudioOnly", evt) |
262
      * localPublishFallbackToAudioOnly | occurs when published stream from local side fallback to audio stream | on("localPublishFallbackToAudioOnly", evt) |
201
      * remoteSubscribeFallbackToAudioOnly | occurs when subscribed side's stream fallback to audio stream | on("remoteSubscribeFallbackToAudioOnly", evt) |
263
      * remoteSubscribeFallbackToAudioOnly | occurs when subscribed side's stream fallback to audio stream | on("remoteSubscribeFallbackToAudioOnly", evt) |
202
      * audioRouteChanged | occurs when local audio route changed | on("audioRouteChanged", evt) |
264
      * audioRouteChanged | occurs when local audio route changed | on("audioRouteChanged", evt) |
208
      * localVideoStats | occurs when reports local video statistics | on("localVideoStats", evt) | 
270
      * localVideoStats | occurs when reports local video statistics | on("localVideoStats", evt) | 
209
      * remoteVideoStats | occurs when reports remote video statistics| on("remoteVideoStats", evt) | 
271
      * remoteVideoStats | occurs when reports remote video statistics| on("remoteVideoStats", evt) | 
210
      * remoteAudioStats | occurs when reports remote audio statistics| on("remoteAudioStats", evt) | 
272
      * remoteAudioStats | occurs when reports remote audio statistics| on("remoteAudioStats", evt) | 
211
-     * audioTransportStatsOfUid | occurs when reports  transport-layer statistics of each remote audio stream. | on("audioTransportStatsOfUid", evt) | 
212
-     * videoTransportStatsOfUid | occurs when reports  transport-layer statistics of each remote video stream.| on("videoTransportStatsOfUid", evt) | 
213
      * audioEffectFinish | occurs when the local audio effect playback finishes. | on("audioEffectFinish", evt) | 
273
      * audioEffectFinish | occurs when the local audio effect playback finishes. | on("audioEffectFinish", evt) | 
214
      * streamPublished | occurs when addPublishStreamUrl success| on("streamPublished", evt) | 
274
      * streamPublished | occurs when addPublishStreamUrl success| on("streamPublished", evt) | 
215
      * streamUnpublish | occurs when removePublishStreamUrl success| on("streamUnpublish", evt) | 
275
      * streamUnpublish | occurs when removePublishStreamUrl success| on("streamUnpublish", evt) | 
226
      * mediaMetaDataReceived | occurs when you received media meta data from the remote side through sendMediaData | on("mediaMetaDataReceived", evt) | 
286
      * mediaMetaDataReceived | occurs when you received media meta data from the remote side through sendMediaData | on("mediaMetaDataReceived", evt) | 
227
      * localUserRegistered | occurs when you register user account success | on("localUserRegistered", evt) |
287
      * localUserRegistered | occurs when you register user account success | on("localUserRegistered", evt) |
228
      * userInfoUpdated | occurs when you peer side using user account join channel | on("userInfoUpdated", evt) |
288
      * userInfoUpdated | occurs when you peer side using user account join channel | on("userInfoUpdated", evt) |
289
+     * receivedChannelMediaRelay | occurs when you received channel media relay | on('receivedChannelMediaRelay", evt)|
290
+     * mediaRelayStateChanged | occurs when you received remote media relay state changed | on('mediaRelayStateChanged", evt)|
229
      * ---
291
      * ---
230
      * 
292
      * 
231
      * @param eventType
293
      * @param eventType
244
             'receiveStreamMessage',
306
             'receiveStreamMessage',
245
             'activeSpeaker',
307
             'activeSpeaker',
246
             'firstRemoteAudioFrame',
308
             'firstRemoteAudioFrame',
247
-            'firstRemoteVideoDecoded',
248
             'firstRemoteVideoFrame',
309
             'firstRemoteVideoFrame',
249
             'userMuteAudio',
310
             'userMuteAudio',
250
-            'userMuteVideo',
251
-            'userEnableVideo',
252
-            'userEnableLocalVideo',
253
             'videoSizeChanged',
311
             'videoSizeChanged',
254
-            'firstRemoteAudioDecoded',
255
             'remoteVideoStateChanged',
312
             'remoteVideoStateChanged',
313
+            'remoteAudioStateChanged',
256
             'remoteSubscribeFallbackToAudioOnly',
314
             'remoteSubscribeFallbackToAudioOnly',
257
             'networkQuality',
315
             'networkQuality',
258
             'streamInjectedStatus',
316
             'streamInjectedStatus',
295
         if ([
353
         if ([
296
             'remoteAudioStats',
354
             'remoteAudioStats',
297
             'remoteVideoStats',
355
             'remoteVideoStats',
298
-            'audioTransportStatsOfUid',
299
-            'videoTransportStatsOfUid',   
300
         ].indexOf(eventType) != -1) {
356
         ].indexOf(eventType) != -1) {
301
             AgoraEventEmitter.addListener(`${RtcEngine.AG_PREFIX}${eventType}`, (args) => {
357
             AgoraEventEmitter.addListener(`${RtcEngine.AG_PREFIX}${eventType}`, (args) => {
302
                 args.stats.uid = this.Int32ToUint32(args.stats.uid);
358
                 args.stats.uid = this.Int32ToUint32(args.stats.uid);
389
             for (let eventType of this._eventTypes) {
445
             for (let eventType of this._eventTypes) {
390
                 AgoraEventEmitter.removeAllListeners(eventType);
446
                 AgoraEventEmitter.removeAllListeners(eventType);
391
             }
447
             }
392
-            this._eventTypes.clear()
448
+            this._eventTypes.clear();
393
         }
449
         }
394
         return Agora.destroy();
450
         return Agora.destroy();
395
     }
451
     }

+ 29
- 0
src/types.ts View File

1
 import { ViewProps } from 'react-native';
1
 import { ViewProps } from 'react-native';
2
 
2
 
3
+/**
4
+ * ChannelMediaInfo
5
+ * @property channelName: string
6
+ * @property token: string
7
+ * @property uid: number
8
+ */
9
+export interface ChannelMediaInfo {
10
+  channelName: string
11
+  token?: string
12
+  uid?: number
13
+}
14
+/**
15
+ * ChannelMediaConfiguration
16
+ * @property src: {
17
+ *    @member channelName,
18
+ *    @member token,
19
+ *    @member uid,
20
+ * }
21
+ * @property channels: {@link Array<ChannelMediaInfo>}
22
+ */
23
+export interface ChannelMediaConfiguration {
24
+  src?: {
25
+    channelName: string
26
+    token?: string
27
+    uid?: number
28
+  }
29
+  channels: Array<ChannelMediaInfo>
30
+}
31
+
3
 /**
32
 /**
4
  * AgoraViewMode
33
  * AgoraViewMode
5
  * @mode hidden Uniformly scale the video until it fills the visible boundaries (cropped). One dimension of the video may have clipped contents.
34
  * @mode hidden Uniformly scale the video until it fills the visible boundaries (cropped). One dimension of the video may have clipped contents.