diff --git a/android/build.gradle b/android/build.gradle index 5564a7dc8..0ef917370 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -61,7 +61,7 @@ dependencies { def androidSupportVersion = rootProject.hasProperty("androidSupportVersion") ? rootProject.androidSupportVersion : DEFAULT_ANDROID_SUPPORT_VERSION // from internet implementation "com.android.support:appcompat-v7:$androidSupportVersion" - implementation "io.agora.rtc:full-sdk:2.8.2" + implementation "io.agora.rtc:full-sdk:2.9.0" // from node_modules implementation "com.facebook.react:react-native:+" } diff --git a/android/src/main/java/com/syan/agora/AgoraConst.java b/android/src/main/java/com/syan/agora/AgoraConst.java index 481fb83a7..a83e83e02 100644 --- a/android/src/main/java/com/syan/agora/AgoraConst.java +++ b/android/src/main/java/com/syan/agora/AgoraConst.java @@ -25,12 +25,8 @@ public class AgoraConst { public final static String AGFirstLocalAudioFrame = "firstLocalAudioFrame"; public final static String AGFirstRemoteAudioFrame = "firstRemoteAudioFrame"; public final static String AGFirstLocalVideoFrame = "firstLocalVideoFrame"; - public final static String AGFirstRemoteVideoDecoded = "firstRemoteVideoDecoded"; public final static String AGFirstRemoteVideoFrame = "firstRemoteVideoFrame"; public final static String AGUserMuteAudio = "userMuteAudio"; - public final static String AGUserMuteVideo = "userMuteVideo"; - public final static String AGUserEnableVideo = "userEnableVideo"; - public final static String AGUserEnableLocalVideo = "userEnableLocalVideo"; public final static String AGVideoSizeChanged = "videoSizeChanged"; public final static String AGRtmpStreamingStateChanged = "rtmpStreamingStateChanged"; public final static String AGNetworkTypeChanged = "networkTypeChanged"; @@ -44,6 +40,11 @@ public class AgoraConst { public final static String AGAudioRouteChanged = "audioRouteChanged"; public final static String AGCameraFocusAreaChanged = "cameraFocusAreaChanged"; public final static String AGCameraExposureAreaChanged = "cameraExposureAreaChanged"; + public final static String AGRemoteAudioStateChanged = "remoteAudioStateChanged"; + public final static String AGLocalAudioStateChanged = "localAudioStateChanged"; + public final static String AGLocalAudioStats = "localAudioStats"; + public final static String AGMediaRelayStateChanged = "mediaRelayStateChanged"; + public final static String AGReceivedChannelMediaRelay = "receivedChannelMediaRelay"; public final static String AGRtcStats = "rtcStats"; public final static String AGLastmileQuality = "lastmileQuality"; @@ -51,8 +52,6 @@ public class AgoraConst { public final static String AGLocalVideoStats = "localVideoStats"; public final static String AGRemoteVideoStats = "remoteVideoStats"; public final static String AGRemoteAudioStats = "remoteAudioStats"; - public final static String AGAudioTransportStatsOfUid = "audioTransportStatsOfUid"; - public final static String AGVideoTransportStatsOfUid = "videoTransportStatsOfUid"; public final static String AGRemoteAudioMixingStart = "remoteAudioMixingStart"; public final static String AGRemoteAudioMixingFinish = "remoteAudioMixingFinish"; diff --git a/android/src/main/java/com/syan/agora/AgoraModule.java b/android/src/main/java/com/syan/agora/AgoraModule.java index b2c6fb2d5..8e40b5edb 100644 --- a/android/src/main/java/com/syan/agora/AgoraModule.java +++ b/android/src/main/java/com/syan/agora/AgoraModule.java @@ -34,6 +34,8 @@ import io.agora.rtc.video.AgoraImage; import io.agora.rtc.video.BeautyOptions; import io.agora.rtc.video.CameraCapturerConfiguration; +import io.agora.rtc.video.ChannelMediaInfo; +import io.agora.rtc.video.ChannelMediaRelayConfiguration; import io.agora.rtc.video.VideoEncoderConfiguration; import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread; @@ -276,7 +278,7 @@ public void onWarning(final int code) { public void run() { WritableMap map = Arguments.createMap(); map.putString("message", "AgoraWarning"); - map.putInt("code", code); + map.putInt("errorCode", code); sendEvent(getReactApplicationContext(), AGWarning, map); } }); @@ -289,7 +291,7 @@ public void onError(final int code) { public void run() { WritableMap map = Arguments.createMap(); map.putString("message", "AgoraError"); - map.putInt("code", code); + map.putInt("errorCode", code); sendEvent(getReactApplicationContext(), AGError, map); } }); @@ -301,7 +303,7 @@ public void onApiCallExecuted(final int code, final String api, final String res @Override public void run() { WritableMap map = Arguments.createMap(); - map.putInt("error", code); + map.putInt("errorCode", code); map.putString("api", api); map.putString("result", result); if (code != 0) { @@ -350,8 +352,12 @@ public void run() { statsMap.putInt("duration", stats.totalDuration); statsMap.putInt("txBytes", stats.txBytes); statsMap.putInt("rxBytes", stats.rxBytes); - // statsMap.putInt("txKBitRate", stats.txKBitRate); - // statsMap.putInt("rxKBitRate", stats.rxKBitRate); + statsMap.putInt("txAudioBytes", stats.txAudioBytes); + statsMap.putInt("txVideoBytes", stats.txVideoBytes); + statsMap.putInt("rxAudioBytes", stats.rxAudioBytes); + statsMap.putInt("rxVideoBytes", stats.rxVideoBytes); + statsMap.putInt("txKBitRate", stats.txKBitRate); + statsMap.putInt("rxKBitRate", stats.rxKBitRate); statsMap.putInt("txAudioKBitRate", stats.txAudioKBitRate); statsMap.putInt("rxAudioKBitRate", stats.rxAudioKBitRate); statsMap.putInt("txVideoKBitRate", stats.txVideoKBitRate); @@ -574,24 +580,6 @@ public void run() { }); } - /** - * onFirstRemoteVideoDecoded - */ - @Override - public void onFirstRemoteVideoDecoded(final int uid, final int width, final int height, final int elapsed) { - runOnUiThread(new Runnable() { - @Override - public void run() { - WritableMap map = Arguments.createMap(); - map.putInt("uid", uid); - map.putInt("width", width); - map.putInt("height", height); - map.putInt("elapsed", elapsed); - sendEvent(getReactApplicationContext(), AGFirstRemoteVideoDecoded, map); - } - }); - } - @Override public void onFirstRemoteVideoFrame(final int uid, final int width, final int height, final int elapsed) { runOnUiThread(new Runnable() { @@ -621,81 +609,73 @@ public void run() { } @Override - public void onUserMuteVideo(final int uid, final boolean muted) { + public void onVideoSizeChanged(final int uid, final int width, final int height, final int rotation) { runOnUiThread(new Runnable() { @Override public void run() { WritableMap map = Arguments.createMap(); - map.putBoolean("muted", muted); map.putInt("uid", uid); - sendEvent(getReactApplicationContext(), AGUserMuteVideo, map); + map.putInt("width", width); + map.putInt("height", height); + map.putInt("rotation", rotation); + sendEvent(getReactApplicationContext(), AGVideoSizeChanged, map); } }); } @Override - public void onUserEnableVideo(final int uid, final boolean enabled) { + public void onRtmpStreamingStateChanged(final String url, final int state, final int errCode) { runOnUiThread(new Runnable() { @Override public void run() { WritableMap map = Arguments.createMap(); - map.putBoolean("enabled", enabled); - map.putInt("uid", uid); - sendEvent(getReactApplicationContext(), AGUserEnableVideo, map); + map.putString("url", url); + map.putInt("state", state); + map.putInt("errorCode", errCode); + sendEvent(getReactApplicationContext(), AGRtmpStreamingStateChanged, map); } }); } @Override - public void onUserEnableLocalVideo(final int uid, final boolean enabled) { + public void onNetworkTypeChanged(final int type) { runOnUiThread(new Runnable() { @Override public void run() { WritableMap map = Arguments.createMap(); - map.putBoolean("enabled", enabled); - map.putInt("uid", uid); - sendEvent(getReactApplicationContext(), AGUserEnableLocalVideo, map); + map.putInt("type", type); + sendEvent(getReactApplicationContext(), AGNetworkTypeChanged, map); } }); } - @Override - public void onVideoSizeChanged(final int uid, final int width, final int height, final int rotation) { - runOnUiThread(new Runnable() { - @Override - public void run() { - WritableMap map = Arguments.createMap(); - map.putInt("uid", uid); - map.putInt("width", width); - map.putInt("height", height); - map.putInt("rotation", rotation); - sendEvent(getReactApplicationContext(), AGVideoSizeChanged, map); - } - }); - } @Override - public void onRtmpStreamingStateChanged(final String url, final int state, final int errCode) { + public void onLocalAudioStateChanged(final int state, final int errCode) { runOnUiThread(new Runnable() { @Override public void run() { WritableMap map = Arguments.createMap(); - map.putString("url", url); map.putInt("state", state); map.putInt("errorCode", errCode); - sendEvent(getReactApplicationContext(), AGRtmpStreamingStateChanged, map); + sendEvent(getReactApplicationContext(), AGLocalAudioStateChanged, map); } }); } - @Override - public void onNetworkTypeChanged(final int type) { + public void onRemoteAudioStateChanged(final int uid, + final int state, + final int reason, + final int elapsed) { runOnUiThread(new Runnable() { @Override public void run() { WritableMap map = Arguments.createMap(); - map.putInt("type", type); - sendEvent(getReactApplicationContext(), AGNetworkTypeChanged, map); + map.putInt("uid", uid); + map.putInt("state", state); + map.putInt("uid", reason); + map.putInt("elapsed", elapsed); + sendEvent(getReactApplicationContext(), AGRemoteAudioStateChanged, map); } }); } @@ -714,13 +694,18 @@ public void run() { } @Override - public void onRemoteVideoStateChanged(final int uid, final int state) { + public void onRemoteVideoStateChanged(final int uid, + final int state, + final int reason, + final int elapsed) { runOnUiThread(new Runnable() { @Override public void run() { WritableMap map = Arguments.createMap(); map.putInt("uid", uid); map.putInt("state", state); + map.putInt("reason", reason); + map.putInt("elapsed", elapsed); sendEvent(getReactApplicationContext(), AGRemoteVideoStateChanged, map); } }); @@ -829,7 +814,13 @@ public void run() { statsMap.putInt("duration", stats.totalDuration); statsMap.putInt("txBytes", stats.txBytes); statsMap.putInt("rxBytes", stats.rxBytes); - statsMap.putInt("txAudioKBitRate", stats.txAudioKBitRate); + statsMap.putInt("txAudioBytes", stats.txAudioBytes); + statsMap.putInt("txVideoBytes", stats.txVideoBytes); + statsMap.putInt("rxAudioBytes", stats.rxAudioBytes); + statsMap.putInt("rxVideoBytes", stats.rxVideoBytes); + statsMap.putInt("txKBitRate", stats.txKBitRate); + statsMap.putInt("rxKBitRate", stats.rxKBitRate); + statsMap.putInt("rxVideoKBitRate", stats.rxVideoKBitRate); statsMap.putInt("rxAudioKBitRate", stats.rxAudioKBitRate); statsMap.putInt("txVideoKBitRate", stats.txVideoKBitRate); statsMap.putInt("rxVideoKBitRate", stats.rxVideoKBitRate); @@ -884,6 +875,14 @@ public void run() { statsMap.putInt("sentFrameRate", stats.sentFrameRate); statsMap.putInt("encoderOutputFrameRate", stats.encoderOutputFrameRate); statsMap.putInt("rendererOutputFrameRate", stats.rendererOutputFrameRate); + statsMap.putInt("targetBitrate", stats.targetBitrate); + statsMap.putInt("targetFrameRate", stats.targetFrameRate); + statsMap.putInt("qualityAdaptIndication", stats.qualityAdaptIndication); + statsMap.putInt("encodedBitrate", stats.encodedBitrate); + statsMap.putInt("encodedFrameWidth", stats.encodedFrameWidth); + statsMap.putInt("encodedFrameHeight", stats.encodedFrameHeight); + statsMap.putInt("encodedFrameCount", stats.encodedFrameCount); + statsMap.putInt("codecType", stats.codecType); WritableMap map = Arguments.createMap(); map.putMap("stats", statsMap); sendEvent(getReactApplicationContext(), AGLocalVideoStats, map); @@ -901,7 +900,9 @@ public void run() { statsMap.putInt("width", stats.width); statsMap.putInt("height", stats.height); statsMap.putInt("receivedBitrate", stats.receivedBitrate); + statsMap.putInt("decoderOutputFrameRate", stats.decoderOutputFrameRate); statsMap.putInt("rendererOutputFrameRate", stats.rendererOutputFrameRate); + statsMap.putInt("packetLossRate", stats.packetLossRate); statsMap.putInt("rxStreamType", stats.rxStreamType); statsMap.putInt("totalFrozenTime", stats.totalFrozenTime); statsMap.putInt("frozenRate", stats.frozenRate); @@ -912,46 +913,6 @@ public void run() { }); } - @Override - public void onRemoteAudioTransportStats(final int uid, - final int delay, - final int lost, - final int rxKBitRate) { - runOnUiThread(new Runnable() { - @Override - public void run() { - WritableMap statsMap = Arguments.createMap(); - statsMap.putInt("uid", uid); - statsMap.putInt("delay", delay); - statsMap.putInt("lost", lost); - statsMap.putInt("rxKBitRate", rxKBitRate); - WritableMap map = Arguments.createMap(); - map.putMap("stats", statsMap); - sendEvent(getReactApplicationContext(), AGAudioTransportStatsOfUid, map); - } - }); - } - - @Override - public void onRemoteVideoTransportStats(final int uid, - final int delay, - final int lost, - final int rxKBitRate) { - runOnUiThread(new Runnable() { - @Override - public void run() { - WritableMap statsMap = Arguments.createMap(); - statsMap.putInt("uid", uid); - statsMap.putInt("delay", delay); - statsMap.putInt("lost", lost); - statsMap.putInt("rxKBitRate", rxKBitRate); - WritableMap map = Arguments.createMap(); - map.putMap("stats", statsMap); - sendEvent(getReactApplicationContext(), AGVideoTransportStatsOfUid, map); - } - }); - } - @Override public void onAudioMixingStateChanged(final int state, final int errorCode) { runOnUiThread(new Runnable() { @@ -984,7 +945,7 @@ public void onStreamPublished(final String url, final int errorCode) { public void run() { WritableMap map = Arguments.createMap(); map.putString("url", url); - map.putInt("code", errorCode); + map.putInt("errorCode", errorCode); sendEvent(getReactApplicationContext(), AGStreamPublished, map); } }); @@ -1054,7 +1015,7 @@ public void run() { WritableMap map = Arguments.createMap(); map.putInt("uid", uid); map.putInt("streamId", streamId); - map.putInt("error", error); + map.putInt("errorCode", error); map.putInt("missed", missed); map.putInt("cached", cached); sendEvent(getReactApplicationContext(), AGOccurStreamMessageError, map); @@ -1112,6 +1073,48 @@ public void run() { } }); } + + @Override + public void onChannelMediaRelayEvent(final int code) { + super.onChannelMediaRelayEvent(code); + runOnUiThread(new Runnable() { + @Override + public void run() { + WritableMap map = Arguments.createMap(); + map.putInt("errorCode", code); + sendEvent(getReactApplicationContext(), AGReceivedChannelMediaRelay, map); + } + }); + } + + @Override + public void onChannelMediaRelayStateChanged(final int state, final int code) { + super.onChannelMediaRelayStateChanged(state, code); + runOnUiThread(new Runnable() { + @Override + public void run() { + WritableMap map = Arguments.createMap(); + map.putInt("state", state); + map.putInt("errorCode", code); + sendEvent(getReactApplicationContext(), AGMediaRelayStateChanged, map); + } + }); + } + + @Override + public void onLocalAudioStats(final LocalAudioStats rtcStats) { + super.onLocalAudioStats(rtcStats); + runOnUiThread(new Runnable() { + @Override + public void run() { + WritableMap map = Arguments.createMap(); + map.putInt("numChannels", rtcStats.numChannels); + map.putInt("sentSampleRate", rtcStats.sentSampleRate); + map.putInt("sentBitrate", rtcStats.sentBitrate); + sendEvent(getReactApplicationContext(), AGLocalAudioStats, map); + } + }); + } }; @ReactMethod @@ -1162,10 +1165,14 @@ public void setClientRole(int role, Promise promise) { } } + private String channelName = null; + @ReactMethod public void joinChannel(ReadableMap options, Promise promise) { Integer res = AgoraManager.getInstance().joinChannel(options); if (res == 0) { + String channelName = options.getString("channelName"); + this.channelName = channelName; promise.resolve(null); } else { promise.reject("-1", res.toString()); @@ -1188,8 +1195,10 @@ public void joinChannelWithUserAccount(ReadableMap options, Promise promise) { if (options.hasKey("token")) { token = options.getString("token"); } + String channelName = options.getString("channelName"); Integer res = rtcEngine.joinChannelWithUserAccount(token, options.getString("channelName"), options.getString("userAccount")); if (res == 0) { + this.channelName = channelName; promise.resolve(null); } else { promise.reject("-1", res.toString()); @@ -1224,6 +1233,24 @@ public void getUserInfoByUserAccount(String userAccount, Promise promise) { } } + @ReactMethod + public void switchChannel(ReadableMap options, Promise promise) { + String token = null; + String channel = null; + if (options.hasKey("token")) { + token = options.getString("token"); + } + if (options.hasKey("channelName")) { + channel = options.getString("channelName"); + } + Integer res = AgoraManager.getInstance().mRtcEngine.switchChannel(token, channel); + if (res == 0) { + promise.resolve(null); + } else { + promise.reject("-1", res.toString()); + } + } + @ReactMethod public void leaveChannel(Promise promise) { Integer res = AgoraManager.getInstance().leaveChannel(); @@ -1239,6 +1266,81 @@ public void destroy() { RtcEngine.destroy(); } + + + @ReactMethod + public void startChannelMediaRelay(ReadableMap options, Promise promise) { + ChannelMediaRelayConfiguration config = new ChannelMediaRelayConfiguration(); + ReadableMap srcOption = options.getMap("src"); + ChannelMediaInfo src = config.getSrcChannelMediaInfo(); + if (srcOption.hasKey("token")) { + src.token = srcOption.getString("token"); + } + if (srcOption.hasKey("channelName")) { + src.channelName = srcOption.getString("channelName"); + } + ReadableMap dstMediaInfo = options.getMap("dst"); + String dstChannelName = null; + Integer dstUid = 0; + String dstToken = null; + if (dstMediaInfo.hasKey("token")) { + dstToken = options.getString("token"); + } + if (dstMediaInfo.hasKey("channelName")) { + dstChannelName = options.getString("channelName"); + } + if (dstMediaInfo.hasKey("uid")) { + dstUid = options.getInt("uid"); + } + ChannelMediaInfo dest = new ChannelMediaInfo(dstChannelName, dstToken, dstUid); + config.setDestChannelInfo(dest.channelName, dest); + Integer res = AgoraManager.getInstance().mRtcEngine.startChannelMediaRelay(config); + if (res == 0) { + promise.resolve(null); + } else { + promise.reject("-1", res.toString()); + } + } + + @ReactMethod + public void updateChannelMediaRelay(ReadableMap options, Promise promise) { + ChannelMediaRelayConfiguration config = new ChannelMediaRelayConfiguration(); + ReadableMap srcOption = options.getMap("src"); + ChannelMediaInfo src = config.getSrcChannelMediaInfo(); + if (srcOption.hasKey("token")) { + src.token = srcOption.getString("token"); + } + if (srcOption.hasKey("channelName")) { + src.channelName = srcOption.getString("channelName"); + } + ReadableMap dstMediaInfo = options.getMap("dst"); + String dstChannelName = null; + Integer dstUid = 0; + String dstToken = null; + if (dstMediaInfo.hasKey("token")) { + dstToken = options.getString("token"); + } + if (dstMediaInfo.hasKey("channelName")) { + dstChannelName = options.getString("channelName"); + } + if (dstMediaInfo.hasKey("uid")) { + dstUid = options.getInt("uid"); + } + ChannelMediaInfo dest = new ChannelMediaInfo(dstChannelName, dstToken, dstUid); + config.setDestChannelInfo(dest.channelName, dest); + Integer res = AgoraManager.getInstance().mRtcEngine.updateChannelMediaRelay(config); + if (res == 0) { + promise.resolve(null); + } else { + promise.reject("-1", res.toString()); + } + } + + @ReactMethod + public void stopChannelMediaRelay() { + AgoraManager.getInstance().mRtcEngine.stopChannelMediaRelay(); + } + @ReactMethod public void startPreview(Promise promise) { Integer res = AgoraManager.getInstance().startPreview(); diff --git a/android/src/main/java/com/syan/agora/AgoraVideoView.java b/android/src/main/java/com/syan/agora/AgoraVideoView.java index ddad5b0eb..4a324b5d2 100644 --- a/android/src/main/java/com/syan/agora/AgoraVideoView.java +++ b/android/src/main/java/com/syan/agora/AgoraVideoView.java @@ -50,7 +50,6 @@ public void setZOrderMediaOverlay(boolean zOrderMediaOverlay) { private Integer renderMode = 1; private Integer remoteUid; private boolean zOrderMediaOverlay; - private SurfaceView surfaceView; public AgoraVideoView(Context context) { super(context); diff --git a/ios/RCTAgora/AgoraConst.h b/ios/RCTAgora/AgoraConst.h index 68820e059..08d13ea7e 100644 --- a/ios/RCTAgora/AgoraConst.h +++ b/ios/RCTAgora/AgoraConst.h @@ -68,6 +68,9 @@ static NSString *AGStreamInjectedStatus = @"streamInjectedStatus"; static NSString *AGReceiveStreamMessage = @"receiveStreamMessage"; static NSString *AGOccurStreamMessageError = @"occurStreamMessageError"; +static NSString *AGReceivedChannelMediaRelay = @"receivedChannelMediaRelay"; +static NSString *AGMediaRelayStateChanged = @"mediaRelayStateChanged"; + static NSString *AGMediaEngineLoaded = @"mediaEngineLoaded"; static NSString *AGMediaEngineStartCall = @"mediaEngineStartCall"; diff --git a/ios/RCTAgora/AgoraConst.m b/ios/RCTAgora/AgoraConst.m index be07527cb..a8a803a2f 100644 --- a/ios/RCTAgora/AgoraConst.m +++ b/ios/RCTAgora/AgoraConst.m @@ -85,6 +85,9 @@ + (instancetype)share { AGReceiveStreamMessage, AGOccurStreamMessageError, + AGReceivedChannelMediaRelay, + AGMediaRelayStateChanged, + AGMediaEngineLoaded, AGMediaEngineStartCall, AGIntervalTest, diff --git a/ios/RCTAgora/RCTAgora.m b/ios/RCTAgora/RCTAgora.m index cb4062ce6..c3a54ef14 100644 --- a/ios/RCTAgora/RCTAgora.m +++ b/ios/RCTAgora/RCTAgora.m @@ -48,7 +48,7 @@ - (NSData *_Nullable)readyToSendMetadataAtTimestamp:(NSTimeInterval)timestamp return toSend; } -- (void)receiveMetadata:(NSData *_Nonnull)data fromUser:(NSUInteger)uid atTimestamp:(NSTimeInterval)timestamp { +- (void)receiveMetadata:(NSData *_Nonnull)data fromUser:(NSInteger)uid atTimestamp:(NSTimeInterval)timestamp { NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; [self sendEvent:AGMediaMetaDataReceived params:@{ @"uid": @(uid), @@ -313,6 +313,67 @@ - (NSDictionary *)constantsToExport { } } +// startChannelMediaRelay +RCT_EXPORT_METHOD(startChannelMediaRelay:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) { + AgoraChannelMediaRelayConfiguration *config = [[AgoraChannelMediaRelayConfiguration alloc] init]; + + AgoraChannelMediaRelayInfo *src = [config sourceInfo]; + NSDictionary *srcOption = options[@"src"]; + src.channelName = srcOption[@"channelName"]; + src.uid = [srcOption[@"uid"] integerValue]; + src.token = srcOption[@"token"]; + AgoraChannelMediaRelayInfo *dst = [[AgoraChannelMediaRelayInfo alloc] init]; + NSDictionary *dstOption = options[@"dst"]; + dst.channelName = dstOption[@"channelName"]; + dst.uid = [dstOption[@"uid"] integerValue]; + dst.token = dstOption[@"token"]; + [config setDestinationInfo:dst forChannelName:dstOption[@"channelName"]]; + NSInteger res = [self.rtcEngine startChannelMediaRelay:config]; + if (res == 0) { + resolve(nil); + } else { + reject(@(-1).stringValue, @(res).stringValue, nil); + } +} + +// updateChannelMediaRelay +RCT_EXPORT_METHOD(updateChannelMediaRelay:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) { + AgoraChannelMediaRelayConfiguration *config = [[AgoraChannelMediaRelayConfiguration alloc] init]; + + AgoraChannelMediaRelayInfo *src = [config sourceInfo]; + NSDictionary *srcOption = options[@"src"]; + src.channelName = srcOption[@"channelName"]; + src.uid = [srcOption[@"uid"] integerValue]; + src.token = srcOption[@"token"]; + AgoraChannelMediaRelayInfo *dst = [[AgoraChannelMediaRelayInfo alloc] init]; + NSDictionary *dstOption = options[@"dst"]; + dst.channelName = dstOption[@"channelName"]; + dst.uid = [dstOption[@"uid"] integerValue]; + dst.token = dstOption[@"token"]; + [config setDestinationInfo:dst forChannelName:dstOption[@"channelName"]]; + NSInteger res = [self.rtcEngine updateChannelMediaRelay:config]; + if (res == 0) { + resolve(nil); + } else { + reject(@(-1).stringValue, @(res).stringValue, nil); + } +} + +// stopChannelMediaRelay +RCT_EXPORT_METHOD(stopChannelMediaRelay:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) { + NSInteger res = [self.rtcEngine stopChannelMediaRelay]; + if (res == 0) { + resolve(nil); + } else { + reject(@(-1).stringValue, @(res).stringValue, nil); + } +} + // register user account RCT_EXPORT_METHOD(registerLocalUserAccount:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve @@ -927,7 +988,7 @@ - (NSDictionary *)constantsToExport { // set volume of effect RCT_EXPORT_METHOD(setVolumeOfEffect - :(NSInteger) soundId + :(int) soundId volume:(double)volume resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { @@ -1717,11 +1778,11 @@ - (void) stopObserving { #pragma mark - // EVENT CALLBACKS - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didOccurWarning:(AgoraWarningCode)warningCode { - [self sendEvent:AGWarning params:@{@"message": @"AgoraWarning", @"code": @(warningCode)}]; + [self sendEvent:AGWarning params:@{@"message": @"AgoraWarning", @"errorCode": @(warningCode)}]; } - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didOccurError:(AgoraErrorCode)errorCode { - [self sendEvent:AGError params:@{@"message": @"AgoraError", @"code": @(errorCode)}]; + [self sendEvent:AGError params:@{@"message": @"AgoraError", @"errorCode": @(errorCode)}]; } - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didApiCallExecute:(NSInteger)error api:(NSString *_Nonnull)api result:(NSString *_Nonnull)result { @@ -1729,13 +1790,13 @@ - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didApiCallExecute:(NSInteg [self sendEvent:AGError params:@{ @"api": api, @"result": result, - @"error": @(error) + @"errorCode": @(error) }]; } else { [self sendEvent:AGApiCallExecute params:@{ @"api": api, @"result": result, - @"error": @(error) + @"errorCode": @(error) }]; } } @@ -1852,7 +1913,7 @@ - (void)rtcEngineRequestToken:(AgoraRtcEngineKit *_Nonnull)engine { - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine localAudioStateChange:(AgoraAudioLocalState)state error:(AgoraAudioLocalError)error { [self sendEvent:AGLocalAudioStateChanged params:@{ @"state": @(state), - @"error": @(error) + @"errorCode": @(error) }]; } @@ -1945,10 +2006,12 @@ - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine videoSizeChangedOfUid:(NSU }]; } -- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine remoteVideoStateChangedOfUid:(NSUInteger)uid state:(AgoraVideoRemoteState)state { +- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine remoteVideoStateChangedOfUid:(NSUInteger)uid state:(AgoraVideoRemoteState)state reason:(AgoraVideoRemoteStateReason)reason elapsed:(NSInteger)elapsed { [self sendEvent:AGRemoteVideoStateChanged params:@{ @"uid": @(uid), - @"state": @(state) + @"state": @(state), + @"reason": @(reason), + @"elapsed": @(elapsed) }]; } @@ -2087,7 +2150,7 @@ - (void)rtcEngineDidAudioEffectFinish:(AgoraRtcEngineKit *_Nonnull)engine soundI - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine streamPublishedWithUrl:(NSString *_Nonnull)url errorCode:(AgoraErrorCode)errorCode { [self sendEvent:AGStreamPublished params:@{ @"url": url, - @"code": @(errorCode) + @"errorCode": @(errorCode) }]; } @@ -2126,6 +2189,19 @@ - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine streamInjectedStatusOfUrl: }]; } +- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine channelMediaRelayStateDidChange:(AgoraChannelMediaRelayState)state error:(AgoraChannelMediaRelayError)error { + [self sendEvent:AGMediaRelayStateChanged params:@{ + @"state": @(state), + @"errorCode": @(error), + }]; +} + +- (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didReceiveChannelMediaRelayEvent:(AgoraChannelMediaRelayEvent)event { + [self sendEvent:AGReceivedChannelMediaRelay params:@{ + @"event": @(event), + }]; +} + - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine receiveStreamMessageFromUid:(NSUInteger)uid streamId:(NSInteger)streamId data:(NSData *_Nonnull)data { NSString *_data = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; [self sendEvent:AGReceiveStreamMessage params:@{ @@ -2138,7 +2214,7 @@ - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didOccurStreamMessageError [self sendEvent:AGOccurStreamMessageError params:@{ @"uid": @(uid), @"streamId": @(streamId), - @"error": @(error), + @"errorCode": @(error), @"missed": @(missed), @"cached": @(cached) }];