Skip to content

Commit

Permalink
Merge pull request #264 from opentok/0.10.0
Browse files Browse the repository at this point in the history
v0.10.0
  • Loading branch information
Manik Sachdeva authored Apr 16, 2019
2 parents 36cd37e + 7d02122 commit f5e6c38
Show file tree
Hide file tree
Showing 17 changed files with 305 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,20 @@ public OTPublisherLayout(ThemedReactContext reactContext) {
public void createPublisherView(String publisherId) {

ConcurrentHashMap<String, Publisher> mPublishers = sharedState.getPublishers();
String pubOrSub = sharedState.getAndroidOnTop();
String zOrder = sharedState.getAndroidZOrder();
Publisher mPublisher = mPublishers.get(publisherId);
if (mPublisher != null) {
mPublisher.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE,
BaseVideoRenderer.STYLE_VIDEO_FILL);
FrameLayout mPublisherViewContainer = new FrameLayout(getContext());
if (pubOrSub.equals("publisher") && mPublisher.getView() instanceof GLSurfaceView) {
if (zOrder.equals("mediaOverlay")) {
((GLSurfaceView) mPublisher.getView()).setZOrderMediaOverlay(true);
} else {
((GLSurfaceView) mPublisher.getView()).setZOrderOnTop(true);
}
}
ConcurrentHashMap<String, FrameLayout> mPublisherViewContainers = sharedState.getPublisherViewContainers();
mPublisherViewContainers.put(publisherId, mPublisherViewContainer);
addView(mPublisherViewContainer, 0);
Expand Down
39 changes: 34 additions & 5 deletions android/src/main/java/com/opentokreactnative/OTRN.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import android.widget.FrameLayout;

import com.opentok.android.Connection;
import com.opentok.android.Publisher;
import com.opentok.android.Session;
import com.opentok.android.Stream;
Expand All @@ -18,13 +19,16 @@ public class OTRN {

public static OTRN sharedState;
private Session mSession;
private String mAndroidOnTop;
private String mAndroidZOrder;

private ConcurrentHashMap<String, Stream> subscriberStreams = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, Subscriber> subscribers = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, Publisher> publishers = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, FrameLayout> subscriberViewContainers = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, FrameLayout> publisherViewContainers = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, Callback> publisherDestroyedCallbacks = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, Connection> connections = new ConcurrentHashMap<>();

public static synchronized OTRN getSharedState() {

Expand All @@ -39,6 +43,31 @@ public synchronized Session getSession() {
return this.mSession;
}

public synchronized void setSession(Session mSession) {

this.mSession = mSession;
}

public synchronized String getAndroidOnTop() {

return this.mAndroidOnTop;
}

public synchronized void setAndroidOnTop(String androidOnTop) {

this.mAndroidOnTop = androidOnTop;
}

public synchronized String getAndroidZOrder() {

return this.mAndroidZOrder;
}

public synchronized void setAndroidZOrder(String androidZOrder) {

this.mAndroidZOrder = androidZOrder;
}


public ConcurrentHashMap<String, Stream> getSubscriberStreams() {

Expand All @@ -55,11 +84,6 @@ public ConcurrentHashMap<String, FrameLayout> getSubscriberViewContainers() {
return this.subscriberViewContainers;
}

public synchronized void setSession(Session mSession) {

this.mSession = mSession;
}

public ConcurrentHashMap<String, Publisher> getPublishers() {

return this.publishers;
Expand All @@ -75,5 +99,10 @@ public ConcurrentHashMap<String, Callback> getPublisherDestroyedCallbacks() {
return this.publisherDestroyedCallbacks;
}

public ConcurrentHashMap<String, Connection> getConnections() {

return this.connections;
}

private OTRN() {}
}
53 changes: 45 additions & 8 deletions android/src/main/java/com/opentokreactnative/OTSessionManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,36 @@ public OTSessionManager(ReactApplicationContext reactContext) {
}

@ReactMethod
public void initSession(String apiKey, String sessionId) {

Session mSession = new Session.Builder(this.getReactApplicationContext(), apiKey, sessionId).build();
public void initSession(String apiKey, String sessionId, ReadableMap sessionOptions) {

final boolean useTextureViews = sessionOptions.getBoolean("useTextureViews");
final boolean isCamera2Capable = sessionOptions.getBoolean("isCamera2Capable");
final boolean connectionEventsSuppressed = sessionOptions.getBoolean("connectionEventsSuppressed");
String androidOnTop = sessionOptions.getString("androidOnTop");
String androidZOrder = sessionOptions.getString("androidZOrder");

Session mSession = new Session.Builder(this.getReactApplicationContext(), apiKey, sessionId)
.sessionOptions(new Session.SessionOptions() {
@Override
public boolean useTextureViews() {
return useTextureViews;
}

@Override
public boolean isCamera2Capable() {
return isCamera2Capable;
}
})
.connectionEventsSuppressed(connectionEventsSuppressed)
.build();
mSession.setSessionListener(this);
mSession.setSignalListener(this);
mSession.setConnectionListener(this);
mSession.setReconnectionListener(this);
mSession.setArchiveListener(this);
mSession.setStreamPropertiesListener(this);
sharedState.setAndroidOnTop(androidOnTop);
sharedState.setAndroidZOrder(androidZOrder);
sharedState.setSession(mSession);
}

Expand Down Expand Up @@ -155,7 +176,8 @@ public void publish(String publisherId, Callback callback) {
mSession.publish(mPublisher);
callback.invoke();
} else {
callback.invoke("There was an error publishing");
WritableMap errorInfo = EventUtils.createError("Error publishing. Could not find native publisher instance.");
callback.invoke(errorInfo);
}

}
Expand All @@ -181,7 +203,8 @@ public void subscribeToStream(String streamId, ReadableMap properties, Callback
mSession.subscribe(mSubscriber);
callback.invoke(null, streamId);
} else {
callback.invoke("Error subscribring. The native session instance could not be found.");
WritableMap errorInfo = EventUtils.createError("Error subscribing. The native session instance could not be found.");
callback.invoke(errorInfo);
}

}
Expand Down Expand Up @@ -312,13 +335,23 @@ public void removeJSComponentEvents(ReadableArray events) {
public void sendSignal(ReadableMap signal, Callback callback) {

Session mSession = sharedState.getSession();
if (mSession != null){
ConcurrentHashMap<String, Connection> mConnections = sharedState.getConnections();
String connectionId = signal.getString("to");
Connection mConnection = null;
if (connectionId != null) {
mConnection = mConnections.get(connectionId);
}
if (mConnection != null && mSession != null) {
mSession.sendSignal(signal.getString("type"), signal.getString("data"), mConnection);
callback.invoke();
} else if (mSession != null) {
mSession.sendSignal(signal.getString("type"), signal.getString("data"));
callback.invoke();
} else {
callback.invoke("There was an error sending the signal. The native session instance could not be found.");
WritableMap errorInfo = EventUtils.createError("There was an error sending the signal. The native session instance could not be found.");
callback.invoke(errorInfo);
}

}

@ReactMethod
Expand Down Expand Up @@ -497,6 +530,8 @@ public void onArchiveStopped(Session session, String id) {
@Override
public void onConnectionCreated(Session session, Connection connection) {

ConcurrentHashMap<String, Connection> mConnections = sharedState.getConnections();
mConnections.put(connection.getConnectionId(), connection);
WritableMap connectionInfo = EventUtils.prepareJSConnectionMap(connection);
sendEventMap(this.getReactApplicationContext(), sessionPreface + "onConnectionCreated", connectionInfo);
printLogs("onConnectionCreated: Connection Created: "+connection.getConnectionId());
Expand All @@ -505,6 +540,8 @@ public void onConnectionCreated(Session session, Connection connection) {
@Override
public void onConnectionDestroyed(Session session, Connection connection) {

ConcurrentHashMap<String, Connection> mConnections = sharedState.getConnections();
mConnections.remove(connection.getConnectionId());
WritableMap connectionInfo = EventUtils.prepareJSConnectionMap(connection);
sendEventMap(this.getReactApplicationContext(), sessionPreface + "onConnectionDestroyed", connectionInfo);
printLogs("onConnectionDestroyed: Connection Destroyed: "+connection.getConnectionId());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.opentokreactnative;

import android.opengl.GLSurfaceView;
import android.view.Gravity;
import android.widget.FrameLayout;

Expand All @@ -25,11 +26,20 @@ public OTSubscriberLayout(ThemedReactContext reactContext) {
public void createSubscriberView(String streamId) {

ConcurrentHashMap<String, Subscriber> mSubscribers = sharedState.getSubscribers();
String pubOrSub = sharedState.getAndroidOnTop();
String zOrder = sharedState.getAndroidZOrder();
Subscriber mSubscriber = mSubscribers.get(streamId);
FrameLayout mSubscriberViewContainer = new FrameLayout(getContext());
if (mSubscriber != null) {
mSubscriber.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE,
BaseVideoRenderer.STYLE_VIDEO_FILL);
if (pubOrSub.equals("subscriber") && mSubscriber.getView() instanceof GLSurfaceView) {
if (zOrder.equals("mediaOverlay")) {
((GLSurfaceView) mSubscriber.getView()).setZOrderMediaOverlay(true);
} else {
((GLSurfaceView) mSubscriber.getView()).setZOrderOnTop(true);
}
}
ConcurrentHashMap<String, FrameLayout> mSubscriberViewContainers = sharedState.getSubscriberViewContainers();
mSubscriberViewContainers.put(streamId, mSubscriberViewContainer);
addView(mSubscriberViewContainer, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,11 @@ public static WritableMap prepareVideoNetworkStats(SubscriberKit.SubscriberVideo
videoStats.putInt("videoPacketsReceived", stats.videoPacketsReceived);
return videoStats;
}

public static WritableMap createError(String message) {

WritableMap errorInfo = Arguments.createMap();
errorInfo.putString("message", message);
return errorInfo;
}
}
2 changes: 2 additions & 0 deletions docs/OTPublisher.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ Please keep in mind that `OT` is not the same as `OT` in the JS SDK, the `OT` in

* **error** (Object) — Sent if the publisher encounters an error. After this message is sent, the publisher can be considered fully detached from a session and may be released.

* **otrnError** (Object) — Sent if there is an error with the communication between the native publisher instance and the JS component.

* **streamCreated** (Object) — Sent when the publisher starts streaming.

* **streamDestroyed** (Object) - Sent when the publisher stops streaming.
56 changes: 54 additions & 2 deletions docs/OTSession.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
| apiKey | String | Yes | TokBox API Key
| sessionId | String | Yes | TokBox Session ID
| token | String | Yes | TokBox token
| options | Object | No | Used to define session options
| signal | Object | No | Used to send a signal to the session
| eventHandlers | Object&lt;Function&gt; | No | Event handlers passed into the native session instance.

Expand All @@ -13,19 +14,39 @@ The `OTSession` component manages the connection to an OpenTok Session. It passe
class App extends Component {
constructor(props) {
super(props);
this.state = {
isConnected: false,
};
this.otSessionRef = React.createRef();
this.sessionEventHandlers = {
streamCreated: event => {
console.log('Stream created!', event);
},
streamDestroyed: event => {
console.log('Stream destroyed!', event);
},
sessionConnected: event => {
this.setState({
isConnected: true,
})
}
};
}

sendSignal = () => {
const { isConnected } = this.state;
if (isConnected) {
this.otSessionRef.signal({
data: '',
to: '', // optional - connectionId of connected client you want to send the signal to
type: '', // optional
})
}
}

render() {
return (
<OTSession apiKey="your-api-key" sessionId="your-session-id" token="your-session-token" eventHandlers={this.sesssionEventHandlers}>
<OTSession apiKey="your-api-key" sessionId="your-session-id" token="your-session-token" eventHandlers={this.sesssionEventHandlers} ref={this.otSessionRef}>
<OTPublisher style={{ width: 100, height: 100 }}/>
<OTSubscriber style={{ width: 100, height: 100 }} />
</OTSession>
Expand All @@ -45,6 +66,8 @@ class App extends Component {

* **error** (Object) — Sent if the attempt to connect to the session fails or if the connection to the session drops due to an error after a successful connection.

* **otrnError** (Object) — Sent if there is an error with the communication between the native session instance and the JS component.

* **sessionConnected** () - Sent when the client connects to the session.

* **sessionDisconnected** () — Sent when the client disconnects from the session.
Expand All @@ -57,4 +80,33 @@ class App extends Component {

* **streamCreated** (Object) — Sent when a new stream is created in this session.

* **streamDestroyed** (Object) - Sent when a stream is no longer published to the session.
* **streamDestroyed** (Object) - Sent when a stream is no longer published to the session.

* **streamPropertyChanged** (Object) - Sent when a stream has started or stopped publishing audio or video or if the video dimensions of the stream have changed.

### Setting Session options:

You can set the session options using the `options` prop. Please note that all session options are optional:
```javascript
class App extends Component {
constructor(props) {
super(props);
this.sessionOptions = {
connectionEventsSuppressed: true, // default is false
androidZOrder: '', // Android only - valid options are 'mediaOverlay' or 'onTop'
androidOnTop: '', // Android only - valid options are 'publisher' or 'subscriber'
useTextureViews: true, // Android only - default is false
isCamera2Capable: false, // Android only - default is false
};
}

render() {
return (
<OTSession apiKey="your-api-key" sessionId="your-session-id" token="your-session-token" options={this.sessionOptions}>
<OTPublisher style={{ width: 100, height: 100 }}/>
<OTSubscriber style={{ width: 100, height: 100 }} />
</OTSession>
);
}
}
```
2 changes: 2 additions & 0 deletions docs/OTSubscriber.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ The `OTSubscriber` component will subscribe to a specified stream from a specifi

* **error** (Object) — Sent if the subscriber fails to connect to its stream.

* **otrnError** (Object) — Sent if there is an error with the communication between the native subscriber instance and the JS component.

* **videoDataReceived** () - Sent when a frame of video has been decoded. Although the subscriber will connect in a relatively short time, video can take more time to synchronize. This message is sent after the `connected` message is sent.

* **videoDisabled** (String) — This message is sent when the subscriber stops receiving video. Check the reason parameter for the reason why the video stopped.
Expand Down
1 change: 1 addition & 0 deletions ios/OpenTokReactNative/OTRN.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class OTRN : NSObject {
var publisherDestroyedCallbacks = [String: RCTResponseSenderBlock]()
var isPublishing = [String: Bool]()
var streamObservers = [String: [NSKeyValueObservation]]()
var connections = [String: OTConnection]()
override init() {
super.init()
}
Expand Down
3 changes: 2 additions & 1 deletion ios/OpenTokReactNative/OTSessionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ @interface RCT_EXTERN_MODULE(OTSessionManager, RCTEventEmitter)

RCT_EXTERN_METHOD(initSession:
(NSString*)apiKey
sessionId:(NSString*)sessionId)
sessionId:(NSString*)sessionId
sessionOptions:(NSDictionary*)sessionOptions)
RCT_EXTERN_METHOD(connect:
(NSString*)token
callback:(RCTResponseSenderBlock*)callback)
Expand Down
Loading

0 comments on commit f5e6c38

Please sign in to comment.