Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[android] Room recording status #568

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 67 additions & 39 deletions android/src/main/java/com/twiliorn/library/CustomTwilioVideoView.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull;
import android.support.annotation.StringDef;
import androidx.annotation.NonNull;
import androidx.annotation.StringDef;
import android.util.Log;
import android.view.View;

Expand Down Expand Up @@ -103,6 +103,8 @@
import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_STATS_RECEIVED;
import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_VIDEO_CHANGED;
import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_DOMINANT_SPEAKER_CHANGED;
import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_RECORDING_STARTED;
import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_RECORDING_STOPPED;

public class CustomTwilioVideoView extends View implements LifecycleEventListener, AudioManager.OnAudioFocusChangeListener {
private static final String TAG = "CustomTwilioVideoView";
Expand Down Expand Up @@ -165,6 +167,8 @@ public class CustomTwilioVideoView extends View implements LifecycleEventListene
String ON_STATS_RECEIVED = "onStatsReceived";
String ON_NETWORK_QUALITY_LEVELS_CHANGED = "onNetworkQualityLevelsChanged";
String ON_DOMINANT_SPEAKER_CHANGED = "onDominantSpeakerDidChange";
String ON_RECORDING_STARTED = "onRecordingStarted";
String ON_RECORDING_STOPPED = "onRecordingStopped";
}

private final ThemedReactContext themedReactContext;
Expand Down Expand Up @@ -210,6 +214,8 @@ public class CustomTwilioVideoView extends View implements LifecycleEventListene

public CustomTwilioVideoView(ThemedReactContext context) {
super(context);
releaseResource();

this.themedReactContext = context;
this.eventEmitter = themedReactContext.getJSModule(RCTEventEmitter.class);

Expand Down Expand Up @@ -382,46 +388,54 @@ public void onHostPause() {

@Override
public void onHostDestroy() {
/*
* Remove stream voice control
*/
if (themedReactContext.getCurrentActivity() != null) {
themedReactContext.getCurrentActivity().setVolumeControlStream(AudioManager.USE_DEFAULT_STREAM_TYPE);
}
/*
* Always disconnect from the room before leaving the Activity to
* ensure any memory allocated to the Room resource is freed.
*/
if (room != null && room.getState() != Room.State.DISCONNECTED) {
room.disconnect();
disconnectedFromOnDestroy = true;
}

/*
* Release the local media ensuring any memory allocated to audio or video is freed.
*/
if (localVideoTrack != null) {
localVideoTrack.release();
localVideoTrack = null;
}

if (localAudioTrack != null) {
localAudioTrack.release();
localAudioTrack = null;
}

// Quit the data track message thread
dataTrackMessageThread.quit();


releaseResource();
}

public void releaseResource() {
themedReactContext.removeLifecycleEventListener(this);
room = null;
localVideoTrack = null;
thumbnailVideoView = null;
cameraCapturer = null;
thumbnailVideoView = null;
roomName = null;
accessToken = null;

/*
* Remove stream voice control
*/
if (themedReactContext != null && themedReactContext.getCurrentActivity() != null) {
themedReactContext.getCurrentActivity().setVolumeControlStream(AudioManager.USE_DEFAULT_STREAM_TYPE);
themedReactContext.removeLifecycleEventListener(this);
}
/*
* Always disconnect from the room before leaving the Activity to
* ensure any memory allocated to the Room resource is freed.
*/
if (room != null && room.getState() != Room.State.DISCONNECTED) {
room.disconnect();
disconnectedFromOnDestroy = true;
}
room = null;


if (localParticipant != null) {
localParticipant.unpublishTrack(localVideoTrack);
localParticipant = null;
}

if (localVideoTrack != null) {
localVideoTrack.release();
localVideoTrack = null;
}

if (localAudioTrack != null) {
localAudioTrack.release();
localAudioTrack = null;
}

if (cameraCapturer != null) {
cameraCapturer.stopCapture();
cameraCapturer = null;
}

// Quit the data track message thread
dataTrackMessageThread.quit();
}

// ====== CONNECTING ===========================================================================
Expand Down Expand Up @@ -804,6 +818,14 @@ public void onStats(List<StatsReport> statsReports) {
}
}

public boolean isActive() {
return room != null;
}

public boolean isRecording() {
return room.isRecording();
}

public void disableOpenSLES() {
WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true);
}
Expand Down Expand Up @@ -915,10 +937,16 @@ public void onParticipantDisconnected(Room room, RemoteParticipant participant)

@Override
public void onRecordingStarted(Room room) {
WritableMap event = new WritableNativeMap();

pushEvent(CustomTwilioVideoView.this, ON_RECORDING_STARTED, event);
}

@Override
public void onRecordingStopped(Room room) {
WritableMap event = new WritableNativeMap();

pushEvent(CustomTwilioVideoView.this, ON_RECORDING_STOPPED, event);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/
package com.twiliorn.library;

import android.support.annotation.Nullable;
import androidx.annotation.Nullable;

import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.common.MapBuilder;
Expand Down Expand Up @@ -40,6 +40,8 @@
import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_STATS_RECEIVED;
import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_NETWORK_QUALITY_LEVELS_CHANGED;
import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_DOMINANT_SPEAKER_CHANGED;
import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_RECORDING_STARTED;
import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_RECORDING_STOPPED;


public class CustomTwilioVideoViewManager extends SimpleViewManager<CustomTwilioVideoView> {
Expand All @@ -65,6 +67,12 @@ public String getName() {
return REACT_CLASS;
}

@Override
public void onDropViewInstance(CustomTwilioVideoView view) {
view.onHostDestroy();
super.onDropViewInstance(view);
}

@Override
protected CustomTwilioVideoView createViewInstance(ThemedReactContext reactContext) {
return new CustomTwilioVideoView(reactContext);
Expand Down Expand Up @@ -166,7 +174,9 @@ public Map getExportedCustomDirectEventTypeConstants() {
));

map.putAll(MapBuilder.of(
ON_PARTICIPANT_REMOVED_DATA_TRACK, MapBuilder.of("registrationName", ON_PARTICIPANT_REMOVED_DATA_TRACK)
ON_PARTICIPANT_REMOVED_DATA_TRACK, MapBuilder.of("registrationName", ON_PARTICIPANT_REMOVED_DATA_TRACK),
ON_RECORDING_STARTED, MapBuilder.of("registrationName", ON_RECORDING_STARTED),
ON_RECORDING_STOPPED, MapBuilder.of("registrationName", ON_RECORDING_STOPPED)
));

map.putAll(MapBuilder.of(
Expand Down Expand Up @@ -198,4 +208,8 @@ public Map<String, Integer> getCommandsMap() {
.put("sendString", SEND_STRING)
.build();
}

public boolean isRecording(CustomTwilioVideoView view) {
return view.isRecording();
}
}
6 changes: 4 additions & 2 deletions android/src/main/java/com/twiliorn/library/TwilioPackage.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@

public class TwilioPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
public List<NativeModule> createNativeModules(ReactApplicationContext reactApplicationContext) {
return Arrays.<NativeModule>asList(
new TwilioVideoModule(reactApplicationContext)
);
}

// Deprecated by RN 0.47
Expand Down
52 changes: 52 additions & 0 deletions android/src/main/java/com/twiliorn/library/TwilioVideoModule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.twiliorn.library;

import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;

import com.facebook.react.uimanager.UIBlock;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.NativeViewHierarchyManager;

public class TwilioVideoModule extends ReactContextBaseJavaModule {
private static final String TAG = "TwilioVideoModule";

private static ReactApplicationContext mReactContext;

public TwilioVideoModule(ReactApplicationContext reactContext) {
super(reactContext);
mReactContext = reactContext;
}

@Override
public String getName() {
return "TwilioVideoModule";
}

@ReactMethod
public void isRecording(final int viewTag, final Promise promise) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);

uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final CustomTwilioVideoView videoView;

try {
videoView = (CustomTwilioVideoView) nativeViewHierarchyManager.resolveView(viewTag);

if(!videoView.isActive()){
promise.reject("E_VIEW_UNAVAILABLE", "isRecording: Video is not running");
} else {
promise.resolve(videoView.isRecording());
}
} catch (Exception e) {
promise.reject("E_VIEW_NOT_FOUND", "isRecording: Expected a CustomTwilioVideoView component");
}
}
});
}
}
3 changes: 3 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ declare module "react-native-twilio-video-webrtc" {

onStatsReceived?: (data: any) => void;
onDataTrackMessageReceived?: DataTrackEventCb;
onRecordingStarted?: () => void;
onRecordingStopped?: () => void;
// iOS only
autoInitializeCamera?: boolean;
ref?: React.Ref<any>;
Expand Down Expand Up @@ -156,6 +158,7 @@ declare module "react-native-twilio-video-webrtc" {
publishLocalVideo: () => void;
unpublishLocalVideo: () => void;
sendString: (message: string) => void;
isRecording: () => Promise<boolean>;
}

class TwilioVideoLocalView extends React.Component<
Expand Down
Loading