diff --git a/build-extras.gradle b/build-extras.gradle
index 4a894f9d..b995e892 100644
--- a/build-extras.gradle
+++ b/build-extras.gradle
@@ -22,5 +22,4 @@ dependencies {
compile 'com.android.support:appcompat-v7:23.1.0'
compile 'com.android.support:design:23.0.0'
compile 'com.android.volley:volley:1.1.0'
- compile 'com.github.ksoichiro:android-observablescrollview:1.6.0'
}
diff --git a/plugin.xml b/plugin.xml
index 04f2748c..fdad4be6 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -9,10 +9,12 @@
Apache 2.0
opentok,tokbox
+
+
-
+
@@ -78,11 +80,14 @@
-
+
+
+
+
@@ -97,5 +102,5 @@
-
+
diff --git a/src/android/OpenTokAndroidPlugin.java b/src/android/OpenTokAndroidPlugin.java
index 58ca94d2..2cbc66dc 100644
--- a/src/android/OpenTokAndroidPlugin.java
+++ b/src/android/OpenTokAndroidPlugin.java
@@ -46,8 +46,6 @@
import com.opentok.android.SubscriberKit;
import com.opentok.android.BaseVideoRenderer;
-import com.github.ksoichiro.android.observablescrollview.ObservableScrollView;
-
public class OpenTokAndroidPlugin extends CordovaPlugin
implements Session.SessionListener,
Session.ConnectionListener,
@@ -73,12 +71,15 @@ public class OpenTokAndroidPlugin extends CordovaPlugin
public static final String[] perms = {Manifest.permission.INTERNET, Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};
public CallbackContext permissionsCallback;
-
public class RunnableUpdateViews implements Runnable {
public JSONArray mProperty;
public View mView;
public ArrayList allStreamViews;
+ // Used for setting the camera views.
+ public float widthRatio;
+ public float heightRatio;
+
public class CustomComparator implements Comparator {
@Override
public int compare(RunnableUpdateViews object1, RunnableUpdateViews object2) {
@@ -119,6 +120,18 @@ public int getZIndex() {
}
}
+ public void setPosition() {
+ try {
+ mView.setX(mProperty.getInt(2) * widthRatio);
+ mView.setY(mProperty.getInt(1) * heightRatio);
+
+ ViewGroup.LayoutParams params = mView.getLayoutParams();
+ params.width = (int) (mProperty.getInt(3) * widthRatio);
+ params.height = (int) (mProperty.getInt(4) * heightRatio);
+ mView.setLayoutParams(params);
+ } catch (Exception e) {}
+ }
+
@SuppressLint("NewApi")
@Override
public void run() {
@@ -126,8 +139,6 @@ public void run() {
Log.i(TAG, "updating view in ui runnable" + mProperty.toString());
Log.i(TAG, "updating view in ui runnable " + mView.toString());
- float widthRatio, heightRatio;
-
// Ratios are index 6 & 7 on TB.updateViews, 8 & 9 on subscribe event, and 9 & 10 on TB.initPublisher
int ratioIndex;
if (mProperty.get(6) instanceof Number) {
@@ -143,12 +154,7 @@ public void run() {
widthRatio = (float) mProperty.getDouble(ratioIndex) * metrics.density;
heightRatio = (float) mProperty.getDouble(ratioIndex + 1) * metrics.density;
- mView.setY(mProperty.getInt(1) * heightRatio);
- mView.setX(mProperty.getInt(2) * widthRatio);
- ViewGroup.LayoutParams params = mView.getLayoutParams();
- params.height = (int) (mProperty.getInt(4) * heightRatio);
- params.width = (int) (mProperty.getInt(3) * widthRatio);
- mView.setLayoutParams(params);
+ setPosition();
updateZIndices();
} catch (Exception e) {
Log.i(TAG, "error when trying to retrieve properties while resizing properties");
@@ -421,22 +427,6 @@ public void initialize(CordovaInterface cordova, CordovaWebView webView) {
// Make the web view transparent.
_webView.getView().setBackgroundColor(Color.argb(1, 0, 0, 0));
-
- cordova.getActivity().runOnUiThread(new Runnable() {
- @Override
- public void run() {
- // original layout
- ViewGroup frameLayout = (ViewGroup) _webView.getView().getParent();
- ViewGroup layoutParent = (ViewGroup) frameLayout.getParent();
- layoutParent.removeView(frameLayout);
-
- // Observable scroll view with webView and cameraViews as children
- ObservableScrollView scrollView = new ObservableScrollView(_cordova.getActivity().getApplicationContext());
- scrollView.addView(frameLayout);
- layoutParent.addView(scrollView);
- }
- });
-
Log.d(TAG, "Initialize Plugin");
// By default, get a pointer to mainView and add mainView to the viewList as it always exists (hold cordova's view)
if (!viewList.has("mainView")) {
@@ -586,6 +576,30 @@ public void run() {
cordova.getActivity().runOnUiThread(runsub);
}
}
+ } else if (action.equals("hasStatusBarPlugin")) {
+ // Currently only needed for iOS, but for the sake of sanity we include it here aswell.
+ } else if (action.equals("updateCamera")) {
+ int top = args.getInt(1);
+ int left = args.getInt(2);
+ int width = args.getInt(3);
+ int height = args.getInt(4);
+
+ if (args.getString(0).equals("TBPublisher") && myPublisher != null && sessionConnected) {
+ myPublisher.mProperty.put(1, top);
+ myPublisher.mProperty.put(2, left);
+ myPublisher.mProperty.put(3, width);
+ myPublisher.mProperty.put(4, height);
+
+ myPublisher.setPosition();
+ } else {
+ RunnableSubscriber runsub = subscriberCollection.get(args.getString(0));
+ runsub.mProperty.put(1, top);
+ runsub.mProperty.put(2, left);
+ runsub.mProperty.put(3, width);
+ runsub.mProperty.put(4, height);
+
+ runsub.setPosition();
+ }
} else if (action.equals("exceptionHandler")) {
}
diff --git a/src/ios/OpenTokPlugin.m b/src/ios/OpenTokPlugin.m
index eb507e5d..e7d2188e 100644
--- a/src/ios/OpenTokPlugin.m
+++ b/src/ios/OpenTokPlugin.m
@@ -17,6 +17,7 @@ @implementation OpenTokPlugin{
NSMutableDictionary *callbackList;
NSString *apiKey;
NSString *sessionId;
+ Boolean statusBarPlugin;
}
@synthesize exceptionId;
@@ -28,6 +29,7 @@ -(void) pluginInitialize{
[self.webView setOpaque:false];
[self.webView setBackgroundColor:UIColor.clearColor];
+ statusBarPlugin = true;
callbackList = [[NSMutableDictionary alloc] init];
}
- (void)addEvent:(CDVInvokedUrlCommand*)command{
@@ -164,8 +166,9 @@ - (void)initPublisher:(CDVInvokedUrlCommand *)command{
[_publisher setPublishAudio:bpubAudio];
[_publisher setPublishVideo:bpubVideo];
[_publisher setAudioFallbackEnabled:baudioFallbackEnabled];
- [self.webView.scrollView addSubview:_publisher.view];
- [_publisher.view setFrame:CGRectMake(left, top, width, height)];
+ [self.webView.superview addSubview:_publisher.view];
+
+ [self setPosition: @"TBPublisher" top: top left: left width: width height: height];
// Set depth location of camera view based on CSS z-index.
_publisher.view.layer.zPosition = zIndex;
@@ -187,9 +190,11 @@ - (void)updateView:(CDVInvokedUrlCommand*)command{
int width = [[command.arguments objectAtIndex:3] intValue];
int height = [[command.arguments objectAtIndex:4] intValue];
int zIndex = [[command.arguments objectAtIndex:5] intValue];
+
if ([sid isEqualToString:@"TBPublisher"]) {
NSLog(@"The Width is: %d", width);
- _publisher.view.frame = CGRectMake(left, top, width, height);
+ // Reposition the video feeds!
+ [self setPosition: sid top: top left: left width: width height: height];
// Set depth location of camera view based on CSS z-index.
_publisher.view.layer.zPosition = zIndex;
@@ -197,7 +202,7 @@ - (void)updateView:(CDVInvokedUrlCommand*)command{
// If the zIndex is 0(default) bring the view to the top, last one wins.
// See: https://github.com/saghul/cordova-plugin-iosrtc/blob/5b6a180b324c8c9bac533fa481a457b74183c740/src/PluginMediaStreamRenderer.swift#L191
if(zIndex == 0) {
- [self.webView.scrollView bringSubviewToFront:_publisher.view];
+ [self.webView.superview bringSubviewToFront:_publisher.view];
}
}
@@ -206,7 +211,7 @@ - (void)updateView:(CDVInvokedUrlCommand*)command{
if (streamInfo) {
// Reposition the video feeds!
- streamInfo.view.frame = CGRectMake(left, top, width, height);
+ [self setPosition: sid top: top left: left width: width height: height];
// Set depth location of camera view based on CSS z-index.
streamInfo.view.layer.zPosition = zIndex;
@@ -214,7 +219,7 @@ - (void)updateView:(CDVInvokedUrlCommand*)command{
// If the zIndex is 0(default) bring the view to the top, last one wins.
// See: https://github.com/saghul/cordova-plugin-iosrtc/blob/5b6a180b324c8c9bac533fa481a457b74183c740/src/PluginMediaStreamRenderer.swift#L191
if(zIndex == 0) {
- [self.webView.scrollView bringSubviewToFront:_publisher.view];
+ [self.webView.superview bringSubviewToFront:_publisher.view];
}
}
@@ -223,6 +228,35 @@ - (void)updateView:(CDVInvokedUrlCommand*)command{
//[self.commandDelegate sendPluginResult:callbackResult toSuccessCallbackString:command.callbackId];
[self.commandDelegate sendPluginResult:callbackResult callbackId:command.callbackId];
}
+- (void)hasStatusBarPlugin:(CDVInvokedUrlCommand*)command{
+ statusBarPlugin = [[command.arguments objectAtIndex:0] boolValue];
+}
+- (void)updateCamera:(CDVInvokedUrlCommand*)command{
+ NSString* sid = [command.arguments objectAtIndex:0];
+ int top = [[command.arguments objectAtIndex:1] intValue];
+ int left = [[command.arguments objectAtIndex:2] intValue];
+ int width = [[command.arguments objectAtIndex:3] intValue];
+ int height = [[command.arguments objectAtIndex:4] intValue];
+
+ [self setPosition: sid top: top left: left width: width height: height];
+}
+- (void)setPosition:(NSString*)sid top:(int)top left:(int)left width:(int)width height:(int)height {
+ int offsetTop = 20;
+ if (statusBarPlugin) {
+ // We set the offsetTop to the top position of the webView because the StatusBarPlugin changes the top position to the proper offset.
+ offsetTop = self.webView.frame.origin.y;
+ } else if ([UIApplication sharedApplication].isStatusBarHidden) {
+ offsetTop = 0;
+ }
+
+ CGRect frame = CGRectMake(left, top + offsetTop, width, height);
+ if ([sid isEqualToString:@"TBPublisher"]) {
+ _publisher.view.frame = frame;
+ } else {
+ OTSubscriber* streamInfo = [subscriberDictionary objectForKey:sid];
+ streamInfo.view.frame = frame;
+ }
+}
#pragma mark Publisher Methods
- (void)publishAudio:(CDVInvokedUrlCommand*)command{
@@ -331,7 +365,7 @@ - (void)subscribe:(CDVInvokedUrlCommand*)command{
// Set depth location of camera view based on CSS z-index.
sub.view.layer.zPosition = zIndex;
- [self.webView.scrollView addSubview:sub.view];
+ [self.webView.superview addSubview:sub.view];
// Return to JS event handler
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
diff --git a/src/js/OT.coffee b/src/js/OT.coffee
index f4ce1b93..7d3935eb 100644
--- a/src/js/OT.coffee
+++ b/src/js/OT.coffee
@@ -59,3 +59,6 @@ window.addEventListener "orientationchange", (->
), 1000
return
), false
+document.addEventListener "ondeviceready", (->
+ Cordova.exec(TBSuccess, TBError, OTPlugin, "hasStatusBarPlugin", [window.hasOwnProperty("StatusBar")] )
+), false
\ No newline at end of file
diff --git a/src/js/OTHelpers.coffee b/src/js/OTHelpers.coffee
index 2e27d3e3..c2876d0b 100644
--- a/src/js/OTHelpers.coffee
+++ b/src/js/OTHelpers.coffee
@@ -7,35 +7,25 @@ streamElements = {} # keep track of DOM elements for each stream
#
# Helper methods
#
-getPosition = (divName) ->
+getPosition = (pubDiv) ->
# Get the position of element
- pubDiv = document.getElementById(divName)
if !pubDiv then return {}
- computedStyle = if window.getComputedStyle then getComputedStyle(pubDiv, null) else {}
- width = pubDiv.offsetWidth
- height = pubDiv.offsetHeight
- curtop = pubDiv.offsetTop
- curleft = pubDiv.offsetLeft
- while(pubDiv = pubDiv.offsetParent)
- curleft += pubDiv.offsetLeft
- curtop += pubDiv.offsetTop
- return {
- top:curtop
- left:curleft
- width:width
- height:height
- }
-
-replaceWithVideoStream = (divName, streamId, properties) ->
+ return pubDiv.getBoundingClientRect()
+
+replaceWithVideoStream = (element, streamId, properties) ->
typeClass = if streamId == PublisherStreamId then PublisherTypeClass else SubscriberTypeClass
- element = document.getElementById(divName)
- element.setAttribute( "class", "OT_root #{typeClass}" )
- element.setAttribute( "data-streamid", streamId )
- element.style.width = properties.width+"px"
- element.style.height = properties.height+"px"
- element.style.overflow = "hidden"
- element.style['background-color'] = "#000000"
- streamElements[ streamId ] = element
+ if (properties.insertMode == "replace")
+ newElement = element
+ else
+ newElement = document.createElement( "div" )
+ newElement.setAttribute( "class", "OT_root #{typeClass}" )
+ newElement.setAttribute( "data-streamid", streamId )
+ newElement.setAttribute( "data-insertMode", properties.insertMode )
+ newElement.style.width = properties.width+"px"
+ newElement.style.height = properties.height+"px"
+ newElement.style.overflow = "hidden"
+ newElement.style['background-color'] = "#000000"
+ streamElements[ streamId ] = newElement
internalDiv = document.createElement( "div" )
internalDiv.setAttribute( "class", VideoContainerClass)
@@ -50,8 +40,15 @@ replaceWithVideoStream = (divName, streamId, properties) ->
# todo: js change styles or append css stylesheets? Concern: users will not be able to change via css
internalDiv.appendChild( videoElement )
- element.appendChild( internalDiv )
- return element
+ newElement.appendChild( internalDiv )
+
+ if (properties.insertMode == "append")
+ element.appendChild(newElement)
+ if (properties.insertMode == "before")
+ element.parentNode.insertBefore(newElement, element)
+ if (properties.insertMode == "after")
+ element.parentNode.insertBefore(newElement, element.nextSibling)
+ return newElement
TBError = (error) ->
console.log("Error: ", error)
@@ -76,8 +73,7 @@ TBUpdateObjects = ()->
console.log("JS: Object updated")
streamId = e.dataset.streamid
console.log("JS sessionId: " + streamId )
- id = e.id
- position = getPosition(id)
+ position = getPosition(e)
Cordova.exec(TBSuccess, TBError, OTPlugin, "updateView", [streamId, position.top, position.left, position.width, position.height, TBGetZIndex(e), ratios.widthRatio, ratios.heightRatio] )
return
TBGenerateDomHelper = ->
@@ -123,3 +119,11 @@ OTReplacePublisher = ()->
pdebug = (msg, data) ->
console.log "JS Lib: #{msg} - ", data
+
+OTOnScrollEvent = (e) ->
+ target = e.target;
+ videos = target.querySelectorAll('[data-streamid]')
+ if(videos)
+ for video in videos
+ position = getPosition(video)
+ Cordova.exec(TBSuccess, TBError, OTPlugin, "updateCamera", [video.getAttribute('data-streamid'), position.top, position.left, position.width, position.height] )
diff --git a/src/js/OTPublisher.coffee b/src/js/OTPublisher.coffee
index 36a028a6..53be23de 100644
--- a/src/js/OTPublisher.coffee
+++ b/src/js/OTPublisher.coffee
@@ -18,12 +18,12 @@ class TBPublisher
constructor: (one, two) ->
@sanitizeInputs(one, two)
pdebug "creating publisher", {}
- position = getPosition(@domId)
+ position = getPosition(@pubElement)
name=""
publishAudio="true"
publishVideo="true"
cameraName = "front"
- zIndex = TBGetZIndex(document.getElementById(@domId))
+ zIndex = TBGetZIndex(@pubElement)
ratios = TBGetScreenRatios()
audioFallbackEnabled = "true"
audioBitrate = 40000
@@ -31,6 +31,7 @@ class TBPublisher
videoSource = "true"
frameRate = 30
resolution = "640X480"
+ insertMode = "replace"
if @properties?
width = @properties.width ? position.width
height = @properties.height ? position.height
@@ -52,12 +53,12 @@ class TBPublisher
audioSource="false"
if(@properties.videoSource? || @properties.videoSource==false)
videoSource="false"
+ insertMode = @properties.insertMode ? insertMode
if (not width?) or width == 0 or (not height?) or height==0
width = DefaultWidth
height = DefaultHeight
- @pubElement = document.getElementById(@domId)
- replaceWithVideoStream(@domId, PublisherStreamId, {width:width, height:height})
- position = getPosition(@domId)
+ replaceWithVideoStream(@pubElement, PublisherStreamId, {width:width, height:height, insertMode:insertMode})
+ position = getPosition(@pubElement)
TBUpdateObjects()
OT.getHelper().eventing(@)
Cordova.exec(TBSuccess, TBError, OTPlugin, "initPublisher", [name, position.top, position.left, width, height, zIndex, publishAudio, publishVideo, cameraName, ratios.widthRatio, ratios.heightRatio, audioFallbackEnabled, audioBitrate, audioSource, videoSource, frameRate, resolution] )
@@ -116,24 +117,38 @@ class TBPublisher
sanitizeInputs: (one, two) ->
if( two? )
# all 2 optional properties present: domId, properties
- @domId = one
+ if one instanceof Element
+ @pubElement = one
+ @domId = @pubElement.id
+ else
+ @domId = one
+ @pubElement = document.getElementById(one)
@properties = two
else if( one? )
# only 1 property is present domId || properties
- if( typeof(one) == "object" )
+ if one instanceof Element
+ @pubElement = one
+ @domId = @pubElement.id
+ else if( typeof(one) == "object" )
@properties = one
else
@domId = one
+ @pubElement = document.getElementById(one)
@properties = if( @properties and typeof( @properties == "object" )) then @properties else {}
+ # if domId does NOT exists and an element is provided, create a unique domId
+ if (!@domId and @pubElement)
+ @domId = "PubSub" + Date.now();
+ @pubElement.setAttribute('id', @domId)
# if domId exists but properties width or height is not specified, set properties
- if( @domId and document.getElementById( @domId ) )
+ if( @domId and @pubElement )
if !@properties.width or !@properties.height
console.log "domId exists but properties width or height is not specified"
- position = getPosition( @domId )
+ position = getPosition( @pubElement )
console.log " width: #{position.width} and height: #{position.height} for domId #{@domId}, and top: #{position.top}, left: #{position.left}"
if position.width > 0 and position.height > 0
@properties.width = position.width
@properties.height = position.height
else
@domId = TBGenerateDomHelper()
+ @pubElement = document.getElementById(@domId)
return @
\ No newline at end of file
diff --git a/src/js/OTSession.coffee b/src/js/OTSession.coffee
index 85007b5a..437bcdb1 100644
--- a/src/js/OTSession.coffee
+++ b/src/js/OTSession.coffee
@@ -36,12 +36,12 @@ class TBSession
return @
getSubscribersForStream: (stream) ->
return @
- publish: (divName, properties) =>
+ publish: (divObject, properties) =>
if( @alreadyPublishing )
pdebug("Session is already publishing", {})
return
@alreadyPublishing = true
- @publisher = new TBPublisher(divName, properties)
+ @publisher = new TBPublisher(divObject, properties)
@publish( @publisher )
publish: () =>
if( @alreadyPublishing )
@@ -72,16 +72,16 @@ class TBSession
return subscriber
if( three? )
# stream, domId, properties || stream, domId, completionHandler || stream, properties, completionHandler
- if( (typeof(two) == "string" || two.nodeType == 1) && typeof(three) == "object" )
+ if( (typeof(two) == "string" || two.nodeType == 1 || two instanceof Element) && typeof(three) == "object" )
console.log("stream, domId, props")
subscriber = new TBSubscriber(one, two, three)
return subscriber
- if( (typeof(two) == "string" || two.nodeType == 1) && typeof(three) == "function" )
+ if( (typeof(two) == "string" || two.nodeType == 1 || two instanceof Element) && typeof(three) == "function" )
console.log("stream, domId, completionHandler")
@subscriberCallbacks[one.streamId]=three
- subscriber = new TBSubscriber(one, domId, {})
+ subscriber = new TBSubscriber(one, two, {})
return subscriber
- if( typeof(two) == "object" && typeof(three) == "function" )
+ if(typeof(two) == "object" && typeof(three) == "function" )
console.log("stream, props, completionHandler")
@subscriberCallbacks[one.streamId] = three
domId = TBGenerateDomHelper()
@@ -89,7 +89,7 @@ class TBSession
return subscriber
if( two? )
# stream, domId || stream, properties || stream,completionHandler
- if( (typeof(two) == "string" || two.nodeType == 1) )
+ if( (typeof(two) == "string" || two.nodeType == 1 || two instanceof Element) )
subscriber = new TBSubscriber(one, two, {})
return subscriber
if( typeof(two) == "object" )
@@ -108,7 +108,7 @@ class TBSession
unpublish:() ->
@alreadyPublishing = false
console.log("JS: Unpublish")
- element = document.getElementById( @publisher.domId )
+ element = @publisher.pubElement
if(element)
@resetElement(element)
TBUpdateObjects()
@@ -140,14 +140,18 @@ class TBSession
@resetElement(e)
objects = document.getElementsByClassName('OT_root')
resetElement: (element) =>
- attributes = ['style', 'data-streamid', 'class']
- elementChildren = element.childNodes
- element.removeAttribute attribute for attribute in attributes
- for childElement in elementChildren
- childClass = childElement.getAttribute 'class'
- if childClass == 'OT_video-container'
- element.removeChild childElement
- break
+ insertMode = element.getAttribute('data-insertMode')
+ if (insertMode == "replace")
+ attributes = ['style', 'data-streamid', 'class', 'data-insertMode']
+ elementChildren = element.childNodes
+ element.removeAttribute attribute for attribute in attributes
+ for childElement in elementChildren
+ childClass = childElement.getAttribute 'class'
+ if childClass == 'OT_video-container'
+ element.removeChild childElement
+ break
+ else
+ element.parentNode.removeChild(element)
return
# event listeners
@@ -169,6 +173,7 @@ class TBSession
delete( @connections[ connection.connectionId] )
return @
sessionConnected: (event) =>
+ document.addEventListener('scroll', OTOnScrollEvent, true);
pdebug "sessionConnectedHandler", event
@trigger("sessionConnected")
@connection = new TBConnection( event.connection )
@@ -176,6 +181,7 @@ class TBSession
event = null
return @
sessionDisconnected: (event) =>
+ document.removeEventListener('scroll', OTOnScrollEvent);
pdebug "sessionDisconnected event", event
@alreadyPublishing = false
sessionDisconnectedEvent = new TBEvent( { reason: event.reason } )
diff --git a/src/js/OTSubscriber.coffee b/src/js/OTSubscriber.coffee
index c774db08..98449b59 100644
--- a/src/js/OTSubscriber.coffee
+++ b/src/js/OTSubscriber.coffee
@@ -33,20 +33,25 @@ class TBSubscriber
subscribeToVideo: (value) ->
return @
- constructor: (stream, divName, properties) ->
- element = document.getElementById(divName)
- @id = divName
- @element = element
+ constructor: (stream, divObject, properties) ->
+ if divObject instanceof Element
+ @element = divObject
+ @id = @element.id
+ else
+ @id = divObject
+ @element = document.getElementById(divObject)
+
pdebug "creating subscriber", properties
@streamId = stream.streamId
if(properties? && properties.width=="100%" && properties.height == "100%")
- element.style.width="100%"
- element.style.height="100%"
+ @element.style.width="100%"
+ @element.style.height="100%"
properties.width = ""
properties.height = ""
- divPosition = getPosition( divName )
+ divPosition = getPosition(@element)
subscribeToVideo="true"
- zIndex = TBGetZIndex(element)
+ zIndex = TBGetZIndex(@element)
+ insertMode = "replace"
if(properties?)
width = properties.width || divPosition.width
height = properties.height || divPosition.height
@@ -57,11 +62,12 @@ class TBSubscriber
subscribeToVideo="false"
if(properties.subscribeToAudio? and properties.subscribeToAudio == false)
subscribeToAudio="false"
+ insertMode = properties.insertMode ? insertMode
if (not width?) or width == 0 or (not height?) or height==0
width = DefaultWidth
height = DefaultHeight
- obj = replaceWithVideoStream(divName, stream.streamId, {width:width, height:height})
- position = getPosition(obj.id)
+ obj = replaceWithVideoStream(@element, stream.streamId, {width:width, height:height, insertMode:insertMode})
+ position = getPosition(@element)
ratios = TBGetScreenRatios()
pdebug "final subscriber position", position
Cordova.exec(TBSuccess, TBError, OTPlugin, "subscribe", [stream.streamId, position.top, position.left, width, height, zIndex, subscribeToAudio, subscribeToVideo, ratios.widthRatio, ratios.heightRatio] )
diff --git a/www/opentok.js b/www/opentok.js
index 1a8d948d..50c61214 100644
--- a/www/opentok.js
+++ b/www/opentok.js
@@ -58,6 +58,10 @@ window.addEventListener("orientationchange", (function() {
}), 1000);
}), false);
+document.addEventListener("ondeviceready", (function() {
+ return Cordova.exec(TBSuccess, TBError, OTPlugin, "hasStatusBarPlugin", [window.hasOwnProperty("StatusBar")]);
+}), false);
+
var TBConnection;
TBConnection = (function() {
@@ -158,44 +162,33 @@ TBEvent = (function() {
})();
-var OTPublisherError, OTReplacePublisher, TBError, TBGenerateDomHelper, TBGetScreenRatios, TBGetZIndex, TBSuccess, TBUpdateObjects, getPosition, pdebug, replaceWithVideoStream, streamElements;
+var OTOnScrollEvent, OTPublisherError, OTReplacePublisher, TBError, TBGenerateDomHelper, TBGetScreenRatios, TBGetZIndex, TBSuccess, TBUpdateObjects, getPosition, pdebug, replaceWithVideoStream, streamElements;
streamElements = {};
-getPosition = function(divName) {
- var computedStyle, curleft, curtop, height, pubDiv, width;
- pubDiv = document.getElementById(divName);
+getPosition = function(pubDiv) {
if (!pubDiv) {
return {};
}
- computedStyle = window.getComputedStyle ? getComputedStyle(pubDiv, null) : {};
- width = pubDiv.offsetWidth;
- height = pubDiv.offsetHeight;
- curtop = pubDiv.offsetTop;
- curleft = pubDiv.offsetLeft;
- while ((pubDiv = pubDiv.offsetParent)) {
- curleft += pubDiv.offsetLeft;
- curtop += pubDiv.offsetTop;
- }
- return {
- top: curtop,
- left: curleft,
- width: width,
- height: height
- };
+ return pubDiv.getBoundingClientRect();
};
-replaceWithVideoStream = function(divName, streamId, properties) {
- var element, internalDiv, typeClass, videoElement;
+replaceWithVideoStream = function(element, streamId, properties) {
+ var internalDiv, newElement, typeClass, videoElement;
typeClass = streamId === PublisherStreamId ? PublisherTypeClass : SubscriberTypeClass;
- element = document.getElementById(divName);
- element.setAttribute("class", "OT_root " + typeClass);
- element.setAttribute("data-streamid", streamId);
- element.style.width = properties.width + "px";
- element.style.height = properties.height + "px";
- element.style.overflow = "hidden";
- element.style['background-color'] = "#000000";
- streamElements[streamId] = element;
+ if (properties.insertMode === "replace") {
+ newElement = element;
+ } else {
+ newElement = document.createElement("div");
+ }
+ newElement.setAttribute("class", "OT_root " + typeClass);
+ newElement.setAttribute("data-streamid", streamId);
+ newElement.setAttribute("data-insertMode", properties.insertMode);
+ newElement.style.width = properties.width + "px";
+ newElement.style.height = properties.height + "px";
+ newElement.style.overflow = "hidden";
+ newElement.style['background-color'] = "#000000";
+ streamElements[streamId] = newElement;
internalDiv = document.createElement("div");
internalDiv.setAttribute("class", VideoContainerClass);
internalDiv.style.width = "100%";
@@ -206,8 +199,17 @@ replaceWithVideoStream = function(divName, streamId, properties) {
videoElement.style.width = "100%";
videoElement.style.height = "100%";
internalDiv.appendChild(videoElement);
- element.appendChild(internalDiv);
- return element;
+ newElement.appendChild(internalDiv);
+ if (properties.insertMode === "append") {
+ element.appendChild(newElement);
+ }
+ if (properties.insertMode === "before") {
+ element.parentNode.insertBefore(newElement, element);
+ }
+ if (properties.insertMode === "after") {
+ element.parentNode.insertBefore(newElement, element.nextSibling);
+ }
+ return newElement;
};
TBError = function(error) {
@@ -228,7 +230,7 @@ OTPublisherError = function(error) {
};
TBUpdateObjects = function() {
- var e, id, objects, position, ratios, streamId, _i, _len;
+ var e, objects, position, ratios, streamId, _i, _len;
console.log("JS: Objects being updated in TBUpdateObjects");
objects = document.getElementsByClassName('OT_root');
ratios = TBGetScreenRatios();
@@ -237,8 +239,7 @@ TBUpdateObjects = function() {
console.log("JS: Object updated");
streamId = e.dataset.streamid;
console.log("JS sessionId: " + streamId);
- id = e.id;
- position = getPosition(id);
+ position = getPosition(e);
Cordova.exec(TBSuccess, TBError, OTPlugin, "updateView", [streamId, position.top, position.left, position.width, position.height, TBGetZIndex(e), ratios.widthRatio, ratios.heightRatio]);
}
};
@@ -303,6 +304,21 @@ pdebug = function(msg, data) {
return console.log("JS Lib: " + msg + " - ", data);
};
+OTOnScrollEvent = function(e) {
+ var position, target, video, videos, _i, _len, _results;
+ target = e.target;
+ videos = target.querySelectorAll('[data-streamid]');
+ if (videos) {
+ _results = [];
+ for (_i = 0, _len = videos.length; _i < _len; _i++) {
+ video = videos[_i];
+ position = getPosition(video);
+ _results.push(Cordova.exec(TBSuccess, TBError, OTPlugin, "updateCamera", [video.getAttribute('data-streamid'), position.top, position.left, position.width, position.height]));
+ }
+ return _results;
+ }
+};
+
var TBPublisher,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
@@ -313,15 +329,15 @@ TBPublisher = (function() {
this.streamCreated = __bind(this.streamCreated, this);
this.eventReceived = __bind(this.eventReceived, this);
this.setSession = __bind(this.setSession, this);
- var audioBitrate, audioFallbackEnabled, audioSource, cameraName, frameRate, height, name, position, publishAudio, publishVideo, ratios, resolution, videoSource, width, zIndex, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9;
+ var audioBitrate, audioFallbackEnabled, audioSource, cameraName, frameRate, height, insertMode, name, position, publishAudio, publishVideo, ratios, resolution, videoSource, width, zIndex, _ref, _ref1, _ref10, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9;
this.sanitizeInputs(one, two);
pdebug("creating publisher", {});
- position = getPosition(this.domId);
+ position = getPosition(this.pubElement);
name = "";
publishAudio = "true";
publishVideo = "true";
cameraName = "front";
- zIndex = TBGetZIndex(document.getElementById(this.domId));
+ zIndex = TBGetZIndex(this.pubElement);
ratios = TBGetScreenRatios();
audioFallbackEnabled = "true";
audioBitrate = 40000;
@@ -329,6 +345,7 @@ TBPublisher = (function() {
videoSource = "true";
frameRate = 30;
resolution = "640X480";
+ insertMode = "replace";
if (this.properties != null) {
width = (_ref = this.properties.width) != null ? _ref : position.width;
height = (_ref1 = this.properties.height) != null ? _ref1 : position.height;
@@ -355,17 +372,18 @@ TBPublisher = (function() {
if ((this.properties.videoSource != null) || this.properties.videoSource === false) {
videoSource = "false";
}
+ insertMode = (_ref10 = this.properties.insertMode) != null ? _ref10 : insertMode;
}
if ((width == null) || width === 0 || (height == null) || height === 0) {
width = DefaultWidth;
height = DefaultHeight;
}
- this.pubElement = document.getElementById(this.domId);
- replaceWithVideoStream(this.domId, PublisherStreamId, {
+ replaceWithVideoStream(this.pubElement, PublisherStreamId, {
width: width,
- height: height
+ height: height,
+ insertMode: insertMode
});
- position = getPosition(this.domId);
+ position = getPosition(this.pubElement);
TBUpdateObjects();
OT.getHelper().eventing(this);
Cordova.exec(TBSuccess, TBError, OTPlugin, "initPublisher", [name, position.top, position.left, width, height, zIndex, publishAudio, publishVideo, cameraName, ratios.widthRatio, ratios.heightRatio, audioFallbackEnabled, audioBitrate, audioSource, videoSource, frameRate, resolution]);
@@ -465,20 +483,34 @@ TBPublisher = (function() {
TBPublisher.prototype.sanitizeInputs = function(one, two) {
var position;
if ((two != null)) {
- this.domId = one;
+ if (one instanceof Element) {
+ this.pubElement = one;
+ this.domId = this.pubElement.id;
+ } else {
+ this.domId = one;
+ this.pubElement = document.getElementById(one);
+ }
this.properties = two;
} else if ((one != null)) {
- if (typeof one === "object") {
+ if (one instanceof Element) {
+ this.pubElement = one;
+ this.domId = this.pubElement.id;
+ } else if (typeof one === "object") {
this.properties = one;
} else {
this.domId = one;
+ this.pubElement = document.getElementById(one);
}
}
this.properties = this.properties && typeof (this.properties === "object") ? this.properties : {};
- if (this.domId && document.getElementById(this.domId)) {
+ if (!this.domId && this.pubElement) {
+ this.domId = "PubSub" + Date.now();
+ this.pubElement.setAttribute('id', this.domId);
+ }
+ if (this.domId && this.pubElement) {
if (!this.properties.width || !this.properties.height) {
console.log("domId exists but properties width or height is not specified");
- position = getPosition(this.domId);
+ position = getPosition(this.pubElement);
console.log(" width: " + position.width + " and height: " + position.height + " for domId " + this.domId + ", and top: " + position.top + ", left: " + position.left);
if (position.width > 0 && position.height > 0) {
this.properties.width = position.width;
@@ -487,6 +519,7 @@ TBPublisher = (function() {
}
} else {
this.domId = TBGenerateDomHelper();
+ this.pubElement = document.getElementById(this.domId);
}
return this;
};
@@ -532,13 +565,13 @@ TBSession = (function() {
return this;
};
- TBSession.prototype.publish = function(divName, properties) {
+ TBSession.prototype.publish = function(divObject, properties) {
if (this.alreadyPublishing) {
pdebug("Session is already publishing", {});
return;
}
this.alreadyPublishing = true;
- this.publisher = new TBPublisher(divName, properties);
+ this.publisher = new TBPublisher(divObject, properties);
return this.publish(this.publisher);
};
@@ -577,15 +610,15 @@ TBSession = (function() {
return subscriber;
}
if ((three != null)) {
- if ((typeof two === "string" || two.nodeType === 1) && typeof three === "object") {
+ if ((typeof two === "string" || two.nodeType === 1 || two instanceof Element) && typeof three === "object") {
console.log("stream, domId, props");
subscriber = new TBSubscriber(one, two, three);
return subscriber;
}
- if ((typeof two === "string" || two.nodeType === 1) && typeof three === "function") {
+ if ((typeof two === "string" || two.nodeType === 1 || two instanceof Element) && typeof three === "function") {
console.log("stream, domId, completionHandler");
this.subscriberCallbacks[one.streamId] = three;
- subscriber = new TBSubscriber(one, domId, {});
+ subscriber = new TBSubscriber(one, two, {});
return subscriber;
}
if (typeof two === "object" && typeof three === "function") {
@@ -597,7 +630,7 @@ TBSession = (function() {
}
}
if ((two != null)) {
- if (typeof two === "string" || two.nodeType === 1) {
+ if (typeof two === "string" || two.nodeType === 1 || two instanceof Element) {
subscriber = new TBSubscriber(one, two, {});
return subscriber;
}
@@ -622,7 +655,7 @@ TBSession = (function() {
var element;
this.alreadyPublishing = false;
console.log("JS: Unpublish");
- element = document.getElementById(this.publisher.domId);
+ element = this.publisher.pubElement;
if (element) {
this.resetElement(element);
TBUpdateObjects();
@@ -683,20 +716,25 @@ TBSession = (function() {
};
TBSession.prototype.resetElement = function(element) {
- var attribute, attributes, childClass, childElement, elementChildren, _i, _j, _len, _len1;
- attributes = ['style', 'data-streamid', 'class'];
- elementChildren = element.childNodes;
- for (_i = 0, _len = attributes.length; _i < _len; _i++) {
- attribute = attributes[_i];
- element.removeAttribute(attribute);
- }
- for (_j = 0, _len1 = elementChildren.length; _j < _len1; _j++) {
- childElement = elementChildren[_j];
- childClass = childElement.getAttribute('class');
- if (childClass === 'OT_video-container') {
- element.removeChild(childElement);
- break;
+ var attribute, attributes, childClass, childElement, elementChildren, insertMode, _i, _j, _len, _len1;
+ insertMode = element.getAttribute('data-insertMode');
+ if (insertMode === "replace") {
+ attributes = ['style', 'data-streamid', 'class', 'data-insertMode'];
+ elementChildren = element.childNodes;
+ for (_i = 0, _len = attributes.length; _i < _len; _i++) {
+ attribute = attributes[_i];
+ element.removeAttribute(attribute);
+ }
+ for (_j = 0, _len1 = elementChildren.length; _j < _len1; _j++) {
+ childElement = elementChildren[_j];
+ childClass = childElement.getAttribute('class');
+ if (childClass === 'OT_video-container') {
+ element.removeChild(childElement);
+ break;
+ }
}
+ } else {
+ element.parentNode.removeChild(element);
}
};
@@ -730,6 +768,7 @@ TBSession = (function() {
};
TBSession.prototype.sessionConnected = function(event) {
+ document.addEventListener('scroll', OTOnScrollEvent, true);
pdebug("sessionConnectedHandler", event);
this.trigger("sessionConnected");
this.connection = new TBConnection(event.connection);
@@ -740,6 +779,7 @@ TBSession = (function() {
TBSession.prototype.sessionDisconnected = function(event) {
var sessionDisconnectedEvent;
+ document.removeEventListener('scroll', OTOnScrollEvent);
pdebug("sessionDisconnected event", event);
this.alreadyPublishing = false;
sessionDisconnectedEvent = new TBEvent({
@@ -883,22 +923,27 @@ TBSubscriber = (function() {
return this;
};
- function TBSubscriber(stream, divName, properties) {
- var divPosition, element, height, name, obj, position, ratios, subscribeToAudio, subscribeToVideo, width, zIndex, _ref;
- element = document.getElementById(divName);
- this.id = divName;
- this.element = element;
+ function TBSubscriber(stream, divObject, properties) {
+ var divPosition, height, insertMode, name, obj, position, ratios, subscribeToAudio, subscribeToVideo, width, zIndex, _ref, _ref1;
+ if (divObject instanceof Element) {
+ this.element = divObject;
+ this.id = this.element.id;
+ } else {
+ this.id = divObject;
+ this.element = document.getElementById(divObject);
+ }
pdebug("creating subscriber", properties);
this.streamId = stream.streamId;
if ((properties != null) && properties.width === "100%" && properties.height === "100%") {
- element.style.width = "100%";
- element.style.height = "100%";
+ this.element.style.width = "100%";
+ this.element.style.height = "100%";
properties.width = "";
properties.height = "";
}
- divPosition = getPosition(divName);
+ divPosition = getPosition(this.element);
subscribeToVideo = "true";
- zIndex = TBGetZIndex(element);
+ zIndex = TBGetZIndex(this.element);
+ insertMode = "replace";
if ((properties != null)) {
width = properties.width || divPosition.width;
height = properties.height || divPosition.height;
@@ -911,16 +956,18 @@ TBSubscriber = (function() {
if ((properties.subscribeToAudio != null) && properties.subscribeToAudio === false) {
subscribeToAudio = "false";
}
+ insertMode = (_ref1 = properties.insertMode) != null ? _ref1 : insertMode;
}
if ((width == null) || width === 0 || (height == null) || height === 0) {
width = DefaultWidth;
height = DefaultHeight;
}
- obj = replaceWithVideoStream(divName, stream.streamId, {
+ obj = replaceWithVideoStream(this.element, stream.streamId, {
width: width,
- height: height
+ height: height,
+ insertMode: insertMode
});
- position = getPosition(obj.id);
+ position = getPosition(this.element);
ratios = TBGetScreenRatios();
pdebug("final subscriber position", position);
Cordova.exec(TBSuccess, TBError, OTPlugin, "subscribe", [stream.streamId, position.top, position.left, width, height, zIndex, subscribeToAudio, subscribeToVideo, ratios.widthRatio, ratios.heightRatio]);