Browse Source

support. android custom raw data api

matrixbirds 5 years ago
parent
commit
deaf93af61

+ 15
- 0
CHANGELOG View File

@@ -2,6 +2,21 @@
2 2
 
3 3
 #### 2.9.0-alpha.1
4 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` relay media streams operation for across channels.
5 20
 
6 21
 #### 2.8.0-alpha.1
7 22
   - add `string uid` api support

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

@@ -0,0 +1,781 @@
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/cpp/include/IAgoraMediaEngine.h View File

@@ -0,0 +1,215 @@
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/cpp/include/IAgoraRtcEngine.h
File diff suppressed because it is too large
View File


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

@@ -0,0 +1,76 @@
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/cpp/include/VMUtil.h View File

@@ -0,0 +1,53 @@
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/cpp/src/agora_media_pre_processing.cpp View File

@@ -0,0 +1,327 @@
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/cpp/src/agora_media_pre_processing.h View File

@@ -0,0 +1,77 @@
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

+ 0
- 1
android/src/main/java/com/syan/agora/AgoraConst.java View File

@@ -19,7 +19,6 @@ public class AgoraConst {
19 19
     public final static String AGTokenPrivilegeWillExpire = "tokenPrivilegeWillExpire";
20 20
     public final static String AGRequestToken = "requestToken";
21 21
 
22
-    public final static String AGMicrophoneEnabled = "microphoneEnabled";
23 22
     public final static String AGAudioVolumeIndication = "audioVolumeIndication";
24 23
     public final static String AGActiveSpeaker = "activeSpeaker";
25 24
     public final static String AGFirstLocalAudioFrame = "firstLocalAudioFrame";

+ 28
- 13
android/src/main/java/com/syan/agora/AgoraModule.java View File

@@ -2,6 +2,7 @@ package com.syan.agora;
2 2
 
3 3
 import android.graphics.Rect;
4 4
 import android.support.annotation.Nullable;
5
+import android.view.SurfaceView;
5 6
 
6 7
 import com.facebook.react.bridge.Arguments;
7 8
 import com.facebook.react.bridge.Callback;
@@ -494,19 +495,6 @@ public class AgoraModule extends ReactContextBaseJavaModule {
494 495
             });
495 496
         }
496 497
 
497
-        @Override
498
-        public void onMicrophoneEnabled(final boolean enabled) {
499
-            runOnUiThread(new Runnable() {
500
-                @Override
501
-                public void run() {
502
-                    WritableMap map = Arguments.createMap();
503
-                    map.putBoolean("enabled", enabled);
504
-                    sendEvent(getReactApplicationContext(), AGMicrophoneEnabled, map);
505
-                }
506
-
507
-            });
508
-        }
509
-
510 498
         @Override
511 499
         public void onAudioVolumeIndication(final AudioVolumeInfo [] speakers, final int totalVolume) {
512 500
             runOnUiThread(new Runnable() {
@@ -2074,6 +2062,33 @@ public class AgoraModule extends ReactContextBaseJavaModule {
2074 2062
         }
2075 2063
     }
2076 2064
 
2065
+    private static boolean recording = false;
2066
+
2067
+    // TODO: need implementation
2068
+    @ReactMethod
2069
+    public void startAVRecording(final ReadableMap option, final Promise promise) {
2070
+        String path = option.getString("path");
2071
+        Integer uid = option.getInt("uid");
2072
+        String format = option.getString("format");
2073
+        if (true == recording) {
2074
+            promise.reject("-1", "recording already started");
2075
+        }
2076
+        SurfaceView view = AgoraManager.getInstance().getSurfaceView(uid);
2077
+        if (null == view) {
2078
+            promise.reject("-1", "recording already started");
2079
+        }
2080
+    }
2081
+
2082
+    // TODO: need implementation
2083
+    @ReactMethod
2084
+    public void stopAVRecording(final Promise promise) {
2085
+        if (false == recording) {
2086
+            promise.reject("-1", "recording didn't start");
2087
+        } else {
2088
+            promise.resolve(null);
2089
+        }
2090
+    }
2091
+
2077 2092
     public LiveInjectStreamConfig.AudioSampleRateType getAudioSampleRateEnum (int val) {
2078 2093
         LiveInjectStreamConfig.AudioSampleRateType type = LiveInjectStreamConfig.AudioSampleRateType.TYPE_32000;
2079 2094
         switch (Integer.valueOf(val)) {

+ 170
- 4
android/src/main/java/com/syan/agora/AgoraVideoView.java View File

@@ -1,18 +1,38 @@
1 1
 package com.syan.agora;
2 2
 
3 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 11
 import android.util.AttributeSet;
5
-import android.view.SurfaceView;
12
+import android.util.Log;
6 13
 import android.view.View;
7 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 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 36
     public boolean isShowLocalVideo() {
17 37
         return showLocalVideo;
18 38
     }
@@ -27,7 +47,6 @@ public class AgoraVideoView extends LinearLayout {
27 47
 
28 48
     public void setRenderMode(Integer renderMode) {
29 49
         this.renderMode = renderMode;
30
-
31 50
     }
32 51
 
33 52
     public Integer getRemoteUid() {
@@ -74,4 +93,151 @@ public class AgoraVideoView extends LinearLayout {
74 93
             }
75 94
         }
76 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
+    }
126
+
127
+    private static final String VCODEC_MIME = "video/avc";
128
+
129
+    private String audioFilePath;
130
+    private String videoFilePath;
131
+
132
+    private Future<Void> audioFuture = null;
133
+    private Future<Void> videoFuture = null;
134
+    private int colorFormat;
135
+    private MediaCodec vencoder;
136
+
137
+    private ExecutorService executor = Executors.newSingleThreadExecutor();
138
+
139
+    public void setAudioFilePath(String path) {
140
+        audioFilePath = path;
141
+    }
142
+
143
+    public void setVideoFilePath(String path) {
144
+        videoFilePath = path;
145
+    }
146
+
147
+    private static MediaCodecInfo selectCodec(String mimeType) {
148
+        int numCodecs = MediaCodecList.getCodecCount();
149
+        for (int i = 0; i < numCodecs; i++) {
150
+            MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
151
+
152
+            if (!codecInfo.isEncoder()) {
153
+                continue;
154
+            }
155
+            String[] types = codecInfo.getSupportedTypes();
156
+            for (int j = 0; j < types.length; j++) {
157
+                if (types[j].equalsIgnoreCase(mimeType)) {
158
+                    return codecInfo;
159
+                }
160
+            }
161
+        }
162
+        return null;
163
+    }
164
+
165
+    private void logColorFormatName(int format) {
166
+        switch (format) {
167
+            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible:
168
+                Log.d("video", "COLOR_FormatYUV420Flexible");
169
+                break;
170
+            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
171
+                Log.d("video", "COLOR_FormatYUV420PackedPlanar");
172
+                break;
173
+            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
174
+                Log.d("video", "COLOR_FormatYUV420Planar");
175
+                break;
176
+            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
177
+                Log.d("video", "COLOR_FormatYUV420PackedSemiPlanar");
178
+                break;
179
+            case COLOR_FormatYUV420SemiPlanar:
180
+                Log.d("video", "COLOR_FormatYUV420SemiPlanar");
181
+                break;
182
+        }
183
+    }
184
+
185
+
186
+    private int getColorFormat(MediaCodecInfo mediaCodecInfo) {
187
+        int matchedFormat = 0;
188
+        MediaCodecInfo.CodecCapabilities codecCapabilities =
189
+                mediaCodecInfo.getCapabilitiesForType(VCODEC_MIME);
190
+        for (int i = 0; i < codecCapabilities.colorFormats.length; i++) {
191
+            int format = codecCapabilities.colorFormats[i];
192
+            if (format >= codecCapabilities.COLOR_FormatYUV420Planar &&
193
+                    format <= codecCapabilities.COLOR_FormatYUV420PackedSemiPlanar) {
194
+                if (format >= matchedFormat) {
195
+                    matchedFormat = format;
196
+                    logColorFormatName(format);
197
+                    break;
198
+                }
199
+            }
200
+        }
201
+        return matchedFormat;
202
+    }
203
+
204
+
205
+    private void initVideoEncoder() {
206
+        MediaCodecInfo mediaCodecInfo = selectCodec(VCODEC_MIME);
207
+        colorFormat = getColorFormat(mediaCodecInfo);
208
+
209
+        String TAG = remoteUid.toString();
210
+        try {
211
+            vencoder = MediaCodec.createByCodecName(mediaCodecInfo.getName());
212
+            Log.d(TAG, "编码器:" + mediaCodecInfo.getName() + "创建完成!");
213
+        } catch (IOException e) {
214
+            e.printStackTrace();
215
+            throw new RuntimeException("vencodec初始化失败!", e);
216
+        }
217
+        MediaFormat mediaFormat = MediaFormat
218
+                .createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, this.getWidth(), this.getHeight());
219
+        mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);
220
+        mediaFormat.setInteger(KEY_BIT_RATE, 300 * 1000);
221
+        mediaFormat.setInteger(KEY_COLOR_FORMAT, colorFormat);
222
+        mediaFormat.setInteger(KEY_FRAME_RATE, 30);
223
+        mediaFormat.setInteger(KEY_I_FRAME_INTERVAL, 5);
224
+        vencoder.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
225
+        vencoder.start();
226
+    }
227
+
228
+    private MediaMuxer vmuxer = null;
229
+
230
+    private int videoTrackIndex;
231
+
232
+    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
233
+    public void startMuxerVideo () {
234
+        try {
235
+            vmuxer = new MediaMuxer(videoFilePath,
236
+                    MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
237
+            videoTrackIndex = vmuxer.addTrack(vencoder.getOutputFormat());
238
+            vmuxer.start();
239
+        } catch (IOException ex) {
240
+            ex.printStackTrace();
241
+        }
242
+    }
77 243
 }

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

@@ -0,0 +1,29 @@
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

@@ -0,0 +1,13 @@
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

@@ -0,0 +1,297 @@
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

@@ -0,0 +1,8 @@
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

@@ -0,0 +1,39 @@
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
+}

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


+ 2
- 2
src/RtcEngine.native.ts View File

@@ -50,7 +50,7 @@ class RtcEngine {
50 50
      * @ignore AG_PREFIX
51 51
      */ 
52 52
     private static readonly AG_PREFIX: string = 'ag_rtc';
53
-
53
+    
54 54
     /**
55 55
      * Creates a RtcEngine Object internal.
56 56
      *
@@ -406,7 +406,7 @@ class RtcEngine {
406 406
             for (let eventType of this._eventTypes) {
407 407
                 AgoraEventEmitter.removeAllListeners(eventType);
408 408
             }
409
-            this._eventTypes.clear()
409
+            this._eventTypes.clear();
410 410
         }
411 411
         return Agora.destroy();
412 412
     }