Merge branch 'merge-webrtc-screenshare-2' of https://github.com/perroned/bigbluebutton into perroned-merge-webrtc-screenshare-2
This commit is contained in:
commit
dcd226dc9f
@ -114,7 +114,7 @@ public interface IBigBlueButtonInGW {
|
|||||||
void editCaptionHistory(String meetingID, String userID, Integer startIndex, Integer endIndex, String locale, String text);
|
void editCaptionHistory(String meetingID, String userID, Integer startIndex, Integer endIndex, String locale, String text);
|
||||||
|
|
||||||
// DeskShare
|
// DeskShare
|
||||||
void deskShareStarted(String conferenceName, String callerId, String callerIdName);
|
void deskShareStarted(String confId, String callerId, String callerIdName);
|
||||||
void deskShareStopped(String conferenceName, String callerId, String callerIdName);
|
void deskShareStopped(String conferenceName, String callerId, String callerIdName);
|
||||||
void deskShareRTMPBroadcastStarted(String conferenceName, String streamname, int videoWidth, int videoHeight, String timestamp);
|
void deskShareRTMPBroadcastStarted(String conferenceName, String streamname, int videoWidth, int videoHeight, String timestamp);
|
||||||
void deskShareRTMPBroadcastStopped(String conferenceName, String streamname, int videoWidth, int videoHeight, String timestamp);
|
void deskShareRTMPBroadcastStopped(String conferenceName, String streamname, int videoWidth, int videoHeight, String timestamp);
|
||||||
|
@ -37,11 +37,6 @@ class BigBlueButtonActor(val system: ActorSystem,
|
|||||||
case msg: UserMutedInVoiceConfMessage => handleUserMutedInVoiceConfMessage(msg)
|
case msg: UserMutedInVoiceConfMessage => handleUserMutedInVoiceConfMessage(msg)
|
||||||
case msg: UserTalkingInVoiceConfMessage => handleUserTalkingInVoiceConfMessage(msg)
|
case msg: UserTalkingInVoiceConfMessage => handleUserTalkingInVoiceConfMessage(msg)
|
||||||
case msg: VoiceConfRecordingStartedMessage => handleVoiceConfRecordingStartedMessage(msg)
|
case msg: VoiceConfRecordingStartedMessage => handleVoiceConfRecordingStartedMessage(msg)
|
||||||
case msg: DeskShareStartedRequest => handleDeskShareStartedRequest(msg)
|
|
||||||
case msg: DeskShareStoppedRequest => handleDeskShareStoppedRequest(msg)
|
|
||||||
case msg: DeskShareRTMPBroadcastStartedRequest => handleDeskShareRTMPBroadcastStartedRequest(msg)
|
|
||||||
case msg: DeskShareRTMPBroadcastStoppedRequest => handleDeskShareRTMPBroadcastStoppedRequest(msg)
|
|
||||||
case msg: DeskShareGetDeskShareInfoRequest => handleDeskShareGetDeskShareInfoRequest(msg)
|
|
||||||
case _ => // do nothing
|
case _ => // do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +146,7 @@ class BigBlueButtonActor(val system: ActorSystem,
|
|||||||
/** Subscribe to meeting and voice events. **/
|
/** Subscribe to meeting and voice events. **/
|
||||||
eventBus.subscribe(m.actorRef, m.mProps.meetingID)
|
eventBus.subscribe(m.actorRef, m.mProps.meetingID)
|
||||||
eventBus.subscribe(m.actorRef, m.mProps.voiceBridge)
|
eventBus.subscribe(m.actorRef, m.mProps.voiceBridge)
|
||||||
|
eventBus.subscribe(m.actorRef, m.mProps.deskshareBridge)
|
||||||
|
|
||||||
meetings += m.mProps.meetingID -> m
|
meetings += m.mProps.meetingID -> m
|
||||||
outGW.send(new MeetingCreated(m.mProps.meetingID, m.mProps.externalMeetingID, m.mProps.recorded, m.mProps.meetingName,
|
outGW.send(new MeetingCreated(m.mProps.meetingID, m.mProps.externalMeetingID, m.mProps.recorded, m.mProps.meetingName,
|
||||||
@ -206,52 +202,5 @@ class BigBlueButtonActor(val system: ActorSystem,
|
|||||||
outGW.send(new GetAllMeetingsReply(resultArray))
|
outGW.send(new GetAllMeetingsReply(resultArray))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def handleDeskShareStartedRequest(msg: DeskShareStartedRequest) {
|
|
||||||
log.info("handleDeskShareStartedRequest: msg.conferenceName=" + msg.conferenceName)
|
|
||||||
findMeetingWithVoiceConfId(msg.conferenceName) foreach { m =>
|
|
||||||
{
|
|
||||||
// println(msg.conferenceName + " (in for each) handleDeskShareStartedRequest BBBActor ")
|
|
||||||
m.actorRef ! msg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def handleDeskShareStoppedRequest(msg: DeskShareStoppedRequest) {
|
|
||||||
log.info("handleDeskShareStoppedRequest msg.conferenceName=" + msg.conferenceName)
|
|
||||||
findMeetingWithVoiceConfId(msg.conferenceName) foreach { m =>
|
|
||||||
{
|
|
||||||
// println(msg.conferenceName + " (in for each) handleDeskShareStoppedRequest BBBActor ")
|
|
||||||
m.actorRef ! msg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def handleDeskShareRTMPBroadcastStartedRequest(msg: DeskShareRTMPBroadcastStartedRequest) {
|
|
||||||
log.info("handleDeskShareRTMPBroadcastStartedRequest msg.conferenceName=" + msg.conferenceName)
|
|
||||||
findMeetingWithVoiceConfId(msg.conferenceName) foreach { m =>
|
|
||||||
{
|
|
||||||
// println(msg.conferenceName + " (in for each) handleDeskShareRTMPBroadcastStartedRequest BBBActor ")
|
|
||||||
m.actorRef ! msg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def handleDeskShareRTMPBroadcastStoppedRequest(msg: DeskShareRTMPBroadcastStoppedRequest) {
|
|
||||||
log.info("handleDeskShareRTMPBroadcastStoppedRequest msg.conferenceName=" + msg.conferenceName)
|
|
||||||
findMeetingWithVoiceConfId(msg.conferenceName) foreach { m =>
|
|
||||||
{
|
|
||||||
// println(msg.conferenceName + " (in for each) handleDeskShareRTMPBroadcastStoppedRequest BBBActor ")
|
|
||||||
m.actorRef ! msg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def handleDeskShareGetDeskShareInfoRequest(msg: DeskShareGetDeskShareInfoRequest): Unit = {
|
|
||||||
val m = meetings.values.find(m => {
|
|
||||||
m.mProps.meetingID == msg.conferenceName
|
|
||||||
})
|
|
||||||
m foreach { mActor => mActor.actorRef ! msg }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ class BigBlueButtonInGW(
|
|||||||
msg.payload.name,
|
msg.payload.name,
|
||||||
msg.payload.record,
|
msg.payload.record,
|
||||||
msg.payload.voiceConfId,
|
msg.payload.voiceConfId,
|
||||||
|
msg.payload.voiceConfId + "-DESKSHARE", // WebRTC Desktop conference id
|
||||||
msg.payload.durationInMinutes,
|
msg.payload.durationInMinutes,
|
||||||
msg.payload.autoStartRecording,
|
msg.payload.autoStartRecording,
|
||||||
msg.payload.allowStartStopRecording,
|
msg.payload.allowStartStopRecording,
|
||||||
@ -498,8 +499,11 @@ class BigBlueButtonInGW(
|
|||||||
* Message Interface for DeskShare
|
* Message Interface for DeskShare
|
||||||
* *****************************************************************
|
* *****************************************************************
|
||||||
*/
|
*/
|
||||||
def deskShareStarted(meetingId: String, callerId: String, callerIdName: String) {
|
def deskShareStarted(confId: String, callerId: String, callerIdName: String) {
|
||||||
eventBus.publish(BigBlueButtonEvent(meetingId, new DeskShareStartedRequest(meetingId, callerId, callerIdName)))
|
println("____BigBlueButtonInGW::deskShareStarted " + confId + callerId + " " +
|
||||||
|
callerIdName)
|
||||||
|
eventBus.publish(BigBlueButtonEvent(confId, new DeskShareStartedRequest(confId, callerId,
|
||||||
|
callerIdName)))
|
||||||
}
|
}
|
||||||
|
|
||||||
def deskShareStopped(meetingId: String, callerId: String, callerIdName: String) {
|
def deskShareStopped(meetingId: String, callerId: String, callerIdName: String) {
|
||||||
|
@ -163,4 +163,80 @@ class LiveMeeting(val mProps: MeetingProperties,
|
|||||||
def permissionsEqual(other: Permissions): Boolean = {
|
def permissionsEqual(other: Permissions): Boolean = {
|
||||||
meetingModel.permissionsEqual(other)
|
meetingModel.permissionsEqual(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WebRTC Desktop Sharing
|
||||||
|
|
||||||
|
def handleDeskShareStartedRequest(msg: DeskShareStartedRequest): Unit = {
|
||||||
|
log.info("handleDeskShareStartedRequest: dsStarted=" + meetingModel.getDeskShareStarted())
|
||||||
|
|
||||||
|
if (!meetingModel.getDeskShareStarted()) {
|
||||||
|
val timestamp = System.currentTimeMillis().toString
|
||||||
|
val streamPath = "rtmp://" + mProps.red5DeskShareIP + "/" + mProps.red5DeskShareApp +
|
||||||
|
"/" + mProps.meetingID + "/" + mProps.meetingID + "-" + timestamp
|
||||||
|
log.info("handleDeskShareStartedRequest: streamPath=" + streamPath)
|
||||||
|
|
||||||
|
// Tell FreeSwitch to broadcast to RTMP
|
||||||
|
outGW.send(new DeskShareStartRTMPBroadcast(msg.conferenceName, streamPath))
|
||||||
|
|
||||||
|
meetingModel.setDeskShareStarted(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def handleDeskShareStoppedRequest(msg: DeskShareStoppedRequest): Unit = {
|
||||||
|
log.info("handleDeskShareStoppedRequest: dsStarted=" + meetingModel.getDeskShareStarted() +
|
||||||
|
" URL:" + meetingModel.getRTMPBroadcastingUrl())
|
||||||
|
|
||||||
|
// Tell FreeSwitch to stop broadcasting to RTMP
|
||||||
|
outGW.send(new DeskShareStopRTMPBroadcast(msg.conferenceName, meetingModel.getRTMPBroadcastingUrl()))
|
||||||
|
|
||||||
|
meetingModel.setDeskShareStarted(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
def handleDeskShareRTMPBroadcastStartedRequest(msg: DeskShareRTMPBroadcastStartedRequest): Unit = {
|
||||||
|
log.info("handleDeskShareRTMPBroadcastStartedRequest: isBroadcastingRTMP=" + meetingModel.isBroadcastingRTMP() +
|
||||||
|
" URL:" + meetingModel.getRTMPBroadcastingUrl())
|
||||||
|
|
||||||
|
// only valid if not broadcasting yet
|
||||||
|
if (!meetingModel.isBroadcastingRTMP()) {
|
||||||
|
meetingModel.setRTMPBroadcastingUrl(msg.streamname)
|
||||||
|
meetingModel.broadcastingRTMPStarted()
|
||||||
|
meetingModel.setDesktopShareVideoWidth(msg.videoWidth)
|
||||||
|
meetingModel.setDesktopShareVideoHeight(msg.videoHeight)
|
||||||
|
log.info("START broadcast ALLOWED when isBroadcastingRTMP=false")
|
||||||
|
|
||||||
|
// Notify viewers in the meeting that there's an rtmp stream to view
|
||||||
|
outGW.send(new DeskShareNotifyViewersRTMP(mProps.meetingID, msg.streamname, msg.videoWidth, msg.videoHeight, true))
|
||||||
|
} else {
|
||||||
|
log.info("START broadcast NOT ALLOWED when isBroadcastingRTMP=true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def handleDeskShareRTMPBroadcastStoppedRequest(msg: DeskShareRTMPBroadcastStoppedRequest): Unit = {
|
||||||
|
log.info("handleDeskShareRTMPBroadcastStoppedRequest: isBroadcastingRTMP=" + meetingModel
|
||||||
|
.isBroadcastingRTMP() + " URL:" + meetingModel.getRTMPBroadcastingUrl())
|
||||||
|
|
||||||
|
// only valid if currently broadcasting
|
||||||
|
if (meetingModel.isBroadcastingRTMP()) {
|
||||||
|
log.info("STOP broadcast ALLOWED when isBroadcastingRTMP=true")
|
||||||
|
meetingModel.broadcastingRTMPStopped()
|
||||||
|
|
||||||
|
// notify viewers that RTMP broadcast stopped
|
||||||
|
outGW.send(new DeskShareNotifyViewersRTMP(mProps.meetingID, meetingModel.getRTMPBroadcastingUrl(),
|
||||||
|
msg.videoWidth, msg.videoHeight, false))
|
||||||
|
} else {
|
||||||
|
log.info("STOP broadcast NOT ALLOWED when isBroadcastingRTMP=false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def handleDeskShareGetDeskShareInfoRequest(msg: DeskShareGetDeskShareInfoRequest): Unit = {
|
||||||
|
|
||||||
|
log.info("handleDeskShareGetDeskShareInfoRequest: " + msg.conferenceName + "isBroadcasting="
|
||||||
|
+ meetingModel.isBroadcastingRTMP() + " URL:" + meetingModel.getRTMPBroadcastingUrl())
|
||||||
|
if (meetingModel.isBroadcastingRTMP()) {
|
||||||
|
// if the meeting has an ongoing WebRTC Deskshare session, send a notification
|
||||||
|
outGW.send(new DeskShareNotifyASingleViewer(mProps.meetingID, msg.requesterID, meetingModel.getRTMPBroadcastingUrl(),
|
||||||
|
meetingModel.getDesktopShareVideoWidth(), meetingModel.getDesktopShareVideoHeight(), true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -178,77 +178,13 @@ class MeetingActor(val mProps: MeetingProperties,
|
|||||||
case msg: UpdateCaptionOwnerRequest => liveMeeting.handleUpdateCaptionOwnerRequest(msg)
|
case msg: UpdateCaptionOwnerRequest => liveMeeting.handleUpdateCaptionOwnerRequest(msg)
|
||||||
case msg: EditCaptionHistoryRequest => liveMeeting.handleEditCaptionHistoryRequest(msg)
|
case msg: EditCaptionHistoryRequest => liveMeeting.handleEditCaptionHistoryRequest(msg)
|
||||||
|
|
||||||
|
case msg: DeskShareStartedRequest => liveMeeting.handleDeskShareStartedRequest(msg)
|
||||||
|
case msg: DeskShareStoppedRequest => liveMeeting.handleDeskShareStoppedRequest(msg)
|
||||||
|
case msg: DeskShareRTMPBroadcastStartedRequest => liveMeeting.handleDeskShareRTMPBroadcastStartedRequest(msg)
|
||||||
|
case msg: DeskShareRTMPBroadcastStoppedRequest => liveMeeting.handleDeskShareRTMPBroadcastStoppedRequest(msg)
|
||||||
|
case msg: DeskShareGetDeskShareInfoRequest => liveMeeting.handleDeskShareGetDeskShareInfoRequest(msg)
|
||||||
|
|
||||||
case _ => // do nothing
|
case _ => // do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast video stream,
|
|
||||||
private def handleDeskShareStartedRequest(msg: DeskShareStartedRequest) {
|
|
||||||
log.info("handleDeskShareStartedRequest: dsStarted=" + meetingModel.getDeskShareStarted())
|
|
||||||
|
|
||||||
if (!meetingModel.getDeskShareStarted()) {
|
|
||||||
val timestamp = System.currentTimeMillis().toString()
|
|
||||||
val streamPath = "rtmp://" + mProps.red5DeskShareIP + "/" + mProps.red5DeskShareApp +
|
|
||||||
"/" + mProps.meetingID + "/" + mProps.meetingID + "-" + timestamp
|
|
||||||
log.info("handleDeskShareStartedRequest: streamPath=" + streamPath)
|
|
||||||
|
|
||||||
// Tell FreeSwitch to broadcast to RTMP
|
|
||||||
outGW.send(new DeskShareStartRTMPBroadcast(msg.conferenceName, streamPath))
|
|
||||||
|
|
||||||
meetingModel.setDeskShareStarted(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def handleDeskShareStoppedRequest(msg: DeskShareStoppedRequest) {
|
|
||||||
log.info("handleDeskShareStoppedRequest: dsStarted=" + meetingModel.getDeskShareStarted())
|
|
||||||
|
|
||||||
// Tell FreeSwitch to stop broadcasting to RTMP
|
|
||||||
outGW.send(new DeskShareStopRTMPBroadcast(msg.conferenceName, meetingModel.getRTMPBroadcastingUrl()))
|
|
||||||
|
|
||||||
meetingModel.setDeskShareStarted(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def handleDeskShareRTMPBroadcastStartedRequest(msg: DeskShareRTMPBroadcastStartedRequest) {
|
|
||||||
log.info("handleDeskShareRTMPBroadcastStartedRequest: isBroadcastingRTMP=" + meetingModel.isBroadcastingRTMP())
|
|
||||||
|
|
||||||
// only valid if not broadcasting yet
|
|
||||||
if (!meetingModel.isBroadcastingRTMP()) {
|
|
||||||
meetingModel.setRTMPBroadcastingUrl(msg.streamname)
|
|
||||||
meetingModel.broadcastingRTMPStarted()
|
|
||||||
meetingModel.setDesktopShareVideoWidth(msg.videoWidth)
|
|
||||||
meetingModel.setDesktopShareVideoHeight(msg.videoHeight)
|
|
||||||
log.info("START broadcast ALLOWED when isBroadcastingRTMP=false")
|
|
||||||
|
|
||||||
// Notify viewers in the meeting that there's an rtmp stream to view
|
|
||||||
outGW.send(new DeskShareNotifyViewersRTMP(mProps.meetingID, msg.streamname, msg.videoWidth, msg.videoHeight, true))
|
|
||||||
} else {
|
|
||||||
log.info("START broadcast NOT ALLOWED when isBroadcastingRTMP=true")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def handleDeskShareRTMPBroadcastStoppedRequest(msg: DeskShareRTMPBroadcastStoppedRequest) {
|
|
||||||
log.info("handleDeskShareRTMPBroadcastStoppedRequest: isBroadcastingRTMP=" + meetingModel.isBroadcastingRTMP())
|
|
||||||
|
|
||||||
// only valid if currently broadcasting
|
|
||||||
if (meetingModel.isBroadcastingRTMP()) {
|
|
||||||
log.info("STOP broadcast ALLOWED when isBroadcastingRTMP=true")
|
|
||||||
meetingModel.broadcastingRTMPStopped()
|
|
||||||
|
|
||||||
// notify viewers that RTMP broadcast stopped
|
|
||||||
outGW.send(new DeskShareNotifyViewersRTMP(mProps.meetingID, meetingModel.getRTMPBroadcastingUrl(),
|
|
||||||
msg.videoWidth, msg.videoHeight, false))
|
|
||||||
} else {
|
|
||||||
log.info("STOP broadcast NOT ALLOWED when isBroadcastingRTMP=false")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def handleDeskShareGetDeskShareInfoRequest(msg: DeskShareGetDeskShareInfoRequest): Unit = {
|
|
||||||
|
|
||||||
log.info("handleDeskShareGetDeskShareInfoRequest: " + msg.conferenceName + "isBroadcasting=" + meetingModel.isBroadcastingRTMP())
|
|
||||||
if (meetingModel.isBroadcastingRTMP()) {
|
|
||||||
// if the meeting has an ongoing WebRTC Deskshare session, send a notification
|
|
||||||
outGW.send(new DeskShareNotifyASingleViewer(mProps.meetingID, msg.requesterID, meetingModel.getRTMPBroadcastingUrl(),
|
|
||||||
meetingModel.getDesktopShareVideoWidth(), meetingModel.getDesktopShareVideoHeight(), true))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@ import java.util.concurrent.TimeUnit
|
|||||||
|
|
||||||
case object StopMeetingActor
|
case object StopMeetingActor
|
||||||
case class MeetingProperties(meetingID: String, externalMeetingID: String, meetingName: String, recorded: Boolean,
|
case class MeetingProperties(meetingID: String, externalMeetingID: String, meetingName: String, recorded: Boolean,
|
||||||
voiceBridge: String, duration: Int, autoStartRecording: Boolean, allowStartStopRecording: Boolean,
|
voiceBridge: String, deskshareBridge: String, duration: Int, autoStartRecording: Boolean,
|
||||||
moderatorPass: String, viewerPass: String, createTime: Long, createDate: String,
|
allowStartStopRecording: Boolean, moderatorPass: String, viewerPass: String, createTime: Long,
|
||||||
red5DeskShareIP: String, red5DeskShareApp: String, isBreakout: Boolean)
|
createDate: String, red5DeskShareIP: String, red5DeskShareApp: String, isBreakout: Boolean)
|
||||||
|
|
||||||
case class MeetingExtensionProp(maxExtensions: Int = 2, numExtensions: Int = 0, extendByMinutes: Int = 20,
|
case class MeetingExtensionProp(maxExtensions: Int = 2, numExtensions: Int = 0, extendByMinutes: Int = 20,
|
||||||
sendNotice: Boolean = true, sent15MinNotice: Boolean = false,
|
sendNotice: Boolean = true, sent15MinNotice: Boolean = false,
|
||||||
|
@ -7,6 +7,7 @@ trait AppsTestFixtures {
|
|||||||
val meetingName = "test meeting"
|
val meetingName = "test meeting"
|
||||||
val record = false
|
val record = false
|
||||||
val voiceConfId = "85115"
|
val voiceConfId = "85115"
|
||||||
|
val deskshareConfId = "85115-DESKSHARE"
|
||||||
val durationInMinutes = 10
|
val durationInMinutes = 10
|
||||||
val autoStartRecording = false
|
val autoStartRecording = false
|
||||||
val allowStartStopRecording = false
|
val allowStartStopRecording = false
|
||||||
@ -18,7 +19,7 @@ trait AppsTestFixtures {
|
|||||||
|
|
||||||
val mProps = new MeetingProperties(meetingId, externalMeetingId,
|
val mProps = new MeetingProperties(meetingId, externalMeetingId,
|
||||||
meetingName, record,
|
meetingName, record,
|
||||||
voiceConfId,
|
voiceConfId, deskshareConfId,
|
||||||
durationInMinutes,
|
durationInMinutes,
|
||||||
autoStartRecording, allowStartStopRecording,
|
autoStartRecording, allowStartStopRecording,
|
||||||
moderatorPassword, viewerPassword,
|
moderatorPassword, viewerPassword,
|
||||||
|
@ -13,20 +13,12 @@
|
|||||||
<include>
|
<include>
|
||||||
<context name="default">
|
<context name="default">
|
||||||
<extension name="public_extensions">
|
<extension name="public_extensions">
|
||||||
<condition field="destination_number" expression="^\d{5}$">
|
<condition field="destination_number" expression="^\d{5}-DESKSHARE$">
|
||||||
<action application="log" data="INFO AAAAAA transferring to $1 XML public!!"/>
|
<action application="log" data="INFO AAAAAA transferring to $1 XML public!!"/>
|
||||||
<action application="transfer" data="${destination_number} XML public"/>
|
<action application="transfer" data="${destination_number} XML public"/>
|
||||||
</condition>
|
</condition>
|
||||||
</extension>
|
</extension>
|
||||||
|
|
||||||
|
|
||||||
<extension name="public_extensions">
|
|
||||||
<condition field="destination_number" expression="^(\d{5})(-screen)$">
|
|
||||||
<action application="log" data="INFO BB $1 $2 BBBB transferring to $1 XML public!!"/>
|
|
||||||
<action application="transfer" data="$1 XML public"/>
|
|
||||||
</condition>
|
|
||||||
</extension>
|
|
||||||
|
|
||||||
<!-- other extensions -->
|
<!-- other extensions -->
|
||||||
|
|
||||||
</context>
|
</context>
|
||||||
|
@ -16,10 +16,10 @@
|
|||||||
<!-- other extensions -->
|
<!-- other extensions -->
|
||||||
|
|
||||||
<extension name="public_extensions">
|
<extension name="public_extensions">
|
||||||
<condition field="destination_number" expression="^\d{5}$">
|
<condition field="destination_number" expression="^\d{5}-DESKSHARE$">
|
||||||
<action application="log" data="INFO ************ redirecting ${destination_number} to ${destination_number}-DESKSHARE@video-mcu-stereo ***********" />
|
<action application="log" data="INFO ************WEBRTC DESKSHARE EXT***********" />
|
||||||
<action application="answer"/>
|
<action application="answer"/>
|
||||||
<action application="conference" data="${destination_number}-DESKSHARE@video-mcu-stereo"/>
|
<action application="conference" data="${destination_number}@video-mcu-stereo"/>
|
||||||
</condition>
|
</condition>
|
||||||
</extension>
|
</extension>
|
||||||
|
|
||||||
|
@ -28,8 +28,6 @@ public class ESLEventListener implements IEslEventListener {
|
|||||||
private static final String STOP_RECORDING_EVENT = "stop-recording";
|
private static final String STOP_RECORDING_EVENT = "stop-recording";
|
||||||
|
|
||||||
private static final String DESKSHARE_CONFERENCE_NAME_SUFFIX = "-DESKSHARE";
|
private static final String DESKSHARE_CONFERENCE_NAME_SUFFIX = "-DESKSHARE";
|
||||||
private static final String DESKSHARE_CALLER_NAME_SUFFIX = " (Screen)";
|
|
||||||
private static final String DESKSHARE_CALLER_ID_SUFFIX = " (screen)";
|
|
||||||
|
|
||||||
private final ConferenceEventListener conferenceEventListener;
|
private final ConferenceEventListener conferenceEventListener;
|
||||||
|
|
||||||
@ -68,53 +66,53 @@ public class ESLEventListener implements IEslEventListener {
|
|||||||
|
|
||||||
String voiceUserId = callerIdName;
|
String voiceUserId = callerIdName;
|
||||||
|
|
||||||
System.out.println("User joined voice conference, user=[" + callerIdName + "], conf=[" + confName + "]");
|
|
||||||
|
|
||||||
Matcher gapMatcher = GLOBAL_AUDION_PATTERN.matcher(callerIdName);
|
Matcher gapMatcher = GLOBAL_AUDION_PATTERN.matcher(callerIdName);
|
||||||
if (gapMatcher.matches()) {
|
if (gapMatcher.matches()) {
|
||||||
System.out.println("Ignoring GLOBAL AUDIO USER [" + callerIdName + "]");
|
System.out.println("Ignoring GLOBAL AUDIO USER [" + callerIdName + "]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deskstop sharing conferences have their name in the form ddddd-DESKSHARE
|
// (WebRTC) Deskstop sharing conferences' name is of the form ddddd-DESKSHARE
|
||||||
// Deskstop sharing conferences have the user with the desktop video displayed in this way:
|
// Voice conferences' name is of the form ddddd
|
||||||
// username (Screen) and usernum (screen)
|
if (confName.endsWith(DESKSHARE_CONFERENCE_NAME_SUFFIX)) {
|
||||||
if (confName.endsWith(DESKSHARE_CONFERENCE_NAME_SUFFIX) &&
|
System.out.println("User joined deskshare conference, user=[" + callerIdName + "], " +
|
||||||
callerId.endsWith(DESKSHARE_CALLER_ID_SUFFIX) &&
|
"conf=[" + confName + "] callerId=[" + callerId + "]");
|
||||||
callerIdName.endsWith(DESKSHARE_CALLER_NAME_SUFFIX)) {
|
|
||||||
DeskShareStartedEvent dsStart = new DeskShareStartedEvent(confName, callerId, callerIdName);
|
DeskShareStartedEvent dsStart = new DeskShareStartedEvent(confName, callerId, callerIdName);
|
||||||
conferenceEventListener.handleConferenceEvent(dsStart);
|
conferenceEventListener.handleConferenceEvent(dsStart);
|
||||||
}
|
} else {
|
||||||
|
Matcher matcher = CALLERNAME_PATTERN.matcher(callerIdName);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
voiceUserId = matcher.group(1).trim();
|
||||||
|
callerIdName = matcher.group(2).trim();
|
||||||
|
}
|
||||||
|
|
||||||
Matcher matcher = CALLERNAME_PATTERN.matcher(callerIdName);
|
System.out.println("User joined voice conference, user=[" + callerIdName + "], conf=[" +
|
||||||
if (matcher.matches()) {
|
confName + "] callerId=[" + callerId + "]");
|
||||||
voiceUserId = matcher.group(1).trim();
|
|
||||||
callerIdName = matcher.group(2).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
VoiceUserJoinedEvent pj = new VoiceUserJoinedEvent(voiceUserId, memberId.toString(), confName, callerId, callerIdName, muted, speaking, "");
|
VoiceUserJoinedEvent pj = new VoiceUserJoinedEvent(voiceUserId, memberId.toString(), confName, callerId, callerIdName, muted, speaking, "");
|
||||||
conferenceEventListener.handleConferenceEvent(pj);
|
conferenceEventListener.handleConferenceEvent(pj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void conferenceEventLeave(String uniqueId, String confName, int confSize, EslEvent event) {
|
public void conferenceEventLeave(String uniqueId, String confName, int confSize, EslEvent event) {
|
||||||
Integer memberId = this.getMemberIdFromEvent(event);
|
Integer memberId = this.getMemberIdFromEvent(event);
|
||||||
System.out.println("User left voice conference, user=[" + memberId.toString() + "], conf=[" + confName + "]");
|
|
||||||
String callerId = this.getCallerIdFromEvent(event);
|
String callerId = this.getCallerIdFromEvent(event);
|
||||||
String callerIdName = this.getCallerIdNameFromEvent(event);
|
String callerIdName = this.getCallerIdNameFromEvent(event);
|
||||||
|
|
||||||
// Deskstop sharing conferences have their name in the form ddddd-DESKSHARE
|
// (WebRTC) Deskstop sharing conferences' name is of the form ddddd-DESKSHARE
|
||||||
// Deskstop sharing conferences have the user with the desktop video displayed in this way:
|
// Voice conferences' name is of the form ddddd
|
||||||
// username (Screen) and usernum (screen)
|
if (confName.endsWith(DESKSHARE_CONFERENCE_NAME_SUFFIX)) {
|
||||||
if (confName.endsWith(DESKSHARE_CONFERENCE_NAME_SUFFIX) &&
|
System.out.println("User left deskshare conference, user=[" + memberId.toString() +
|
||||||
callerId.endsWith(DESKSHARE_CALLER_ID_SUFFIX) &&
|
"], " + "conf=[" + confName + "]");
|
||||||
callerIdName.endsWith(DESKSHARE_CALLER_NAME_SUFFIX)) {
|
|
||||||
DeskShareEndedEvent dsEnd = new DeskShareEndedEvent(confName, callerId, callerIdName);
|
DeskShareEndedEvent dsEnd = new DeskShareEndedEvent(confName, callerId, callerIdName);
|
||||||
conferenceEventListener.handleConferenceEvent(dsEnd);
|
conferenceEventListener.handleConferenceEvent(dsEnd);
|
||||||
|
} else {
|
||||||
|
System.out.println("User left voice conference, user=[" + memberId.toString() + "], " +
|
||||||
|
"conf=[" + confName + "]");
|
||||||
|
VoiceUserLeftEvent pl = new VoiceUserLeftEvent(memberId.toString(), confName);
|
||||||
|
conferenceEventListener.handleConferenceEvent(pl);
|
||||||
}
|
}
|
||||||
|
|
||||||
VoiceUserLeftEvent pl = new VoiceUserLeftEvent(memberId.toString(), confName);
|
|
||||||
conferenceEventListener.handleConferenceEvent(pl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -231,7 +229,8 @@ public class ESLEventListener implements IEslEventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void eventReceived(EslEvent event) {
|
public void eventReceived(EslEvent event) {
|
||||||
System.out.println("ESL Event Listener received event=[" + event.getEventName() + "]");
|
System.out.println("ESL Event Listener received event=[" + event.getEventName() + "]" +
|
||||||
|
event.getEventHeaders().toString());
|
||||||
// if (event.getEventName().equals(FreeswitchHeartbeatMonitor.EVENT_HEARTBEAT)) {
|
// if (event.getEventName().equals(FreeswitchHeartbeatMonitor.EVENT_HEARTBEAT)) {
|
||||||
//// setChanged();
|
//// setChanged();
|
||||||
// notifyObservers(event);
|
// notifyObservers(event);
|
||||||
|
@ -14,8 +14,7 @@ import org.bigbluebutton.common.messages.DeskShareRTMPBroadcastStoppedEventMessa
|
|||||||
|
|
||||||
class VoiceConferenceService(sender: RedisPublisher) extends IVoiceConferenceService {
|
class VoiceConferenceService(sender: RedisPublisher) extends IVoiceConferenceService {
|
||||||
|
|
||||||
val FROM_VOICE_CONF_SYSTEM_CHAN = "bigbluebutton:from-voice-conf:system";
|
val FROM_VOICE_CONF_SYSTEM_CHAN = "bigbluebutton:from-voice-conf:system"
|
||||||
private final val DESKSHARE_CONFERENCE_NAME_SUFFIX = "-DESKSHARE"
|
|
||||||
|
|
||||||
def voiceConfRecordingStarted(voiceConfId: String, recordStream: String, recording: java.lang.Boolean, timestamp: String) {
|
def voiceConfRecordingStarted(voiceConfId: String, recordStream: String, recording: java.lang.Boolean, timestamp: String) {
|
||||||
val msg = new VoiceConfRecordingStartedMessage(voiceConfId, recordStream, recording, timestamp)
|
val msg = new VoiceConfRecordingStartedMessage(voiceConfId, recordStream, recording, timestamp)
|
||||||
@ -24,13 +23,14 @@ class VoiceConferenceService(sender: RedisPublisher) extends IVoiceConferenceSer
|
|||||||
|
|
||||||
def userJoinedVoiceConf(voiceConfId: String, voiceUserId: String, userId: String, callerIdName: String,
|
def userJoinedVoiceConf(voiceConfId: String, voiceUserId: String, userId: String, callerIdName: String,
|
||||||
callerIdNum: String, muted: java.lang.Boolean, talking: java.lang.Boolean, avatarURL: String) {
|
callerIdNum: String, muted: java.lang.Boolean, talking: java.lang.Boolean, avatarURL: String) {
|
||||||
// println("******** FreeswitchConferenceService received voiceUserJoined vui=[" + userId + "] wui=[" + webUserId + "]")
|
println("******** FreeswitchConferenceService received voiceUserJoined vui=[" +
|
||||||
|
userId + "] wui=[" + voiceUserId + "]")
|
||||||
val msg = new UserJoinedVoiceConfMessage(voiceConfId, voiceUserId, userId, callerIdName, callerIdNum, muted, talking, avatarURL)
|
val msg = new UserJoinedVoiceConfMessage(voiceConfId, voiceUserId, userId, callerIdName, callerIdNum, muted, talking, avatarURL)
|
||||||
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
||||||
}
|
}
|
||||||
|
|
||||||
def userLeftVoiceConf(voiceConfId: String, voiceUserId: String) {
|
def userLeftVoiceConf(voiceConfId: String, voiceUserId: String) {
|
||||||
// println("******** FreeswitchConferenceService received voiceUserLeft vui=[" + userId + "] conference=[" + conference + "]")
|
println("******** FreeswitchConferenceService received voiceUserLeft vui=[" + voiceUserId + "] conference=[" + voiceConfId + "]")
|
||||||
val msg = new UserLeftVoiceConfMessage(voiceConfId, voiceUserId)
|
val msg = new UserLeftVoiceConfMessage(voiceConfId, voiceUserId)
|
||||||
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
||||||
}
|
}
|
||||||
@ -52,30 +52,26 @@ class VoiceConferenceService(sender: RedisPublisher) extends IVoiceConferenceSer
|
|||||||
}
|
}
|
||||||
|
|
||||||
def deskShareStarted(voiceConfId: String, callerIdNum: String, callerIdName: String) {
|
def deskShareStarted(voiceConfId: String, callerIdNum: String, callerIdName: String) {
|
||||||
val trimmedVoiceConfId = voiceConfId.replace(DESKSHARE_CONFERENCE_NAME_SUFFIX, "")
|
println("******** FreeswitchConferenceService send deskShareStarted to BBB " + voiceConfId)
|
||||||
println("******** FreeswitchConferenceService send deskShareStarted to BBB " + trimmedVoiceConfId)
|
val msg = new DeskShareStartedEventMessage(voiceConfId, callerIdNum, callerIdName)
|
||||||
val msg = new DeskShareStartedEventMessage(trimmedVoiceConfId, callerIdNum, callerIdName)
|
|
||||||
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
||||||
}
|
}
|
||||||
|
|
||||||
def deskShareEnded(voiceConfId: String, callerIdNum: String, callerIdName: String) {
|
def deskShareEnded(voiceConfId: String, callerIdNum: String, callerIdName: String) {
|
||||||
val trimmedVoiceConfId = voiceConfId.replace(DESKSHARE_CONFERENCE_NAME_SUFFIX, "")
|
println("******** FreeswitchConferenceService send deskShareStopped to BBB " + voiceConfId)
|
||||||
println("******** FreeswitchConferenceService send deskShareStopped to BBB " + trimmedVoiceConfId)
|
val msg = new DeskShareStoppedEventMessage(voiceConfId, callerIdNum, callerIdName)
|
||||||
val msg = new DeskShareStoppedEventMessage(trimmedVoiceConfId, callerIdNum, callerIdName)
|
|
||||||
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
||||||
}
|
}
|
||||||
|
|
||||||
def deskShareRTMPBroadcastStarted(voiceConfId: String, streamname: String, vw: java.lang.Integer, vh: java.lang.Integer, timestamp: String) {
|
def deskShareRTMPBroadcastStarted(voiceConfId: String, streamname: String, vw: java.lang.Integer, vh: java.lang.Integer, timestamp: String) {
|
||||||
val trimmedVoiceConfId = voiceConfId.replace(DESKSHARE_CONFERENCE_NAME_SUFFIX, "")
|
println("******** FreeswitchConferenceService send deskShareRTMPBroadcastStarted to BBB " + voiceConfId)
|
||||||
println("******** FreeswitchConferenceService send deskShareRTMPBroadcastStarted to BBB " + trimmedVoiceConfId)
|
val msg = new DeskShareRTMPBroadcastStartedEventMessage(voiceConfId, streamname, vw, vh, timestamp)
|
||||||
val msg = new DeskShareRTMPBroadcastStartedEventMessage(trimmedVoiceConfId, streamname, vw, vh, timestamp)
|
|
||||||
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
||||||
}
|
}
|
||||||
|
|
||||||
def deskShareRTMPBroadcastStopped(voiceConfId: String, streamname: String, vw: java.lang.Integer, vh: java.lang.Integer, timestamp: String) {
|
def deskShareRTMPBroadcastStopped(voiceConfId: String, streamname: String, vw: java.lang.Integer, vh: java.lang.Integer, timestamp: String) {
|
||||||
val trimmedVoiceConfId = voiceConfId.replace(DESKSHARE_CONFERENCE_NAME_SUFFIX, "")
|
println("******** FreeswitchConferenceService send deskShareRTMPBroadcastStopped to BBB " + voiceConfId)
|
||||||
println("******** FreeswitchConferenceService send deskShareRTMPBroadcastStopped to BBB " + trimmedVoiceConfId)
|
val msg = new DeskShareRTMPBroadcastStoppedEventMessage(voiceConfId, streamname, vw, vh, timestamp)
|
||||||
val msg = new DeskShareRTMPBroadcastStoppedEventMessage(trimmedVoiceConfId, streamname, vw, vh, timestamp)
|
|
||||||
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,13 +42,15 @@
|
|||||||
baseTabIndex="301"
|
baseTabIndex="301"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<module name="ScreenshareModule"
|
<module name="ScreenshareModule"
|
||||||
url="http://HOST/client/ScreenshareModule.swf?v=VERSION"
|
url="http://HOST/client/ScreenshareModule.swf?v=VERSION"
|
||||||
uri="rtmp://HOST/screenshare"
|
uri="rtmp://HOST/screenshare"
|
||||||
showButton="true"
|
showButton="true"
|
||||||
autoStart="false"
|
autoStart="false"
|
||||||
autoFullScreen="false"
|
autoFullScreen="false"
|
||||||
baseTabIndex="201"
|
baseTabIndex="201"
|
||||||
|
useWebRTCIfAvailable="false"
|
||||||
|
chromeExtensionKey=""
|
||||||
help="http://HOST/client/help/screenshare-help.html"
|
help="http://HOST/client/help/screenshare-help.html"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -105,7 +105,6 @@
|
|||||||
<script src="lib/jquery.verto.js" language="javascript"></script>
|
<script src="lib/jquery.verto.js" language="javascript"></script>
|
||||||
<script src="lib/Screen-Capturing.js" language="javascript"></script>
|
<script src="lib/Screen-Capturing.js" language="javascript"></script>
|
||||||
<script src="lib/verto_extension.js" language="javascript"></script>
|
<script src="lib/verto_extension.js" language="javascript"></script>
|
||||||
<script src="lib/verto_extension_share.js" language="javascript"></script>
|
|
||||||
|
|
||||||
<script src="lib/bbb_deskshare.js?v=VERSION" language="javascript"></script>
|
<script src="lib/bbb_deskshare.js?v=VERSION" language="javascript"></script>
|
||||||
<script src="lib/bbb_api_bridge.js?v=VERSION" language="javascript"></script>
|
<script src="lib/bbb_api_bridge.js?v=VERSION" language="javascript"></script>
|
||||||
|
@ -92,8 +92,6 @@ var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
|
|||||||
var isChrome = !!window.chrome && !isOpera;
|
var isChrome = !!window.chrome && !isOpera;
|
||||||
|
|
||||||
function getChromeExtensionStatus(extensionid, callback) {
|
function getChromeExtensionStatus(extensionid, callback) {
|
||||||
callback = normalizeCallback(callback);
|
|
||||||
|
|
||||||
if (isFirefox) return callback('not-chrome');
|
if (isFirefox) return callback('not-chrome');
|
||||||
|
|
||||||
if (chromeMediaSource == 'desktop') return callback('installed-enabled');
|
if (chromeMediaSource == 'desktop') return callback('installed-enabled');
|
||||||
|
@ -103,7 +103,7 @@
|
|||||||
|
|
||||||
if (moz) {
|
if (moz) {
|
||||||
this.constraints = {
|
this.constraints = {
|
||||||
offerToReceiveAudio: true,
|
offerToReceiveAudio: this.options.useSpeak === "none" ? false : true,
|
||||||
offerToReceiveVideo: this.options.useVideo ? true : false,
|
offerToReceiveVideo: this.options.useVideo ? true : false,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@ -111,7 +111,7 @@
|
|||||||
optional: [{
|
optional: [{
|
||||||
'DtlsSrtpKeyAgreement': 'true'
|
'DtlsSrtpKeyAgreement': 'true'
|
||||||
}],mandatory: {
|
}],mandatory: {
|
||||||
OfferToReceiveAudio: true,
|
OfferToReceiveAudio: this.options.useSpeak === "none" ? false : true,
|
||||||
OfferToReceiveVideo: this.options.useVideo ? true : false,
|
OfferToReceiveVideo: this.options.useVideo ? true : false,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -342,8 +342,8 @@
|
|||||||
if(typeof self.options.localVideoStream.stop == 'function') {
|
if(typeof self.options.localVideoStream.stop == 'function') {
|
||||||
self.options.localVideoStream.stop();
|
self.options.localVideoStream.stop();
|
||||||
} else {
|
} else {
|
||||||
if (self.localVideoStream.active){
|
if (self.options.localVideoStream.active){
|
||||||
var tracks = self.localVideoStream.getTracks();
|
var tracks = self.options.localVideoStream.getTracks();
|
||||||
console.error(tracks);
|
console.error(tracks);
|
||||||
tracks.forEach(function(track, index){
|
tracks.forEach(function(track, index){
|
||||||
console.log(track);
|
console.log(track);
|
||||||
@ -513,7 +513,7 @@
|
|||||||
audio = false;
|
audio = false;
|
||||||
} else {
|
} else {
|
||||||
audio = {
|
audio = {
|
||||||
mandatory: obj.options.audioParams,
|
mandatory: {},
|
||||||
optional: []
|
optional: []
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -521,6 +521,15 @@
|
|||||||
audio.optional = [{sourceId: obj.options.useMic}]
|
audio.optional = [{sourceId: obj.options.useMic}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj.options.audioParams) {
|
||||||
|
for (var key in obj.options.audioParams) {
|
||||||
|
var con = {};
|
||||||
|
con[key] = obj.options.audioParams[key];
|
||||||
|
audio.optional.push(con);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.options.useVideo && obj.options.localVideo) {
|
if (obj.options.useVideo && obj.options.localVideo) {
|
||||||
@ -558,8 +567,9 @@
|
|||||||
video.optional.push({sourceId: obj.options.useCamera});
|
video.optional.push({sourceId: obj.options.useCamera});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bestFrameRate && !window.moz) {
|
if (bestFrameRate) {
|
||||||
video.optional.push({minFrameRate: bestFrameRate});
|
video.optional.push({minFrameRate: bestFrameRate});
|
||||||
|
video.optional.push({maxFrameRate: bestFrameRate});
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -603,15 +613,7 @@
|
|||||||
onICEComplete: function() {
|
onICEComplete: function() {
|
||||||
return onICEComplete(self);
|
return onICEComplete(self);
|
||||||
},
|
},
|
||||||
onRemoteStream: screen ? function(stream) {
|
onRemoteStream: screen ? function(stream) {} : function(stream) {
|
||||||
// Added by Dan Perrone (perroned)
|
|
||||||
// https://github.com/perroned
|
|
||||||
// Date: January 13, 2016
|
|
||||||
// Commit: 279f40a4c280bba11052adc621fddbb3135ccb6d
|
|
||||||
|
|
||||||
verto_afterStreamPublish();} :
|
|
||||||
// ----------------------------------------------------
|
|
||||||
function(stream) {
|
|
||||||
return onRemoteStream(self, stream);
|
return onRemoteStream(self, stream);
|
||||||
},
|
},
|
||||||
onOfferSDP: function(sdp) {
|
onOfferSDP: function(sdp) {
|
||||||
@ -633,58 +635,12 @@
|
|||||||
function onError(e) {
|
function onError(e) {
|
||||||
onStreamError(self, e);
|
onStreamError(self, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
var mediaParams = getMediaParams(self);
|
var mediaParams = getMediaParams(self);
|
||||||
|
|
||||||
console.log("Audio constraints", mediaParams.audio);
|
console.log("Audio constraints", mediaParams.audio);
|
||||||
console.log("Video constraints", mediaParams.video);
|
console.log("Video constraints", mediaParams.video);
|
||||||
|
|
||||||
// Added by Dan Perrone (perroned)
|
|
||||||
// https://github.com/perroned
|
|
||||||
// Date: January 13, 2016
|
|
||||||
// Commit: 279f40a4c280bba11052adc621fddbb3135ccb6d
|
|
||||||
|
|
||||||
// watchOnly, listenOnly, joinAudio
|
|
||||||
// modify the gUM calls based on additional types of calls I added
|
|
||||||
if (window.watchOnly && !window.listenOnly && !window.joinAudio) {
|
|
||||||
var stream = null;
|
|
||||||
if (typeof webkitMediaStream !== 'undefined') {
|
|
||||||
// Google Chrome
|
|
||||||
stream = new webkitMediaStream;
|
|
||||||
} else {
|
|
||||||
// Firefox
|
|
||||||
audioContext = new window.AudioContext;
|
|
||||||
stream = audioContext.createMediaStreamDestination().stream;
|
|
||||||
}
|
|
||||||
onSuccess(stream);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (window.listenOnly && !window.watchOnly && !window.joinAudio) {
|
|
||||||
var stream = null;
|
|
||||||
if (typeof webkitMediaStream !== 'undefined') {
|
|
||||||
// Google Chrome
|
|
||||||
stream = new webkitMediaStream;
|
|
||||||
} else {
|
|
||||||
// Firefox
|
|
||||||
audioContext = new window.AudioContext;
|
|
||||||
stream = audioContext.createMediaStreamDestination().stream;
|
|
||||||
}
|
|
||||||
onSuccess(stream);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (window.joinAudio && !window.watchOnly && !window.listenOnly) {
|
|
||||||
getUserMedia({
|
|
||||||
constraints: {
|
|
||||||
audio: mediaParams.audio,
|
|
||||||
video: mediaParams.video
|
|
||||||
},
|
|
||||||
video: mediaParams.useVideo,
|
|
||||||
onsuccess: onSuccess,
|
|
||||||
onerror: onError
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// ---------------------------------------------------
|
|
||||||
|
|
||||||
if (mediaParams.audio || mediaParams.video) {
|
if (mediaParams.audio || mediaParams.video) {
|
||||||
|
|
||||||
getUserMedia({
|
getUserMedia({
|
||||||
@ -1078,41 +1034,13 @@
|
|||||||
var n = navigator,
|
var n = navigator,
|
||||||
media;
|
media;
|
||||||
n.getMedia = n.webkitGetUserMedia || n.mozGetUserMedia;
|
n.getMedia = n.webkitGetUserMedia || n.mozGetUserMedia;
|
||||||
|
n.getMedia(options.constraints || {
|
||||||
// Added by Dan Perrone (perroned)
|
audio: true,
|
||||||
// https://github.com/perroned
|
video: video_constraints
|
||||||
// Date: February 17, 2016
|
},
|
||||||
// Commit: 05488dda5d9d1048e286b0bdee27515d217b15a5
|
streaming, options.onerror ||
|
||||||
|
function(e) {
|
||||||
var constraints = {};
|
console.error(e);
|
||||||
var errorCallback = null;
|
|
||||||
if (window.firefoxDesksharePresent) {
|
|
||||||
window.firefoxDesksharePresent = false;
|
|
||||||
constraints = {
|
|
||||||
audio: false,
|
|
||||||
video: {
|
|
||||||
mediaSource: 'window',
|
|
||||||
mozMediaSource: 'window'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
constraints = options.constraints || {
|
|
||||||
audio: true,
|
|
||||||
video: video_constraints
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// if a callback was added use it, otherwise use default error handler
|
|
||||||
if (typeof window.firefoxDesksharePresentErrorCallback === "function") {
|
|
||||||
errorCallback = window.firefoxDesksharePresentErrorCallback;
|
|
||||||
} else {
|
|
||||||
errorCallback = options.onerror ||
|
|
||||||
function(e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n.getMedia(constraints, streaming, function() {
|
|
||||||
errorCallback({'status': 'Failed to getUserMedia on Firefox', 'errorcode': 2000});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function streaming(stream) {
|
function streaming(stream) {
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
for (i = 0; i < loops; i++) {
|
for (i = 0; i < loops; i++) {
|
||||||
socket.send("#SPB " + data);
|
socket.send("#SPB " + data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rem) {
|
if (rem) {
|
||||||
socket.send("#SPB " + data);
|
socket.send("#SPB " + data);
|
||||||
}
|
}
|
||||||
@ -418,12 +418,12 @@
|
|||||||
|
|
||||||
var up_kps = (((this.speedBytes * 8) / (this.up_dur / 1000)) / 1024).toFixed(0);
|
var up_kps = (((this.speedBytes * 8) / (this.up_dur / 1000)) / 1024).toFixed(0);
|
||||||
var down_kps = (((this.speedBytes * 8) / (this.down_dur / 1000)) / 1024).toFixed(0);
|
var down_kps = (((this.speedBytes * 8) / (this.down_dur / 1000)) / 1024).toFixed(0);
|
||||||
|
|
||||||
console.info("Speed Test: Up: " + up_kps + " Down: " + down_kps);
|
console.info("Speed Test: Up: " + up_kps + " Down: " + down_kps);
|
||||||
this.speedCB(event, { upDur: this.up_dur, downDur: this.down_dur, upKPS: up_kps, downKPS: down_kps });
|
this.speedCB(event, { upDur: this.up_dur, downDur: this.down_dur, upKPS: up_kps, downKPS: down_kps });
|
||||||
this.speedCB = null;
|
this.speedCB = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,8 +132,13 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var tag = verto.options.tag;
|
||||||
|
if (typeof(tag) === "function") {
|
||||||
|
tag = tag();
|
||||||
|
}
|
||||||
|
|
||||||
if (verto.options.ringFile && verto.options.tag) {
|
if (verto.options.ringFile && verto.options.tag) {
|
||||||
verto.ringer = $("#" + verto.options.tag);
|
verto.ringer = $("#" + tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
verto.rpcClient.call('login', {});
|
verto.rpcClient.call('login', {});
|
||||||
@ -473,7 +478,7 @@
|
|||||||
|
|
||||||
if (data.params.callID) {
|
if (data.params.callID) {
|
||||||
var dialog = verto.dialogs[data.params.callID];
|
var dialog = verto.dialogs[data.params.callID];
|
||||||
|
|
||||||
if (data.method === "verto.attach" && dialog) {
|
if (data.method === "verto.attach" && dialog) {
|
||||||
delete dialog.verto.dialogs[dialog.callID];
|
delete dialog.verto.dialogs[dialog.callID];
|
||||||
dialog.rtc.stop();
|
dialog.rtc.stop();
|
||||||
@ -1308,11 +1313,15 @@
|
|||||||
this.modCommand("vid-write-png", null, file);
|
this.modCommand("vid-write-png", null, file);
|
||||||
};
|
};
|
||||||
|
|
||||||
$.verto.conf.prototype.setVideoLayout = function(layout) {
|
$.verto.conf.prototype.setVideoLayout = function(layout, canvasID) {
|
||||||
if (!this.params.hasVid) {
|
if (!this.params.hasVid) {
|
||||||
throw 'Conference has no video';
|
throw 'Conference has no video';
|
||||||
}
|
}
|
||||||
this.modCommand("vid-layout", null, layout);
|
if (canvasID) {
|
||||||
|
this.modCommand("vid-layout", null, [layout, canvasID]);
|
||||||
|
} else {
|
||||||
|
this.modCommand("vid-layout", null, layout);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$.verto.conf.prototype.kick = function(memberID) {
|
$.verto.conf.prototype.kick = function(memberID) {
|
||||||
@ -1382,7 +1391,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$.verto.modfuncs = {};
|
$.verto.modfuncs = {};
|
||||||
@ -1405,7 +1414,7 @@
|
|||||||
confMan.verto = verto;
|
confMan.verto = verto;
|
||||||
confMan.serno = CONFMAN_SERNO++;
|
confMan.serno = CONFMAN_SERNO++;
|
||||||
confMan.canvasCount = confMan.params.laData.canvasCount;
|
confMan.canvasCount = confMan.params.laData.canvasCount;
|
||||||
|
|
||||||
function genMainMod(jq) {
|
function genMainMod(jq) {
|
||||||
var play_id = "play_" + confMan.serno;
|
var play_id = "play_" + confMan.serno;
|
||||||
var stop_id = "stop_" + confMan.serno;
|
var stop_id = "stop_" + confMan.serno;
|
||||||
@ -1424,7 +1433,7 @@
|
|||||||
|
|
||||||
jq.html(html);
|
jq.html(html);
|
||||||
|
|
||||||
$.verto.modfuncs.change_video_layout = function(id, canvas_id) {
|
$.verto.modfuncs.change_video_layout = function(id, canvas_id) {
|
||||||
var val = $("#" + id + " option:selected").text();
|
var val = $("#" + id + " option:selected").text();
|
||||||
if (val !== "none") {
|
if (val !== "none") {
|
||||||
confMan.modCommand("vid-layout", null, [val, canvas_id]);
|
confMan.modCommand("vid-layout", null, [val, canvas_id]);
|
||||||
@ -1435,11 +1444,11 @@
|
|||||||
for (var j = 0; j < confMan.canvasCount; j++) {
|
for (var j = 0; j < confMan.canvasCount; j++) {
|
||||||
var vlayout_id = "confman_vid_layout_" + j + "_" + confMan.serno;
|
var vlayout_id = "confman_vid_layout_" + j + "_" + confMan.serno;
|
||||||
var vlselect_id = "confman_vl_select_" + j + "_" + confMan.serno;
|
var vlselect_id = "confman_vl_select_" + j + "_" + confMan.serno;
|
||||||
|
|
||||||
|
|
||||||
var vlhtml = "<div id='" + vlayout_id + "'><br>" +
|
var vlhtml = "<div id='" + vlayout_id + "'><br>" +
|
||||||
"<b>Video Layout Canvas " + (j+1) +
|
"<b>Video Layout Canvas " + (j+1) +
|
||||||
"</b> <select onChange='$.verto.modfuncs.change_video_layout(\"" + vlayout_id + "\", \"" + j + "\")' id='" + vlselect_id + "'></select> " +
|
"</b> <select onChange='$.verto.modfuncs.change_video_layout(\"" + vlayout_id + "\", \"" + (j+1) + "\")' id='" + vlselect_id + "'></select> " +
|
||||||
"<br><br></div>";
|
"<br><br></div>";
|
||||||
jq.append(vlhtml);
|
jq.append(vlhtml);
|
||||||
}
|
}
|
||||||
@ -1490,7 +1499,7 @@
|
|||||||
var layer_set_id = "layer_set_" + x;
|
var layer_set_id = "layer_set_" + x;
|
||||||
var layer_next_id = "layer_next_" + x;
|
var layer_next_id = "layer_next_" + x;
|
||||||
var layer_prev_id = "layer_prev_" + x;
|
var layer_prev_id = "layer_prev_" + x;
|
||||||
|
|
||||||
var tmute_id = "tmute_" + x;
|
var tmute_id = "tmute_" + x;
|
||||||
var tvmute_id = "tvmute_" + x;
|
var tvmute_id = "tvmute_" + x;
|
||||||
var vbanner_id = "vbanner_" + x;
|
var vbanner_id = "vbanner_" + x;
|
||||||
@ -1502,7 +1511,7 @@
|
|||||||
var volup_id = "vol_in_up" + x;
|
var volup_id = "vol_in_up" + x;
|
||||||
var voldn_id = "vol_in_dn" + x;
|
var voldn_id = "vol_in_dn" + x;
|
||||||
var transfer_id = "transfer" + x;
|
var transfer_id = "transfer" + x;
|
||||||
|
|
||||||
|
|
||||||
var html = "<div id='" + box_id + "'>";
|
var html = "<div id='" + box_id + "'>";
|
||||||
|
|
||||||
@ -1515,7 +1524,7 @@
|
|||||||
"<button class='ctlbtn' id='" + voldn_id + "'>Vol -</button>" +
|
"<button class='ctlbtn' id='" + voldn_id + "'>Vol -</button>" +
|
||||||
"<button class='ctlbtn' id='" + volup_id + "'>Vol +</button>" +
|
"<button class='ctlbtn' id='" + volup_id + "'>Vol +</button>" +
|
||||||
"<button class='ctlbtn' id='" + transfer_id + "'>Transfer</button>";
|
"<button class='ctlbtn' id='" + transfer_id + "'>Transfer</button>";
|
||||||
|
|
||||||
if (confMan.params.hasVid) {
|
if (confMan.params.hasVid) {
|
||||||
html += "<br><br><b>Video Controls</b><hr noshade>";
|
html += "<br><br><b>Video Controls</b><hr noshade>";
|
||||||
|
|
||||||
@ -1530,14 +1539,14 @@
|
|||||||
"<button class='ctlbtn' id='" + canvas_in_set_id + "'>Set Input Canvas</button>" +
|
"<button class='ctlbtn' id='" + canvas_in_set_id + "'>Set Input Canvas</button>" +
|
||||||
"<button class='ctlbtn' id='" + canvas_in_prev_id + "'>Prev Input Canvas</button>" +
|
"<button class='ctlbtn' id='" + canvas_in_prev_id + "'>Prev Input Canvas</button>" +
|
||||||
"<button class='ctlbtn' id='" + canvas_in_next_id + "'>Next Input Canvas</button>" +
|
"<button class='ctlbtn' id='" + canvas_in_next_id + "'>Next Input Canvas</button>" +
|
||||||
|
|
||||||
"<br>" +
|
"<br>" +
|
||||||
|
|
||||||
"<button class='ctlbtn' id='" + canvas_out_set_id + "'>Set Watching Canvas</button>" +
|
"<button class='ctlbtn' id='" + canvas_out_set_id + "'>Set Watching Canvas</button>" +
|
||||||
"<button class='ctlbtn' id='" + canvas_out_prev_id + "'>Prev Watching Canvas</button>" +
|
"<button class='ctlbtn' id='" + canvas_out_prev_id + "'>Prev Watching Canvas</button>" +
|
||||||
"<button class='ctlbtn' id='" + canvas_out_next_id + "'>Next Watching Canvas</button>";
|
"<button class='ctlbtn' id='" + canvas_out_next_id + "'>Next Watching Canvas</button>";
|
||||||
}
|
}
|
||||||
|
|
||||||
html += "<br>" +
|
html += "<br>" +
|
||||||
|
|
||||||
"<button class='ctlbtn' id='" + layer_set_id + "'>Set Layer</button>" +
|
"<button class='ctlbtn' id='" + layer_set_id + "'>Set Layer</button>" +
|
||||||
@ -1620,7 +1629,7 @@
|
|||||||
$("#" + canvas_out_prev_id).click(function() {
|
$("#" + canvas_out_prev_id).click(function() {
|
||||||
confMan.modCommand("vid-watching-canvas", x, "prev");
|
confMan.modCommand("vid-watching-canvas", x, "prev");
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#" + tmute_id).click(function() {
|
$("#" + tmute_id).click(function() {
|
||||||
confMan.modCommand("tmute", x);
|
confMan.modCommand("tmute", x);
|
||||||
});
|
});
|
||||||
@ -1697,14 +1706,14 @@
|
|||||||
for (var j = 0; j < confMan.canvasCount; j++) {
|
for (var j = 0; j < confMan.canvasCount; j++) {
|
||||||
var vlselect_id = "#confman_vl_select_" + j + "_" + confMan.serno;
|
var vlselect_id = "#confman_vl_select_" + j + "_" + confMan.serno;
|
||||||
var vlayout_id = "#confman_vid_layout_" + j + "_" + confMan.serno;
|
var vlayout_id = "#confman_vid_layout_" + j + "_" + confMan.serno;
|
||||||
|
|
||||||
var x = 0;
|
var x = 0;
|
||||||
var options;
|
var options;
|
||||||
|
|
||||||
$(vlselect_id).selectmenu({});
|
$(vlselect_id).selectmenu({});
|
||||||
$(vlselect_id).selectmenu("enable");
|
$(vlselect_id).selectmenu("enable");
|
||||||
$(vlselect_id).empty();
|
$(vlselect_id).empty();
|
||||||
|
|
||||||
$(vlselect_id).append(new Option("Choose a Layout", "none"));
|
$(vlselect_id).append(new Option("Choose a Layout", "none"));
|
||||||
|
|
||||||
if (e.data.responseData) {
|
if (e.data.responseData) {
|
||||||
@ -1713,15 +1722,15 @@
|
|||||||
for (var i in e.data.responseData) {
|
for (var i in e.data.responseData) {
|
||||||
rdata.push(e.data.responseData[i].name);
|
rdata.push(e.data.responseData[i].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
options = rdata.sort(function(a, b) {
|
options = rdata.sort(function(a, b) {
|
||||||
var ga = a.substring(0, 6) == "group:" ? true : false;
|
var ga = a.substring(0, 6) == "group:" ? true : false;
|
||||||
var gb = b.substring(0, 6) == "group:" ? true : false;
|
var gb = b.substring(0, 6) == "group:" ? true : false;
|
||||||
|
|
||||||
if ((ga || gb) && ga != gb) {
|
if ((ga || gb) && ga != gb) {
|
||||||
return ga ? -1 : 1;
|
return ga ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ( ( a == b ) ? 0 : ( ( a > b ) ? 1 : -1 ) );
|
return ( ( a == b ) ? 0 : ( ( a > b ) ? 1 : -1 ) );
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1881,6 +1890,11 @@
|
|||||||
$.verto.dialog = function(direction, verto, params) {
|
$.verto.dialog = function(direction, verto, params) {
|
||||||
var dialog = this;
|
var dialog = this;
|
||||||
|
|
||||||
|
var tag = verto.options.tag;
|
||||||
|
if (typeof(tag) === "function") {
|
||||||
|
tag = tag();
|
||||||
|
}
|
||||||
|
|
||||||
dialog.params = $.extend({
|
dialog.params = $.extend({
|
||||||
useVideo: verto.options.useVideo,
|
useVideo: verto.options.useVideo,
|
||||||
useStereo: verto.options.useStereo,
|
useStereo: verto.options.useStereo,
|
||||||
@ -1888,12 +1902,12 @@
|
|||||||
useCamera: verto.options.deviceParams.useCamera,
|
useCamera: verto.options.deviceParams.useCamera,
|
||||||
useMic: verto.options.deviceParams.useMic,
|
useMic: verto.options.deviceParams.useMic,
|
||||||
useSpeak: verto.options.deviceParams.useSpeak,
|
useSpeak: verto.options.deviceParams.useSpeak,
|
||||||
tag: verto.options.tag,
|
tag: tag,
|
||||||
localTag: verto.options.localTag,
|
localTag: verto.options.localTag,
|
||||||
login: verto.options.login,
|
login: verto.options.login,
|
||||||
videoParams: verto.options.videoParams
|
videoParams: verto.options.videoParams
|
||||||
}, params);
|
}, params);
|
||||||
|
|
||||||
dialog.verto = verto;
|
dialog.verto = verto;
|
||||||
dialog.direction = direction;
|
dialog.direction = direction;
|
||||||
dialog.lastState = null;
|
dialog.lastState = null;
|
||||||
@ -1905,13 +1919,13 @@
|
|||||||
dialog.useCamera = dialog.params.useCamera;
|
dialog.useCamera = dialog.params.useCamera;
|
||||||
dialog.useMic = dialog.params.useMic;
|
dialog.useMic = dialog.params.useMic;
|
||||||
dialog.useSpeak = dialog.params.useSpeak;
|
dialog.useSpeak = dialog.params.useSpeak;
|
||||||
|
|
||||||
if (dialog.params.callID) {
|
if (dialog.params.callID) {
|
||||||
dialog.callID = dialog.params.callID;
|
dialog.callID = dialog.params.callID;
|
||||||
} else {
|
} else {
|
||||||
dialog.callID = dialog.params.callID = generateGUID();
|
dialog.callID = dialog.params.callID = generateGUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dialog.params.tag) {
|
if (dialog.params.tag) {
|
||||||
dialog.audioStream = document.getElementById(dialog.params.tag);
|
dialog.audioStream = document.getElementById(dialog.params.tag);
|
||||||
|
|
||||||
@ -1973,7 +1987,7 @@
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
dialog.setState($.verto.enum.state.requesting);
|
dialog.setState($.verto.enum.state.requesting);
|
||||||
|
|
||||||
dialog.sendMethod("verto.invite", {
|
dialog.sendMethod("verto.invite", {
|
||||||
sdp: rtc.mediaData.SDP
|
sdp: rtc.mediaData.SDP
|
||||||
});
|
});
|
||||||
@ -2070,7 +2084,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Attach audio output device to video element using device/sink ID.
|
// Attach audio output device to video element using device/sink ID.
|
||||||
function find_name(id) {
|
function find_name(id) {
|
||||||
for (var i in $.verto.audioOutDevices) {
|
for (var i in $.verto.audioOutDevices) {
|
||||||
var source = $.verto.audioOutDevices[i];
|
var source = $.verto.audioOutDevices[i];
|
||||||
@ -2154,7 +2168,7 @@
|
|||||||
var speaker = dialog.useSpeak;
|
var speaker = dialog.useSpeak;
|
||||||
console.info("Using Speaker: ", speaker);
|
console.info("Using Speaker: ", speaker);
|
||||||
|
|
||||||
if (speaker && speaker !== "any") {
|
if (speaker && speaker !== "any" && speaker !== "none") {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
dialog.setAudioPlaybackDevice(speaker);
|
dialog.setAudioPlaybackDevice(speaker);
|
||||||
}, 500);
|
}, 500);
|
||||||
@ -2181,6 +2195,11 @@
|
|||||||
dialog.setState($.verto.enum.state.destroy);
|
dialog.setState($.verto.enum.state.destroy);
|
||||||
break;
|
break;
|
||||||
case $.verto.enum.state.destroy:
|
case $.verto.enum.state.destroy:
|
||||||
|
|
||||||
|
if (typeof(dialog.verto.options.tag) === "function") {
|
||||||
|
$('#' + dialog.params.tag).remove();
|
||||||
|
}
|
||||||
|
|
||||||
delete dialog.verto.dialogs[dialog.callID];
|
delete dialog.verto.dialogs[dialog.callID];
|
||||||
if (dialog.params.screenShare) {
|
if (dialog.params.screenShare) {
|
||||||
dialog.rtc.stopPeer();
|
dialog.rtc.stopPeer();
|
||||||
@ -2314,7 +2333,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
$.verto.dialog.prototype.getMute = function() {
|
$.verto.dialog.prototype.getMute = function() {
|
||||||
var dialog = this;
|
var dialog = this;
|
||||||
return dialog.rtc.getMute();
|
return dialog.rtc.getMute();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2324,7 +2343,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
$.verto.dialog.prototype.getVideoMute = function() {
|
$.verto.dialog.prototype.getVideoMute = function() {
|
||||||
var dialog = this;
|
var dialog = this;
|
||||||
return dialog.rtc.getVideoMute();
|
return dialog.rtc.getVideoMute();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2411,7 +2430,7 @@
|
|||||||
|
|
||||||
$.verto.dialog.prototype.answer = function(params) {
|
$.verto.dialog.prototype.answer = function(params) {
|
||||||
var dialog = this;
|
var dialog = this;
|
||||||
|
|
||||||
if (!dialog.answered) {
|
if (!dialog.answered) {
|
||||||
if (!params) {
|
if (!params) {
|
||||||
params = {};
|
params = {};
|
||||||
@ -2438,7 +2457,7 @@
|
|||||||
dialog.useSpeak = params.useSpeak;
|
dialog.useSpeak = params.useSpeak;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.rtc.createAnswer(params);
|
dialog.rtc.createAnswer(params);
|
||||||
dialog.answered = true;
|
dialog.answered = true;
|
||||||
}
|
}
|
||||||
@ -2605,7 +2624,7 @@
|
|||||||
$.verto.enum = Object.freeze($.verto.enum);
|
$.verto.enum = Object.freeze($.verto.enum);
|
||||||
|
|
||||||
$.verto.saved = [];
|
$.verto.saved = [];
|
||||||
|
|
||||||
$.verto.unloadJobs = [];
|
$.verto.unloadJobs = [];
|
||||||
|
|
||||||
$(window).bind('beforeunload', function() {
|
$(window).bind('beforeunload', function() {
|
||||||
@ -2630,7 +2649,7 @@
|
|||||||
|
|
||||||
var checkDevices = function(runtime) {
|
var checkDevices = function(runtime) {
|
||||||
console.info("enumerating devices");
|
console.info("enumerating devices");
|
||||||
var aud_in = [], aud_out = [], vid = [];
|
var aud_in = [], aud_out = [], vid = [];
|
||||||
|
|
||||||
if ((!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) && MediaStreamTrack.getSources) {
|
if ((!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) && MediaStreamTrack.getSources) {
|
||||||
MediaStreamTrack.getSources(function (media_sources) {
|
MediaStreamTrack.getSources(function (media_sources) {
|
||||||
@ -2642,17 +2661,17 @@
|
|||||||
aud_in.push(media_sources[i]);
|
aud_in.push(media_sources[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$.verto.videoDevices = vid;
|
$.verto.videoDevices = vid;
|
||||||
$.verto.audioInDevices = aud_in;
|
$.verto.audioInDevices = aud_in;
|
||||||
|
|
||||||
console.info("Audio Devices", $.verto.audioInDevices);
|
console.info("Audio Devices", $.verto.audioInDevices);
|
||||||
console.info("Video Devices", $.verto.videoDevices);
|
console.info("Video Devices", $.verto.videoDevices);
|
||||||
runtime(true);
|
runtime(true);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
/* of course it's a totally different API CALL with different element names for the same exact thing */
|
/* of course it's a totally different API CALL with different element names for the same exact thing */
|
||||||
|
|
||||||
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
|
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
|
||||||
console.log("enumerateDevices() not supported.");
|
console.log("enumerateDevices() not supported.");
|
||||||
return;
|
return;
|
||||||
@ -2667,7 +2686,7 @@
|
|||||||
|
|
||||||
console.log(device.kind + ": " + device.label +
|
console.log(device.kind + ": " + device.label +
|
||||||
" id = " + device.deviceId);
|
" id = " + device.deviceId);
|
||||||
|
|
||||||
if (device.kind === "videoinput") {
|
if (device.kind === "videoinput") {
|
||||||
vid.push({id: device.deviceId, kind: "video", label: device.label});
|
vid.push({id: device.deviceId, kind: "video", label: device.label});
|
||||||
} else if (device.kind === "audioinput") {
|
} else if (device.kind === "audioinput") {
|
||||||
@ -2676,17 +2695,17 @@
|
|||||||
aud_out.push({id: device.deviceId, kind: "audio_out", label: device.label});
|
aud_out.push({id: device.deviceId, kind: "audio_out", label: device.label});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$.verto.videoDevices = vid;
|
$.verto.videoDevices = vid;
|
||||||
$.verto.audioInDevices = aud_in;
|
$.verto.audioInDevices = aud_in;
|
||||||
$.verto.audioOutDevices = aud_out;
|
$.verto.audioOutDevices = aud_out;
|
||||||
|
|
||||||
console.info("Audio IN Devices", $.verto.audioInDevices);
|
console.info("Audio IN Devices", $.verto.audioInDevices);
|
||||||
console.info("Audio Out Devices", $.verto.audioOutDevices);
|
console.info("Audio Out Devices", $.verto.audioOutDevices);
|
||||||
console.info("Video Devices", $.verto.videoDevices);
|
console.info("Video Devices", $.verto.videoDevices);
|
||||||
runtime(true);
|
runtime(true);
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
console.log(" Device Enumeration ERROR: " + err.name + ": " + err.message);
|
console.log(" Device Enumeration ERROR: " + err.name + ": " + err.message);
|
||||||
|
@ -1,14 +1,76 @@
|
|||||||
var callback = function(message){console.log(message);}; // holds the user's callback for a global scope
|
Verto = function (
|
||||||
callbacks = {};
|
tag,
|
||||||
var callICEConnected = false;
|
voiceBridge,
|
||||||
var callPurposefullyEnded = false; // used to determine whether the user ended the call or the call was ended from somewhere else outside
|
conferenceUsername,
|
||||||
var callTimeout = null; // function that will run if there is no call established
|
userCallback,
|
||||||
var toDisplayDisconnectCallback = true; // if a call is dropped only display the error the first time
|
onFail = null,
|
||||||
var wasCallSuccessful = false; // when the websocket connection is closed this determines whether a call was ever successfully established
|
chromeExtension = null) {
|
||||||
webcamStream = "webcamStream";
|
|
||||||
window[webcamStream] = null;
|
voiceBridge += "-DESKSHARE";
|
||||||
verto = null;
|
this.cur_call = null;
|
||||||
videoTag = null;
|
this.share_call = null;
|
||||||
|
this.vertoHandle;
|
||||||
|
|
||||||
|
this.vid_width = 1920;
|
||||||
|
this.vid_height = 1080;
|
||||||
|
|
||||||
|
this.local_vid_width = 320;
|
||||||
|
this.local_vid_height = 180;
|
||||||
|
this.outgoingBandwidth;
|
||||||
|
this.incomingBandwidth;
|
||||||
|
this.sessid = null;
|
||||||
|
|
||||||
|
this.renderTag = 'remote-media';
|
||||||
|
|
||||||
|
this.destination_number = voiceBridge;
|
||||||
|
this.caller_id_name = conferenceUsername;
|
||||||
|
this.caller_id_number = conferenceIdNumber;
|
||||||
|
|
||||||
|
this.vertoPort = "8082";
|
||||||
|
this.hostName = window.location.hostname;
|
||||||
|
this.socketUrl = 'wss://' + this.hostName + ':' + this.vertoPort;
|
||||||
|
this.login = "bbbuser";
|
||||||
|
this.password = "secret";
|
||||||
|
this.minWidth = '640';
|
||||||
|
this.minHeight = '480';
|
||||||
|
this.maxWidth = '1920';
|
||||||
|
this.maxHeight = '1080';
|
||||||
|
|
||||||
|
this.useVideo = false;
|
||||||
|
this.useCamera = false;
|
||||||
|
this.useMic = false;
|
||||||
|
|
||||||
|
this.callWasSuccessful = false;
|
||||||
|
|
||||||
|
this.iceServers = null;
|
||||||
|
|
||||||
|
this.userCallback = userCallback;
|
||||||
|
|
||||||
|
if (chromeExtension != null) {
|
||||||
|
this.chromeExtension = chromeExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onFail != null) {
|
||||||
|
this.onFail = Verto.normalizeCallback(onFail);
|
||||||
|
} else {
|
||||||
|
var _this = this;
|
||||||
|
this.onFail = function () {
|
||||||
|
_this.logError('Default error handler');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.logger = function (obj) {
|
||||||
|
console.log(obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.logError = function (obj) {
|
||||||
|
console.error(obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.setRenderTag = function (tag) {
|
||||||
|
this.renderTag = tag;
|
||||||
|
};
|
||||||
|
|
||||||
// receives either a string variable holding the name of an actionscript
|
// receives either a string variable holding the name of an actionscript
|
||||||
// registered callback, or a javascript function object.
|
// registered callback, or a javascript function object.
|
||||||
@ -16,388 +78,432 @@ videoTag = null;
|
|||||||
// or if it is an actionscript string it will return a javascript Function
|
// or if it is an actionscript string it will return a javascript Function
|
||||||
// that when invokved will invoke the actionscript registered callback
|
// that when invokved will invoke the actionscript registered callback
|
||||||
// and passes along parameters
|
// and passes along parameters
|
||||||
function normalizeCallback(callback) {
|
Verto.normalizeCallback = function (callback) {
|
||||||
if (typeof callback == "function") {
|
if (typeof callback == 'function') {
|
||||||
return callback;
|
return callback;
|
||||||
} else {
|
} else {
|
||||||
return function(args) {
|
return function (args) {
|
||||||
document.getElementById("BigBlueButton")[callback](args);
|
document.getElementById('BigBlueButton')[callback](args);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// save a copy of the hangup function registered for the verto object
|
Verto.prototype.onWSLogin = function (v, success) {
|
||||||
var oldHangup = $.verto.prototype.hangup;
|
this.cur_call = null;
|
||||||
// overwrite the verto hangup handler with my own handler
|
if (success) {
|
||||||
$.verto.prototype.hangup = function(callID, userCallback) {
|
this.callWasSuccessful = true;
|
||||||
console.log("call state callbacks - bye");
|
this.mediaCallback();
|
||||||
if (userCallback) {
|
return;
|
||||||
callback = userCallback;
|
} else {
|
||||||
}
|
// error logging verto into freeswitch
|
||||||
callActive = false;
|
this.logError({ status: 'failed', errorcode: '10XX' });
|
||||||
|
this.callWasSuccessful = false;
|
||||||
|
this.onFail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (cur_call) {
|
Verto.prototype.registerCallbacks = function () {
|
||||||
console.log('call ended ' + cur_call.audioStream.currentTime); // the duration of the call
|
var callbacks = {
|
||||||
if (callPurposefullyEnded === true) { // the user ended the call themself
|
onMessage: function () {},
|
||||||
callback({'status':'ended'});
|
|
||||||
} else {
|
|
||||||
callback({'status':'failed', 'errorcode': 1005}); // Call ended unexpectedly
|
|
||||||
}
|
|
||||||
clearTimeout(callTimeout);
|
|
||||||
cur_call = null;
|
|
||||||
} else {
|
|
||||||
console.log('bye event already received');
|
|
||||||
}
|
|
||||||
// call the original hangup procedure
|
|
||||||
return oldHangup.apply(this, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
// main entry point to making a verto call
|
onDialogState: function (d) {},
|
||||||
callIntoConference_verto = function(voiceBridge, conferenceUsername, conferenceIdNumber, userCallback, videoTag, options, vertoServerCredentials) {
|
|
||||||
window.videoTag = videoTag;
|
|
||||||
// stores the user's callback in the global scope
|
|
||||||
if (userCallback) {
|
|
||||||
callback = userCallback;
|
|
||||||
}
|
|
||||||
if(!isLoggedIntoVerto()) { // start the verto log in procedure
|
|
||||||
// runs when a web socket is disconnected
|
|
||||||
callbacks.onWSClose = function(v, success) {
|
|
||||||
if(wasCallSuccessful) { // a call was established through the websocket
|
|
||||||
if(toDisplayDisconnectCallback) { // will only display the error the first time
|
|
||||||
// the connection was dropped in an already established call
|
|
||||||
console.log("websocket disconnected");
|
|
||||||
callback({'status':'failed', 'errorcode': 1001}); // WebSocket disconnected
|
|
||||||
toDisplayDisconnectCallback = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// this callback was triggered and a call was never successfully established
|
|
||||||
console.log("websocket connection could not be established");
|
|
||||||
callback({'status':'failed', 'errorcode': 1002}); // Could not make a WebSocket connection
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// runs when the websocket is successfully created
|
|
||||||
callbacks.onWSLogin = function(v, success) {
|
|
||||||
cur_call = null;
|
|
||||||
ringing = false;
|
|
||||||
console.log("Inside onWSLogin");
|
|
||||||
|
|
||||||
if (success) {
|
onWSLogin: this.onWSLogin.bind(this),
|
||||||
console.log("starting call");
|
|
||||||
toDisplayDisconnectCallback = true; // yes, display an error if the socket closes
|
|
||||||
wasCallSuccessful = true; // yes, a call was successfully established through the websocket
|
|
||||||
webrtc_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, callback, options);
|
|
||||||
} else {
|
|
||||||
callback({'status':'failed', 'errorcode': '10XX'}); // eror logging verto into freeswitch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set up verto
|
|
||||||
// $.verto.init({}, init(videoTag));
|
|
||||||
init(videoTag, vertoServerCredentials);
|
|
||||||
} else {
|
|
||||||
console.log("already logged into verto, going straight to making a call");
|
|
||||||
webrtc_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, callback, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkSupport = function(callback) {
|
onWSClose: function (v, success) {
|
||||||
if(!isWebRTCAvailable_verto()) {
|
cur_call = null;
|
||||||
callback({'status': 'failed', 'errorcode': 1003}); // Browser version not supported
|
if (this.callWasSuccessful) {
|
||||||
}
|
// the connection was dropped in an already established call
|
||||||
|
this.logError('websocket disconnected');
|
||||||
|
|
||||||
if (!navigator.getUserMedia) {
|
// WebSocket disconnected
|
||||||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
this.logError({ status: 'failed', errorcode: 1001 });
|
||||||
}
|
toDisplayDisconnectCallback = false;
|
||||||
|
} else {
|
||||||
|
// this callback was triggered and a call was never successfully established
|
||||||
|
this.logError('websocket connection could not be established');
|
||||||
|
|
||||||
if (!navigator.getUserMedia){
|
// Could not make a WebSocket connection
|
||||||
callback({'status': 'failed', 'errorcode': '10XX'}); // getUserMedia not supported in this browser
|
this.logError({ status: 'failed', errorcode: 1002 });
|
||||||
}
|
this.onFail();
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
}.bind(this),
|
||||||
|
};
|
||||||
|
this.callbacks = callbacks;
|
||||||
|
};
|
||||||
|
|
||||||
configStuns = function(callbacks, callback, videoTag, vertoServerCredentials) {
|
Verto.prototype.hold = function () {
|
||||||
console.log("Fetching STUN/TURN server info for Verto initialization");
|
this.cur_call.toggleHold();
|
||||||
var stunsConfig = {};
|
};
|
||||||
$.ajax({
|
|
||||||
dataType: 'json',
|
|
||||||
url: '/bigbluebutton/api/stuns/'
|
|
||||||
}).done(function(data) {
|
|
||||||
console.log("ajax request done");
|
|
||||||
console.log(data);
|
|
||||||
if(data['response'] && data.response.returncode == "FAILED") {
|
|
||||||
console.error(data.response.message);
|
|
||||||
callback({'status':'failed', 'errorcode': data.response.message});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
stunsConfig['stunServers'] = ( data['stunServers'] ? data['stunServers'].map(function(data) {
|
|
||||||
return {'url': data['url']};
|
|
||||||
}) : [] );
|
|
||||||
stunsConfig['turnServers'] = ( data['turnServers'] ? data['turnServers'].map(function(data) {
|
|
||||||
return {
|
|
||||||
'urls': data['url'],
|
|
||||||
'username': data['username'],
|
|
||||||
'credential': data['password']
|
|
||||||
};
|
|
||||||
}) : [] );
|
|
||||||
stunsConfig = stunsConfig['stunServers'].concat(stunsConfig['turnServers']);
|
|
||||||
console.log("success got stun data, making verto");
|
|
||||||
makeVerto(callbacks, stunsConfig, videoTag, vertoServerCredentials);
|
|
||||||
}).fail(function(data, textStatus, errorThrown) {
|
|
||||||
// BBBLog.error("Could not fetch stun/turn servers", {error: textStatus, user: callerIdName, voiceBridge: conferenceVoiceBridge});
|
|
||||||
callback({'status':'failed', 'errorcode': 1009});
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
docall_verto = function(extension, conferenceUsername, conferenceIdNumber, callbacks, options) {
|
Verto.prototype.hangup = function () {
|
||||||
console.log(extension + ", " + conferenceUsername + ", " + conferenceIdNumber);
|
if (this.cur_call) {
|
||||||
|
// the duration of the call
|
||||||
|
this.logger('call ended ' + this.cur_call.audioStream.currentTime);
|
||||||
|
this.cur_call.hangup();
|
||||||
|
this.cur_call = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (cur_call) { // only allow for one call
|
if (this.share_call) {
|
||||||
console.log("Quitting: Call already in progress");
|
// the duration of the call
|
||||||
return;
|
this.logger('call ended ' + this.share_call.audioStream.currentTime);
|
||||||
}
|
this.share_call.hangup();
|
||||||
// determine the resolution the user chose for webcam video
|
this.share_call = null;
|
||||||
outgoingBandwidth = "default";
|
}
|
||||||
incomingBandwidth = "default";
|
|
||||||
var useVideo = useCamera = useMic = false;
|
|
||||||
// debugger;
|
|
||||||
if(options.watchOnly) {
|
|
||||||
window.watchOnly = true;
|
|
||||||
window.listenOnly = false;
|
|
||||||
window.joinAudio = false;
|
|
||||||
useVideo = true;
|
|
||||||
useCamera = false;
|
|
||||||
useMic = false;
|
|
||||||
} else if(options.listenOnly) {
|
|
||||||
window.listenOnly = true;
|
|
||||||
window.watchOnly = false;
|
|
||||||
window.joinAudio = false;
|
|
||||||
useVideo = false;
|
|
||||||
useCamera = false;
|
|
||||||
useMic = false;
|
|
||||||
} else if(options.joinAudio) {
|
|
||||||
window.joinAudio = true;
|
|
||||||
window.watchOnly = false;
|
|
||||||
window.listenOnly = false;
|
|
||||||
useVideo = false;
|
|
||||||
useCamera = false;
|
|
||||||
useMic = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_call = verto.newCall({
|
// the user ended the call themself
|
||||||
destination_number: extension,
|
// if (callPurposefullyEnded === true) {
|
||||||
caller_id_name: conferenceUsername,
|
if (true) {
|
||||||
caller_id_number: conferenceIdNumber,
|
this.logger({ status: 'ended' });
|
||||||
outgoingBandwidth: outgoingBandwidth,
|
} else {
|
||||||
incomingBandwidth: incomingBandwidth,
|
// Call ended unexpectedly
|
||||||
useStereo: true,
|
this.logError({ status: 'failed', errorcode: 1005 });
|
||||||
useVideo: useVideo,
|
}
|
||||||
useCamera: useCamera,
|
};
|
||||||
useMic: useMic,
|
|
||||||
dedEnc: false,
|
|
||||||
mirrorInput: false
|
|
||||||
});
|
|
||||||
|
|
||||||
if (callbacks != null) { // add user supplied callbacks to the current call
|
Verto.prototype.mute = function () {
|
||||||
cur_call.rtc.options.callbacks = $.extend(cur_call.rtc.options.callbacks, callbacks);
|
this.cur_call.dtmf('0');
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// check if logged into verto by seeing if there is a ready websocket connection
|
Verto.prototype.localmute = function () {
|
||||||
function isLoggedIntoVerto() {
|
// var muted = cur_call.setMute('toggle');
|
||||||
return (verto != null ? (ref = verto.rpcClient) != null ? ref.socketReady() : void 0 : void 0);
|
// if (muted) {
|
||||||
}
|
// display('Talking to: ' + cur_call.cidString() + ' [LOCALLY MUTED]');
|
||||||
|
// } else {
|
||||||
|
// display('Talking to: ' + cur_call.cidString());
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
// overwrite and substitute my own init function
|
Verto.prototype.localvidmute = function () {
|
||||||
init = function(videoTag, vertoServerCredentials) {
|
// var muted = cur_call.setVideoMute('toggle');
|
||||||
videoTag = window.videoTag;
|
// if (muted) {
|
||||||
cur_call = null;
|
// display('Talking to: ' + cur_call.cidString() + ' [VIDEO LOCALLY MUTED]');
|
||||||
share_call = null;
|
// } else {
|
||||||
incomingBandwidth = "default";
|
// display('Talking to: ' + cur_call.cidString());
|
||||||
configStuns(callbacks, callback, videoTag, vertoServerCredentials);
|
// }
|
||||||
}
|
};
|
||||||
|
|
||||||
|
Verto.prototype.vmute = function () {
|
||||||
|
this.cur_call.dtmf('*0');
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.setWatchVideo = function (tag) {
|
||||||
|
this.mediaCallback = this.docall;
|
||||||
|
this.useVideo = true;
|
||||||
|
this.useCamera = 'none';
|
||||||
|
this.useMic = 'none';
|
||||||
|
this.create(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.setListenOnly = function (tag) {
|
||||||
|
this.mediaCallback = this.docall;
|
||||||
|
this.useVideo = false;
|
||||||
|
this.useCamera = 'none';
|
||||||
|
this.useMic = 'none';
|
||||||
|
this.create(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.setMicrophone = function (tag) {
|
||||||
|
this.mediaCallback = this.docall;
|
||||||
|
this.useVideo = false;
|
||||||
|
this.useCamera = 'none';
|
||||||
|
this.useMic = 'any';
|
||||||
|
this.create(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.setScreenShare = function (tag) {
|
||||||
|
this.mediaCallback = this.makeShare;
|
||||||
|
this.create(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.create = function (tag) {
|
||||||
|
this.setRenderTag(tag);
|
||||||
|
this.registerCallbacks();
|
||||||
|
this.configStuns(this.init);
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.docall = function () {
|
||||||
|
if (this.cur_call) {
|
||||||
|
this.logger('Quitting: Call already in progress');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cur_call = window.vertoHandle.newCall({
|
||||||
|
destination_number: this.destination_number,
|
||||||
|
caller_id_name: this.caller_id_name,
|
||||||
|
caller_id_number: this.caller_id_number,
|
||||||
|
outgoingBandwidth: this.outgoingBandwidth,
|
||||||
|
incomingBandwidth: this.incomingBandwidth,
|
||||||
|
useVideo: this.useVideo,
|
||||||
|
useStereo: true,
|
||||||
|
useCamera: this.useCamera,
|
||||||
|
useMic: this.useMic,
|
||||||
|
useSpeak: 'any',
|
||||||
|
dedEnc: true,
|
||||||
|
tag: this.renderTag,
|
||||||
|
});
|
||||||
|
this.logger(this.cur_call);
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.makeShare = function () {
|
||||||
|
if (this.share_call) {
|
||||||
|
this.logError('Quitting: Call already in progress');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var screenInfo = null;
|
||||||
|
if (!!navigator.mozGetUserMedia) {
|
||||||
|
screenInfo = {
|
||||||
|
video: {
|
||||||
|
mozMediaSource: 'window',
|
||||||
|
mediaSource: 'window',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.doShare(screenInfo.video);
|
||||||
|
} else if (!!window.chrome) {
|
||||||
|
var _this = this;
|
||||||
|
if (!_this.chromeExtension) {
|
||||||
|
_this.logError({
|
||||||
|
status: 'failed',
|
||||||
|
message: 'Missing Chrome Extension key',
|
||||||
|
});
|
||||||
|
_this.onFail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getChromeExtensionStatus(this.chromeExtension, function (status) {
|
||||||
|
if (status != 'installed-enabled') {
|
||||||
|
_this.logError('No chrome Extension');
|
||||||
|
_this.onFail();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bring up Chrome screen picker
|
||||||
|
getScreenConstraints(function (error, screenConstraints) {
|
||||||
|
if (error) {
|
||||||
|
_this.onFail();
|
||||||
|
return _this.logError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
screenInfo = screenConstraints.mandatory;
|
||||||
|
|
||||||
|
_this.logger(screenInfo);
|
||||||
|
_this.doShare(screenInfo);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.doShare = function (screenConstraints) {
|
||||||
|
this.share_call = window.vertoHandle.newCall({
|
||||||
|
destination_number: this.destination_number,
|
||||||
|
caller_id_name: this.caller_id_name,
|
||||||
|
caller_id_number: this.caller_id_number,
|
||||||
|
outgoingBandwidth: this.outgoingBandwidth,
|
||||||
|
incomingBandwidth: this.incomingBandwidth,
|
||||||
|
videoParams: screenConstraints,
|
||||||
|
useVideo: true,
|
||||||
|
screenShare: true,
|
||||||
|
dedEnc: true,
|
||||||
|
mirrorInput: false,
|
||||||
|
tag: this.renderTag,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.init = function () {
|
||||||
|
this.cur_call = null;
|
||||||
|
|
||||||
|
if (!window.vertoHandle) {
|
||||||
|
window.vertoHandle = new $.verto({
|
||||||
|
login: this.login,
|
||||||
|
passwd: this.password,
|
||||||
|
socketUrl: this.socketUrl,
|
||||||
|
tag: this.renderTag,
|
||||||
|
ringFile: 'sounds/bell_ring2.wav',
|
||||||
|
sessid: this.sessid,
|
||||||
|
videoParams: {
|
||||||
|
minWidth: this.vid_width,
|
||||||
|
minHeight: this.vid_height,
|
||||||
|
maxWidth: this.vid_width,
|
||||||
|
maxHeight: this.vid_height,
|
||||||
|
minFrameRate: 15,
|
||||||
|
vertoBestFrameRate: 30,
|
||||||
|
},
|
||||||
|
|
||||||
|
deviceParams: {
|
||||||
|
useCamera: false,
|
||||||
|
useMic: false,
|
||||||
|
useSpeak: 'none',
|
||||||
|
},
|
||||||
|
|
||||||
|
audioParams: {
|
||||||
|
googAutoGainControl: false,
|
||||||
|
googNoiseSuppression: false,
|
||||||
|
googHighpassFilter: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
iceServers: this.iceServers,
|
||||||
|
}, this.callbacks);
|
||||||
|
} else {
|
||||||
|
this.mediaCallback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Verto.prototype.configStuns = function (callback) {
|
||||||
|
this.logger('Fetching STUN/TURN server info for Verto initialization');
|
||||||
|
var _this = this;
|
||||||
|
var stunsConfig = {};
|
||||||
|
$.ajax({
|
||||||
|
dataType: 'json',
|
||||||
|
url: '/bigbluebutton/api/stuns/',
|
||||||
|
}).done(function (data) {
|
||||||
|
_this.logger('ajax request done');
|
||||||
|
_this.logger(data);
|
||||||
|
if (data.response && data.response.returncode == 'FAILED') {
|
||||||
|
_this.logError(data.response.message, { error: true });
|
||||||
|
_this.logError({ status: 'failed', errorcode: data.response.message });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stunsConfig.stunServers = (data.stunServers ? data.stunServers.map(function (data) {
|
||||||
|
return { url: data.url };
|
||||||
|
}) : []);
|
||||||
|
|
||||||
|
stunsConfig.turnServers = (data.turnServers ? data.turnServers.map(function (data) {
|
||||||
|
return {
|
||||||
|
urls: data.url,
|
||||||
|
username: data.username,
|
||||||
|
credential: data.password,
|
||||||
|
};
|
||||||
|
}) : []);
|
||||||
|
|
||||||
|
stunsConfig = stunsConfig.stunServers.concat(stunsConfig.turnServers);
|
||||||
|
_this.logger('success got stun data, making verto');
|
||||||
|
_this.iceServers = stunsConfig;
|
||||||
|
callback.apply(_this);
|
||||||
|
}).fail(function (data, textStatus, errorThrown) {
|
||||||
|
_this.logError({ status: 'failed', errorcode: 1009 });
|
||||||
|
_this.onFail();
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// checks whether Google Chrome or Firefox have the WebRTCPeerConnection object
|
// checks whether Google Chrome or Firefox have the WebRTCPeerConnection object
|
||||||
function isWebRTCAvailable_verto() {
|
Verto.prototype.isWebRTCAvailable = function () {
|
||||||
return (typeof window.webkitRTCPeerConnection !== 'undefined' || typeof window.mozRTCPeerConnection !== 'undefined');
|
return (typeof window.webkitRTCPeerConnection !== 'undefined' ||
|
||||||
}
|
typeof window.mozRTCPeerConnection !== 'undefined');
|
||||||
|
|
||||||
// exit point for conference
|
|
||||||
function leaveWebRTCVoiceConference_verto() {
|
|
||||||
console.log("Leaving the voice conference");
|
|
||||||
webrtc_hangup_verto();
|
|
||||||
}
|
|
||||||
|
|
||||||
function make_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, userCallback, server, recall, options) {
|
|
||||||
if (userCallback) {
|
|
||||||
callback = userCallback;
|
|
||||||
}
|
|
||||||
callPurposefullyEnded = false;
|
|
||||||
|
|
||||||
// after 15 seconds if a call hasn't been established display error, hangup and logout of verto
|
|
||||||
callTimeout = setTimeout(function() {
|
|
||||||
console.log('Ten seconds without updates sending timeout code');
|
|
||||||
callback({'status':'failed', 'errorcode': 1006}); // Failure on call
|
|
||||||
if (verto != null) {
|
|
||||||
verto.hangup();
|
|
||||||
verto.logout();
|
|
||||||
verto = null;
|
|
||||||
}
|
|
||||||
cur_call = null;
|
|
||||||
}, 10000*1.5);
|
|
||||||
|
|
||||||
var myRTCCallbacks = {
|
|
||||||
onError: function(vertoErrorObject, errorMessage) {
|
|
||||||
console.error("custom callback: onError");
|
|
||||||
console.error(vertoErrorObject);
|
|
||||||
console.error("ERROR:");
|
|
||||||
console.error(errorMessage);
|
|
||||||
if(errorMessage.name === "PermissionDeniedError") { // user denied access to media peripherals
|
|
||||||
console.error("User denied permission/access to hardware");
|
|
||||||
console.error("getUserMedia: failure - ", errorMessage);
|
|
||||||
callback({'status': 'mediafail', 'cause': errorMessage});
|
|
||||||
}
|
|
||||||
cur_call.hangup({cause: "Device or Permission Error"});
|
|
||||||
clearTimeout(callTimeout);
|
|
||||||
},
|
|
||||||
onICEComplete: function(self, candidate) { // ICE candidate negotiation is complete
|
|
||||||
console.log("custom callback: onICEComplete");
|
|
||||||
console.log('Received ICE status changed to completed');
|
|
||||||
if (callICEConnected === false) {
|
|
||||||
callICEConnected = true;
|
|
||||||
if (callActive === true) {
|
|
||||||
callback({'status':'started'});
|
|
||||||
}
|
|
||||||
clearTimeout(callTimeout);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onStream: function(rtc, stream) { // call has been established
|
|
||||||
console.log("getUserMicMedia: success");
|
|
||||||
callback({'status':'mediasuccess'});
|
|
||||||
console.log("custom callback: stream started");
|
|
||||||
callActive = true;
|
|
||||||
console.log('BigBlueButton call accepted');
|
|
||||||
|
|
||||||
if (callICEConnected === true) {
|
|
||||||
callback({'status':'started'});
|
|
||||||
} else {
|
|
||||||
callback({'status':'waitingforice'});
|
|
||||||
}
|
|
||||||
clearTimeout(callTimeout);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if(isLoggedIntoVerto()) {
|
|
||||||
console.log("Verto is logged into FreeSWITCH, socket is available, making call");
|
|
||||||
callICEConnected = false;
|
|
||||||
|
|
||||||
docall_verto(voiceBridge, conferenceUsername, conferenceIdNumber, myRTCCallbacks, options);
|
|
||||||
|
|
||||||
if(recall === false) {
|
|
||||||
console.log('call connecting');
|
|
||||||
callback({'status': 'connecting'});
|
|
||||||
} else {
|
|
||||||
console.log('call connecting again');
|
|
||||||
}
|
|
||||||
|
|
||||||
callback({'status':'mediarequest'});
|
|
||||||
} else {
|
|
||||||
console.error("Verto is NOT logged into FreeSWITCH, socket is NOT available, abandoning call request");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeVerto(callbacks, stunsConfig, videoTag, vertoServerCredentials) {
|
|
||||||
var vertoPort = vertoServerCredentials.vertoPort;
|
|
||||||
var hostName = vertoServerCredentials.hostName;
|
|
||||||
var socketUrl = "wss://" + hostName + ":" + vertoPort;
|
|
||||||
var login = vertoServerCredentials.login;
|
|
||||||
var password = vertoServerCredentials.password;
|
|
||||||
var minWidth = "640";
|
|
||||||
var minHeight = "480";
|
|
||||||
var maxWidth = "1920";
|
|
||||||
var maxHeight = "1080";
|
|
||||||
|
|
||||||
console.log("stuns info is");
|
|
||||||
console.log(stunsConfig);
|
|
||||||
// debugger;
|
|
||||||
verto = new $.verto({
|
|
||||||
login: login,
|
|
||||||
passwd: password,
|
|
||||||
socketUrl: socketUrl,
|
|
||||||
tag: videoTag,
|
|
||||||
ringFile: "sounds/bell_ring2.wav",
|
|
||||||
loginParams: {foo: true, bar: "yes"},
|
|
||||||
useVideo: false,
|
|
||||||
useCamera: false,
|
|
||||||
iceServers: stunsConfig, // use user supplied stun configuration
|
|
||||||
// iceServers: true, // use stun, use default verto configuration
|
|
||||||
}, callbacks);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets verto to begin using the resolution that the user selected
|
|
||||||
my_check_vid_res = function() {
|
|
||||||
var selectedVideoConstraints = getChosenWebcamResolution();
|
|
||||||
my_real_size(selectedVideoConstraints);
|
|
||||||
|
|
||||||
if (verto) {
|
|
||||||
verto.videoParams({
|
|
||||||
"minWidth": selectedVideoConstraints.constraints.minWidth,
|
|
||||||
"minHeight": selectedVideoConstraints.constraints.minHeight,
|
|
||||||
"maxWidth": selectedVideoConstraints.constraints.maxWidth,
|
|
||||||
"maxHeight": selectedVideoConstraints.constraints.maxHeight,
|
|
||||||
"minFrameRate": selectedVideoConstraints.constraints.minFrameRate,
|
|
||||||
"vertoBestFrameRate": selectedVideoConstraints.constraints.vertoBestFrameRate
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my_real_size = function(selectedVideoConstraints) {
|
|
||||||
$("#" + window.videoTag).height("100%");
|
|
||||||
$("#" + window.videoTag).width("100%");
|
|
||||||
}
|
|
||||||
|
|
||||||
var RTCPeerConnectionCallbacks = {
|
|
||||||
iceFailed: function(e) {
|
|
||||||
console.log('received ice negotiation failed');
|
|
||||||
callback({'status':'failed', 'errorcode': 1007}); // Failure on call
|
|
||||||
//
|
|
||||||
// TODO unless I do this, the call only lasts for a few seconds.
|
|
||||||
// When I comment out the lines below, it works fine indefinitely
|
|
||||||
// Anton Georgiev Dec 10 2015
|
|
||||||
//
|
|
||||||
//cur_call = null;
|
|
||||||
//verto.hangup();
|
|
||||||
//verto = null;
|
|
||||||
//clearTimeout(callTimeout);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
this.RTCPeerConnectionCallbacks = RTCPeerConnectionCallbacks;
|
|
||||||
|
|
||||||
window.verto_afterStreamPublish = function() {}
|
this.VertoManager = function () {
|
||||||
|
this.vertoAudio = null;
|
||||||
|
this.vertoVideo = null;
|
||||||
|
this.vertoScreenShare = null;
|
||||||
|
window.vertoHandle = null;
|
||||||
|
};
|
||||||
|
|
||||||
function webrtc_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, userCallback, options) {
|
Verto.prototype.logout = function () {
|
||||||
if (userCallback) {
|
this.exitAudio();
|
||||||
callback = userCallback;
|
this.exitVideo();
|
||||||
}
|
this.exitScreenShare();
|
||||||
console.log("webrtc_call\n"+voiceBridge + ", " + conferenceUsername + ", " + conferenceIdNumber + ", " + callback);
|
window.vertoHandle.logout();
|
||||||
|
};
|
||||||
|
|
||||||
if(!isWebRTCAvailable()) {
|
VertoManager.prototype.exitAudio = function () {
|
||||||
callback({'status': 'failed', 'errorcode': 1003}); // Browser version not supported
|
if (this.vertoAudio != null) {
|
||||||
return;
|
console.log('Hanging up vertoAudio');
|
||||||
}
|
this.vertoAudio.hangup();
|
||||||
|
this.vertoAudio = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var server = window.document.location.hostname;
|
VertoManager.prototype.exitVideo = function () {
|
||||||
console.log("user " + conferenceUsername + " calling to " + voiceBridge);
|
if (this.vertoVideo != null) {
|
||||||
if (isLoggedIntoVerto()) {
|
console.log('Hanging up vertoVideo');
|
||||||
make_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, callback, "", false, options);
|
this.vertoVideo.hangup();
|
||||||
}
|
this.vertoVideo = null;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function webrtc_hangup_verto(userCallback) {
|
VertoManager.prototype.exitScreenShare = function () {
|
||||||
if (userCallback) {
|
if (this.vertoScreenShare != null) {
|
||||||
callback = userCallback;
|
console.log('Hanging up vertoScreenShare');
|
||||||
}
|
this.vertoScreenShare.hangup();
|
||||||
callPurposefullyEnded = true;
|
this.vertoScreenShare = null;
|
||||||
console.log("Hanging up current session");
|
}
|
||||||
if(verto) {
|
};
|
||||||
verto.hangup(false, callback);
|
|
||||||
}
|
VertoManager.prototype.joinListenOnly = function (tag) {
|
||||||
}
|
this.exitAudio();
|
||||||
|
var obj = Object.create(Verto.prototype);
|
||||||
|
Verto.apply(obj, arguments);
|
||||||
|
this.vertoAudio = obj;
|
||||||
|
this.vertoAudio.setListenOnly(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
VertoManager.prototype.joinMicrophone = function (tag) {
|
||||||
|
this.exitAudio();
|
||||||
|
var obj = Object.create(Verto.prototype);
|
||||||
|
Verto.apply(obj, arguments);
|
||||||
|
this.vertoAudio = obj;
|
||||||
|
this.vertoAudio.setMicrophone(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
VertoManager.prototype.joinWatchVideo = function (tag) {
|
||||||
|
this.exitVideo();
|
||||||
|
var obj = Object.create(Verto.prototype);
|
||||||
|
Verto.apply(obj, arguments);
|
||||||
|
this.vertoVideo = obj;
|
||||||
|
this.vertoVideo.setWatchVideo(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
VertoManager.prototype.shareScreen = function (tag) {
|
||||||
|
this.exitScreenShare();
|
||||||
|
var obj = Object.create(Verto.prototype);
|
||||||
|
Verto.apply(obj, arguments);
|
||||||
|
this.vertoScreenShare = obj;
|
||||||
|
this.vertoScreenShare.setScreenShare(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.vertoInitialize = function () {
|
||||||
|
if (window.vertoManager == null || window.vertoManager == undefined) {
|
||||||
|
window.vertoManager = new VertoManager();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.vertoExitAudio = function () {
|
||||||
|
window.vertoInitialize();
|
||||||
|
window.vertoManager.exitAudio();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.vertoExitScreenShare = function () {
|
||||||
|
window.vertoInitialize();
|
||||||
|
window.vertoManager.exitScreenShare();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.vertoJoinListenOnly = function () {
|
||||||
|
window.vertoInitialize();
|
||||||
|
window.vertoManager.joinListenOnly.apply(window.vertoManager, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.vertoJoinMicrophone = function () {
|
||||||
|
window.vertoInitialize();
|
||||||
|
window.vertoManager.joinMicrophone.apply(window.vertoManager, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.vertoWatchVideo = function () {
|
||||||
|
window.vertoInitialize();
|
||||||
|
window.vertoManager.joinWatchVideo.apply(window.vertoManager, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.vertoShareScreen = function () {
|
||||||
|
window.vertoInitialize();
|
||||||
|
window.vertoManager.shareScreen.apply(window.vertoManager, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.vertoExtensionGetChromeExtensionStatus = function (extensionid, callback) {
|
||||||
|
callback = Verto.normalizeCallback(callback);
|
||||||
|
getChromeExtensionStatus(extensionid, callback);
|
||||||
|
};
|
||||||
|
@ -1,214 +0,0 @@
|
|||||||
var deskshareStream = "deskshareStream";
|
|
||||||
window[deskshareStream] = null;
|
|
||||||
this.share_call = null;
|
|
||||||
|
|
||||||
// final entry point for sharing from Chrome.
|
|
||||||
// already have the resolution and constraints chosen
|
|
||||||
var configDeskshareFromChrome = function(videoTag, callbacks, extensionId, resolutionConstruction) {
|
|
||||||
// do initial check for extension
|
|
||||||
getChromeExtensionStatus(extensionId, function(status) {
|
|
||||||
if (status != "installed-enabled") {
|
|
||||||
callbacks.onError({'status': 'failed', 'errorcode': 2001});
|
|
||||||
console.error("No chrome Extension");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bring up Chrome screen picker
|
|
||||||
getScreenConstraints(function(error, screen_constraints) {
|
|
||||||
if(error) {
|
|
||||||
callbacks.onError({'status': 'failed', 'errorcode': 2021});
|
|
||||||
return console.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
screen_constraints = resolutionConstruction(screen_constraints);
|
|
||||||
window.firefoxDesksharePresent = false;
|
|
||||||
doCall(screen_constraints, videoTag, callbacks);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// entry point for Chrome HTML5 sharing
|
|
||||||
// connects with html5 client libraries to retrieve a selected resolution
|
|
||||||
var configDeskshareFromChromeHTML5 = function(videoTag, callbacks, extensionId) {
|
|
||||||
var resolutionConstruction = function(screen_constraints) {
|
|
||||||
console.log("modifying video quality");
|
|
||||||
var selectedDeskshareResolution = getChosenDeskshareResolution(); // this is the video profile the user chose
|
|
||||||
my_real_size(selectedDeskshareResolution);
|
|
||||||
var selectedDeskshareConstraints = getDeskshareConstraintsFromResolution(selectedDeskshareResolution, screen_constraints); // convert to a valid constraints object
|
|
||||||
console.log(selectedDeskshareConstraints);
|
|
||||||
return selectedDeskshareConstraints.video.mandatory;
|
|
||||||
};
|
|
||||||
configDeskshareFromChrome(videoTag, callbacks, extensionId, resolutionConstruction);
|
|
||||||
};
|
|
||||||
|
|
||||||
// entry point when desksharing using Google Chrome via the flash Client
|
|
||||||
// currently uses a default preset resolution in place of a resolution picker
|
|
||||||
// prepares the constraints and passes off to generic Chrome handler
|
|
||||||
var configDeskshareFromChromeFlash = function(videoTag, callbacks, extensionId) {
|
|
||||||
var resolutionConstruction = function(screen_constraints) {
|
|
||||||
// BigBlueButton low
|
|
||||||
var getDeskshareConstraints = function(constraints) {
|
|
||||||
return {
|
|
||||||
"audio": false,
|
|
||||||
"video": {
|
|
||||||
"mandatory": {
|
|
||||||
"maxWidth": 1920,
|
|
||||||
"maxHeight": 1080,
|
|
||||||
"chromeMediaSource": constraints.mandatory.chromeMediaSource,
|
|
||||||
"chromeMediaSourceId": constraints.mandatory.chromeMediaSourceId,
|
|
||||||
"minFrameRate": 12,
|
|
||||||
},
|
|
||||||
"optional": []
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log("not modifying video quality");
|
|
||||||
var selectedDeskshareConstraints = getDeskshareConstraints(screen_constraints); // convert to a valid constraints object
|
|
||||||
console.log(selectedDeskshareConstraints);
|
|
||||||
return selectedDeskshareConstraints.video.mandatory;
|
|
||||||
};
|
|
||||||
configDeskshareFromChrome(videoTag, callbacks, extensionId, resolutionConstruction);
|
|
||||||
};
|
|
||||||
|
|
||||||
// final entry point for Firefox sharing
|
|
||||||
var configDeskshareFromFirefox = function(screen_constraints, videoTag, callbacks) {
|
|
||||||
// bypass all the default gUM calls inside jquery.FSRTC.js to use my own
|
|
||||||
window.firefoxDesksharePresent = true;
|
|
||||||
// the gUM args to invoke the Firefox screen picker
|
|
||||||
var screen_constraints = {
|
|
||||||
video: {
|
|
||||||
"mozMediaSource": 'window',
|
|
||||||
"mediaSource": 'window',
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// register the callback to the window namespace to be available in jquery.FSRTC.js
|
|
||||||
window.firefoxDesksharePresentErrorCallback = callbacks.onError;
|
|
||||||
doCall(screen_constraints, videoTag, callbacks);
|
|
||||||
};
|
|
||||||
|
|
||||||
var configDeskshareFromFirefoxFlash = function(screen_constraints, videoTag, callbacks) {
|
|
||||||
console.log("deskshare from firefox flash");
|
|
||||||
configDeskshareFromFirefox(screen_constraints, videoTag, callbacks);
|
|
||||||
};
|
|
||||||
|
|
||||||
var configDeskshareFromFirefoxHTML5 = function(screen_constraints, videoTag, callbacks) {
|
|
||||||
console.log("deskshare from firefox html5");
|
|
||||||
configDeskshareFromFirefox(screen_constraints, videoTag, callbacks);
|
|
||||||
};
|
|
||||||
|
|
||||||
function endScreenshare(loggingCallback, onSuccess) {
|
|
||||||
console.log("endScreenshare");
|
|
||||||
if (share_call) {
|
|
||||||
console.log("a screenshare call is active. Hanging up");
|
|
||||||
share_call.hangup();
|
|
||||||
share_call = null;
|
|
||||||
normalizeCallback(onSuccess)();
|
|
||||||
} else {
|
|
||||||
console.log("a screenshare call is NOT active. Doing nothing");
|
|
||||||
}
|
|
||||||
normalizeCallback(loggingCallback)({'status':'success', 'message': 'screenshare ended'});
|
|
||||||
}
|
|
||||||
|
|
||||||
function startScreenshare(loggingCallback, videoTag, vertoServerCredentials, extensionId, modifyResolution, onSuccess, onFail) {
|
|
||||||
onSuccess = normalizeCallback(onSuccess);
|
|
||||||
onFail = normalizeCallback(onFail);
|
|
||||||
loggingCallback = normalizeCallback(loggingCallback);
|
|
||||||
console.log("startScreenshare");
|
|
||||||
if(!isLoggedIntoVerto()) { // start the verto log in procedure
|
|
||||||
// runs when the websocket is successfully created
|
|
||||||
callbacks.onWSLogin = function(v, success) {
|
|
||||||
startScreenshareAfterLogin(loggingCallback, videoTag, extensionId, modifyResolution, onSuccess, onFail);
|
|
||||||
loggingCallback({'status':'success', 'message': 'screenshare started'});
|
|
||||||
console.log("logged in. starting screenshare");
|
|
||||||
}
|
|
||||||
// set up verto
|
|
||||||
init(window.videoTag, vertoServerCredentials);
|
|
||||||
} else {
|
|
||||||
console.log("already logged into verto, going straight to making a call");
|
|
||||||
startScreenshareAfterLogin(loggingCallback, videoTag, extensionId, modifyResolution, onSuccess, onFail);
|
|
||||||
loggingCallback({'status':'success', 'message': 'screenshare started'});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function startScreenshareAfterLogin(loggingCallback, videoTag, extensionId, modifyResolution, onSuccess, onFail) {
|
|
||||||
if (share_call) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
outgoingBandwidth = incomingBandwidth = "default";
|
|
||||||
var sharedev = "screen";
|
|
||||||
|
|
||||||
if (sharedev !== "screen") {
|
|
||||||
console.log("Attempting Screen Capture with non-screen device....");
|
|
||||||
|
|
||||||
BBB.getMyUserInfo(function (retData){
|
|
||||||
share_call = verto.newCall({
|
|
||||||
destination_number: retData.voiceBridge + "-screen",
|
|
||||||
caller_id_name: retData.myUsername + " (Screen)",
|
|
||||||
caller_id_number: retData.myUserID + " (screen)",
|
|
||||||
outgoingBandwidth: outgoingBandwidth,
|
|
||||||
incomingBandwidth: incomingBandwidth,
|
|
||||||
useCamera: sharedev,
|
|
||||||
useVideo: true,
|
|
||||||
screenShare: true,
|
|
||||||
dedEnc: false,
|
|
||||||
mirrorInput: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var callbacks = {
|
|
||||||
onError: normalizeCallback(onFail),
|
|
||||||
onICEComplete: function(self, candidate) { // ICE candidate negotiation is complete
|
|
||||||
console.log("custom callback: onICEComplete");
|
|
||||||
normalizeCallback(onSuccess)(candidate);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// determine if Firefox or Chrome
|
|
||||||
// for now the only difference is that html5 has a resolution dialog
|
|
||||||
if (!!navigator.mozGetUserMedia) {
|
|
||||||
if (modifyResolution) {
|
|
||||||
configDeskshareFromFirefoxHTML5(null, videoTag, callbacks);
|
|
||||||
} else {
|
|
||||||
configDeskshareFromFirefoxFlash(null, videoTag, callbacks);
|
|
||||||
}
|
|
||||||
} else if (!!window.chrome) {
|
|
||||||
if (modifyResolution) {
|
|
||||||
configDeskshareFromChromeHTML5(videoTag, callbacks, extensionId);
|
|
||||||
} else {
|
|
||||||
configDeskshareFromChromeFlash(videoTag, callbacks, extensionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function doCall(screen_constraints, videoTag, callbacks) {
|
|
||||||
console.log("\n\n\nhere are the screen_constraints\n\n\n");
|
|
||||||
console.log(screen_constraints);
|
|
||||||
window.listenOnly = false;
|
|
||||||
window.watchOnly = false;
|
|
||||||
window.joinAudio = true;
|
|
||||||
|
|
||||||
BBB.getMyUserInfo(function (retData){
|
|
||||||
var callParams = {
|
|
||||||
destination_number: retData.voiceBridge + "-screen",
|
|
||||||
caller_id_name: retData.myUsername + " (Screen)",
|
|
||||||
caller_id_number: retData.myUserID + " (screen)",
|
|
||||||
outgoingBandwidth: outgoingBandwidth,
|
|
||||||
incomingBandwidth: incomingBandwidth,
|
|
||||||
videoParams: screen_constraints,
|
|
||||||
useVideo: true,
|
|
||||||
screenShare: true,
|
|
||||||
dedEnc: true,
|
|
||||||
mirrorInput: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (videoTag != null) {
|
|
||||||
callParams.tag = videoTag;
|
|
||||||
}
|
|
||||||
share_call = verto.newCall(callParams);
|
|
||||||
share_call.rtc.options.callbacks = $.extend(share_call.rtc.options.callbacks, callbacks);
|
|
||||||
});
|
|
||||||
}
|
|
@ -20,13 +20,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
|
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
|
||||||
xmlns:maps="org.bigbluebutton.modules.deskShare.maps.*"
|
|
||||||
implements="org.bigbluebutton.common.IBigBlueButtonModule"
|
implements="org.bigbluebutton.common.IBigBlueButtonModule"
|
||||||
creationComplete="onCreationComplete()" xmlns:maps1="org.bigbluebutton.modules.screenshare.maps.*">
|
creationComplete="onCreationComplete()" xmlns:maps1="org.bigbluebutton.modules.screenshare.maps.*">
|
||||||
|
|
||||||
<maps1:ScreenshareEventMap id="deskshareGlobalEventMap" />
|
<maps1:ScreenshareEventMap id="deskshareGlobalEventMap" />
|
||||||
|
<maps1:WebRTCDeskshareEventMap id="webRTCDeskshareEventMap" />
|
||||||
|
|
||||||
<mx:Script>
|
<mx:Script>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
import com.asfusion.mate.events.Dispatcher;
|
import com.asfusion.mate.events.Dispatcher;
|
||||||
|
@ -109,23 +109,26 @@ package org.bigbluebutton.modules.deskshare.managers
|
|||||||
private function startWebRTCDeskshare():void {
|
private function startWebRTCDeskshare():void {
|
||||||
LOGGER.debug("DeskshareManager::startWebRTCDeskshare");
|
LOGGER.debug("DeskshareManager::startWebRTCDeskshare");
|
||||||
|
|
||||||
var result:String;
|
|
||||||
if (ExternalInterface.available) {
|
if (ExternalInterface.available) {
|
||||||
var loggingCallback:Function = function(args:Object):void {LOGGER.debug(args); JSLog.warn("loggingCallback", args)};
|
|
||||||
ExternalInterface.addCallback("loggingCallback", loggingCallback);
|
|
||||||
var videoTag:String = "localVertoVideo";
|
var videoTag:String = "localVertoVideo";
|
||||||
var modifyResolution:Boolean = false;
|
|
||||||
// register these callbacks
|
|
||||||
var onSuccess:Function = function():void { LOGGER.debug("onSuccess"); JSLog.warn("onSuccess - as", {})};
|
|
||||||
ExternalInterface.addCallback("onSuccess", onSuccess);
|
|
||||||
var onFail:Function = function(args:Object):void {
|
var onFail:Function = function(args:Object):void {
|
||||||
JSLog.warn("onFail - as", args);
|
JSLog.warn("onFail - as", args);
|
||||||
JSLog.warn("WebRTCDeskshareManager::startWebRTCDeskshare - falling back to java", {});
|
JSLog.warn("WebRTCDeskshareManager::startWebRTCDeskshare - falling back to java", {});
|
||||||
globalDispatcher.dispatchEvent(new UseJavaModeCommand())
|
globalDispatcher.dispatchEvent(new UseJavaModeCommand())
|
||||||
};
|
};
|
||||||
ExternalInterface.addCallback("onFail", onFail);
|
ExternalInterface.addCallback("onFail", onFail);
|
||||||
JSLog.warn("calling startScreenshare", {});
|
|
||||||
result = ExternalInterface.call("startScreenshare", "loggingCallback", videoTag, vertoServerCredentials, chromeExtensionKey, modifyResolution, "onSuccess", "onFail");
|
ExternalInterface.call(
|
||||||
|
'vertoShareScreen',
|
||||||
|
videoTag,
|
||||||
|
'3500',
|
||||||
|
'FreeSWITCH USers - abc',
|
||||||
|
'1008',
|
||||||
|
null,
|
||||||
|
vertoServerCredentials,
|
||||||
|
chromeExtensionKey,
|
||||||
|
onFail
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.bigbluebutton.modules.screenshare.events
|
||||||
|
{
|
||||||
|
import flash.events.Event;
|
||||||
|
|
||||||
|
public class DeskshareToolbarEvent extends Event
|
||||||
|
{
|
||||||
|
public static const STOP:String = "deactivate toolbar status";
|
||||||
|
|
||||||
|
public function DeskshareToolbarEvent(type:String)
|
||||||
|
{
|
||||||
|
super(type, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.bigbluebutton.modules.screenshare.events
|
||||||
|
{
|
||||||
|
import flash.events.Event;
|
||||||
|
|
||||||
|
public class UseJavaModeCommand extends Event
|
||||||
|
{
|
||||||
|
public static const USE_JAVA_MODE:String = "use Java to join deskshare event";
|
||||||
|
|
||||||
|
public function UseJavaModeCommand()
|
||||||
|
{
|
||||||
|
super(USE_JAVA_MODE, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.bigbluebutton.modules.screenshare.events
|
||||||
|
{
|
||||||
|
import flash.events.Event;
|
||||||
|
|
||||||
|
public class WebRTCShareWindowEvent extends Event
|
||||||
|
{
|
||||||
|
public static const CLOSE:String = "WebRTC Deskshare Share Window Close Event";
|
||||||
|
|
||||||
|
public function WebRTCShareWindowEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
|
||||||
|
{
|
||||||
|
super(type, bubbles, cancelable);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.bigbluebutton.modules.screenshare.events
|
||||||
|
{
|
||||||
|
import flash.events.Event;
|
||||||
|
|
||||||
|
public class WebRTCStreamEvent extends Event
|
||||||
|
{
|
||||||
|
public static const START:String = "WebRTC Deskshare Stream Started Event";
|
||||||
|
public static const STOP:String = "WebRTC Deskshare Stream Stopped Event";
|
||||||
|
|
||||||
|
public var videoWidth:Number = 0;
|
||||||
|
public var videoHeight:Number = 0;
|
||||||
|
|
||||||
|
public function WebRTCStreamEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
|
||||||
|
{
|
||||||
|
super(type, bubbles, cancelable);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.bigbluebutton.modules.screenshare.events
|
||||||
|
{
|
||||||
|
import flash.events.Event;
|
||||||
|
import org.bigbluebutton.main.api.JSLog;
|
||||||
|
|
||||||
|
public class WebRTCViewStreamEvent extends Event
|
||||||
|
{
|
||||||
|
public static const START:String = "WebRTC Start Viewing Stream Event";
|
||||||
|
public static const STOP:String = "WebRTC Stop Viewing Stream Event";
|
||||||
|
|
||||||
|
public var videoWidth:Number = 0;
|
||||||
|
public var videoHeight:Number = 0;
|
||||||
|
public var rtmp:String = null;
|
||||||
|
|
||||||
|
public function WebRTCViewStreamEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
|
||||||
|
{
|
||||||
|
super(type, bubbles, cancelable);
|
||||||
|
JSLog.warn("creating a WebRTCViewStreamEvent event " + type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.bigbluebutton.modules.screenshare.events
|
||||||
|
{
|
||||||
|
import flash.events.Event;
|
||||||
|
|
||||||
|
public class WebRTCViewWindowEvent extends Event
|
||||||
|
{
|
||||||
|
public static const CLOSE:String = "WebRTC Deskshare View Window Close Event";
|
||||||
|
|
||||||
|
public function WebRTCViewWindowEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
|
||||||
|
{
|
||||||
|
super(type, bubbles, cancelable);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -32,6 +32,9 @@ package org.bigbluebutton.modules.screenshare.managers {
|
|||||||
import org.bigbluebutton.modules.screenshare.model.ScreenshareModel;
|
import org.bigbluebutton.modules.screenshare.model.ScreenshareModel;
|
||||||
import org.bigbluebutton.modules.screenshare.model.ScreenshareOptions;
|
import org.bigbluebutton.modules.screenshare.model.ScreenshareOptions;
|
||||||
import org.bigbluebutton.modules.screenshare.services.ScreenshareService;
|
import org.bigbluebutton.modules.screenshare.services.ScreenshareService;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.UseJavaModeCommand;
|
||||||
|
import org.bigbluebutton.modules.screenshare.utils.BrowserCheck;
|
||||||
|
import org.bigbluebutton.main.api.JSLog;
|
||||||
|
|
||||||
public class ScreenshareManager {
|
public class ScreenshareManager {
|
||||||
private static const LOGGER:ILogger = getClassLogger(ScreenshareManager);
|
private static const LOGGER:ILogger = getClassLogger(ScreenshareManager);
|
||||||
@ -43,6 +46,7 @@ package org.bigbluebutton.modules.screenshare.managers {
|
|||||||
private var service:ScreenshareService;
|
private var service:ScreenshareService;
|
||||||
private var globalDispatcher:Dispatcher;
|
private var globalDispatcher:Dispatcher;
|
||||||
private var sharing:Boolean = false;
|
private var sharing:Boolean = false;
|
||||||
|
private var usingJava:Boolean = true;
|
||||||
|
|
||||||
public function ScreenshareManager() {
|
public function ScreenshareManager() {
|
||||||
service = new ScreenshareService();
|
service = new ScreenshareService();
|
||||||
@ -73,7 +77,7 @@ package org.bigbluebutton.modules.screenshare.managers {
|
|||||||
LOGGER.debug("handle Connection Success Event");
|
LOGGER.debug("handle Connection Success Event");
|
||||||
service.checkIfPresenterIsSharingScreen();
|
service.checkIfPresenterIsSharingScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleStreamStartedEvent(event:StreamStartedEvent):void {
|
public function handleStreamStartedEvent(event:StreamStartedEvent):void {
|
||||||
ScreenshareModel.getInstance().streamId = event.streamId;
|
ScreenshareModel.getInstance().streamId = event.streamId;
|
||||||
ScreenshareModel.getInstance().width = event.width;
|
ScreenshareModel.getInstance().width = event.width;
|
||||||
@ -98,8 +102,8 @@ package org.bigbluebutton.modules.screenshare.managers {
|
|||||||
ScreenshareModel.getInstance().url = event.url;
|
ScreenshareModel.getInstance().url = event.url;
|
||||||
|
|
||||||
if (UsersUtil.amIPresenter()) {
|
if (UsersUtil.amIPresenter()) {
|
||||||
// var dispatcher:Dispatcher = new Dispatcher();
|
// var dispatcher:Dispatcher = new Dispatcher();
|
||||||
// dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
// dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
||||||
} else {
|
} else {
|
||||||
handleStreamStartEvent(ScreenshareModel.getInstance().streamId, event.width, event.height);
|
handleStreamStartEvent(ScreenshareModel.getInstance().streamId, event.width, event.height);
|
||||||
|
|
||||||
@ -108,8 +112,7 @@ package org.bigbluebutton.modules.screenshare.managers {
|
|||||||
var dispatcher:Dispatcher = new Dispatcher();
|
var dispatcher:Dispatcher = new Dispatcher();
|
||||||
dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function initDeskshare():void {
|
private function initDeskshare():void {
|
||||||
sharing = false;
|
sharing = false;
|
||||||
var option:ScreenshareOptions = new ScreenshareOptions();
|
var option:ScreenshareOptions = new ScreenshareOptions();
|
||||||
@ -141,10 +144,16 @@ package org.bigbluebutton.modules.screenshare.managers {
|
|||||||
toolbarButtonManager.startedSharing();
|
toolbarButtonManager.startedSharing();
|
||||||
var option:ScreenshareOptions = new ScreenshareOptions();
|
var option:ScreenshareOptions = new ScreenshareOptions();
|
||||||
option.parseOptions();
|
option.parseOptions();
|
||||||
var autoStart:Boolean = false; // harcode for now
|
|
||||||
publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), autoStart, option.autoFullScreen);
|
if (option.useWebRTCIfAvailable && !BrowserCheck.isWebRTCSupported()) {
|
||||||
sharing = true;
|
usingJava = true;
|
||||||
service.requestStartSharing();
|
var autoStart:Boolean = false; // harcode for now
|
||||||
|
publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), autoStart, option.autoFullScreen);
|
||||||
|
sharing = true;
|
||||||
|
service.requestStartSharing();
|
||||||
|
} else {
|
||||||
|
usingJava = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequestStopSharingEvent():void {
|
public function handleRequestStopSharingEvent():void {
|
||||||
@ -187,8 +196,19 @@ package org.bigbluebutton.modules.screenshare.managers {
|
|||||||
|
|
||||||
private function handleStreamStartEvent(streamId:String, videoWidth:Number, videoHeight:Number):void {
|
private function handleStreamStartEvent(streamId:String, videoWidth:Number, videoHeight:Number):void {
|
||||||
LOGGER.debug("Received start vieweing command");
|
LOGGER.debug("Received start vieweing command");
|
||||||
|
if (!usingJava) { return; }
|
||||||
viewWindowManager.startViewing(streamId, videoWidth, videoHeight);
|
viewWindowManager.startViewing(streamId, videoWidth, videoHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function handleUseJavaModeCommand():void {
|
||||||
|
JSLog.warn("ScreenshareManager::handleUseJavaModeCommand", {});
|
||||||
|
usingJava = true;
|
||||||
|
handleStartSharingEvent(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleDeskshareToolbarStopEvent():void {
|
||||||
|
JSLog.warn("ScreenshareManager::handleDeskshareToolbarStopEvent", {});
|
||||||
|
toolbarButtonManager.stopedSharing();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,298 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.bigbluebutton.modules.screenshare.managers
|
||||||
|
{
|
||||||
|
import com.asfusion.mate.events.Dispatcher;
|
||||||
|
|
||||||
|
import flash.external.ExternalInterface;
|
||||||
|
|
||||||
|
import org.as3commons.logging.api.ILogger;
|
||||||
|
import org.as3commons.logging.api.getClassLogger;
|
||||||
|
import org.bigbluebutton.core.UsersUtil;
|
||||||
|
import org.bigbluebutton.core.managers.UserManager;
|
||||||
|
import org.bigbluebutton.main.events.MadePresenterEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.UseJavaModeCommand;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.WebRTCViewStreamEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.model.ScreenshareOptions;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.ShareWindowEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.services.WebRTCDeskshareService;
|
||||||
|
import org.bigbluebutton.modules.screenshare.utils.BrowserCheck;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.DeskshareToolbarEvent;
|
||||||
|
import org.bigbluebutton.main.api.JSLog;
|
||||||
|
|
||||||
|
public class WebRTCDeskshareManager {
|
||||||
|
private static const LOGGER:ILogger = getClassLogger(WebRTCDeskshareManager);
|
||||||
|
|
||||||
|
private var publishWindowManager:WebRTCPublishWindowManager;
|
||||||
|
private var viewWindowManager:WebRTCViewerWindowManager;
|
||||||
|
private var toolbarButtonManager:ToolbarButtonManager;
|
||||||
|
private var module:ScreenshareModule;
|
||||||
|
private var service:WebRTCDeskshareService;
|
||||||
|
private var globalDispatcher:Dispatcher;
|
||||||
|
private var sharing:Boolean = false;
|
||||||
|
private var usingWebRTC:Boolean = false;
|
||||||
|
private var chromeExtensionKey:String = null;
|
||||||
|
|
||||||
|
public function WebRTCDeskshareManager() {
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::WebRTCDeskshareManager", {});
|
||||||
|
service = new WebRTCDeskshareService();
|
||||||
|
globalDispatcher = new Dispatcher();
|
||||||
|
publishWindowManager = new WebRTCPublishWindowManager(service);
|
||||||
|
viewWindowManager = new WebRTCViewerWindowManager(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleStartModuleEvent(module:ScreenshareModule):void {
|
||||||
|
LOGGER.debug("WebRTC Screenshare Module starting");
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleStartModuleEvent", {});
|
||||||
|
this.module = module;
|
||||||
|
service.handleStartModuleEvent(module);
|
||||||
|
|
||||||
|
if (UsersUtil.amIPresenter()) {
|
||||||
|
initDeskshare();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleStopModuleEvent():void {
|
||||||
|
LOGGER.debug("WebRTC Deskshare Module stopping");
|
||||||
|
|
||||||
|
publishWindowManager.stopSharing();
|
||||||
|
viewWindowManager.stopViewing();
|
||||||
|
service.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*presenter stopped their program stream*/
|
||||||
|
public function handleStreamStoppedEvent():void {
|
||||||
|
LOGGER.debug("WebRTCDeskshareManager::handleStreamStoppedEvent Sending deskshare stopped command");
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleStreamStoppedEvent", {});
|
||||||
|
stopWebRTCDeskshare();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*viewer being told there is no more stream*/
|
||||||
|
public function handleStreamStopEvent(args:Object):void {
|
||||||
|
LOGGER.debug("WebRTCDeskshareManager::handleStreamStopEvent");
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleStreamStopEvent", {});
|
||||||
|
viewWindowManager.handleViewWindowCloseEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequestStopSharingEvent():void {
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleRequestStopSharingEvent", {});
|
||||||
|
/* stopping WebRTC deskshare. Alert DeskshareManager to reset toolbar */
|
||||||
|
globalDispatcher.dispatchEvent(new DeskshareToolbarEvent(DeskshareToolbarEvent.STOP));
|
||||||
|
stopWebRTCDeskshare();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function stopWebRTCDeskshare():void {
|
||||||
|
LOGGER.debug("WebRTCDeskshareManager::stopWebRTCDeskshare");
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::stopWebRTCDeskshare", {});
|
||||||
|
viewWindowManager.stopViewing();
|
||||||
|
|
||||||
|
globalDispatcher.dispatchEvent(new ShareWindowEvent(ShareWindowEvent.CLOSE));
|
||||||
|
|
||||||
|
if (ExternalInterface.available) {
|
||||||
|
ExternalInterface.call("vertoExitScreenShare");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function startWebRTCDeskshare():void {
|
||||||
|
LOGGER.debug("WebRTCDeskshareManager::startWebRTCDeskshare");
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::startWebRTCDeskshare", {});
|
||||||
|
|
||||||
|
if (ExternalInterface.available) {
|
||||||
|
var videoTag:String = "localVertoVideo";
|
||||||
|
var onFail:Function = function(args:Object):void {
|
||||||
|
JSLog.warn("onFail - as", args);
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::startWebRTCDeskshare - falling back to java", {});
|
||||||
|
globalDispatcher.dispatchEvent(new UseJavaModeCommand())
|
||||||
|
};
|
||||||
|
ExternalInterface.addCallback("onFail", onFail);
|
||||||
|
|
||||||
|
var voiceBridge:String = UserManager.getInstance().getConference().voiceBridge;
|
||||||
|
var myName:String = 'FreeSWITCH Users - ';
|
||||||
|
myName += UserManager.getInstance().getConference().getMyName();
|
||||||
|
|
||||||
|
ExternalInterface.call(
|
||||||
|
'vertoShareScreen',
|
||||||
|
videoTag,
|
||||||
|
voiceBridge,
|
||||||
|
myName,
|
||||||
|
null,
|
||||||
|
"onFail",
|
||||||
|
chromeExtensionKey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function initDeskshare():void {
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::initDeskshare", {});
|
||||||
|
sharing = false;
|
||||||
|
var options:ScreenshareOptions = new ScreenshareOptions();
|
||||||
|
options.parseOptions();
|
||||||
|
if (options.chromeExtensionKey) {
|
||||||
|
chromeExtensionKey = options.chromeExtensionKey;
|
||||||
|
}
|
||||||
|
if (options.autoStart) {
|
||||||
|
handleStartSharingEvent(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleMadePresenterEvent(e:MadePresenterEvent):void {
|
||||||
|
LOGGER.debug("Got MadePresenterEvent ");
|
||||||
|
initDeskshare();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleMadeViewerEvent(e:MadePresenterEvent):void{
|
||||||
|
LOGGER.debug("Got MadeViewerEvent ");
|
||||||
|
if (sharing) {
|
||||||
|
publishWindowManager.stopSharing();
|
||||||
|
stopWebRTCDeskshare();
|
||||||
|
}
|
||||||
|
sharing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function canIUseVertoOnThisBrowser(onFailure:Function, onSuccess:Function):void {
|
||||||
|
LOGGER.debug("DeskshareManager::canIUseVertoOnThisBrowser");
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::canIUseVertoOnThisBrowser", {});
|
||||||
|
var options:ScreenshareOptions = new ScreenshareOptions();
|
||||||
|
options.parseOptions();
|
||||||
|
|
||||||
|
if (options.useWebRTCIfAvailable && BrowserCheck.isWebRTCSupported()) {
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleStartSharingEvent WebRTC Supported", {});
|
||||||
|
if (BrowserCheck.isFirefox()) {
|
||||||
|
onSuccess("Firefox, lets try");
|
||||||
|
} else {
|
||||||
|
if (chromeExtensionKey != null) {
|
||||||
|
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleStartSharingEvent chrome extension key exists - ", chromeExtensionKey);
|
||||||
|
if (ExternalInterface.available) {
|
||||||
|
|
||||||
|
var success:Function = function(status:String):void {
|
||||||
|
ExternalInterface.addCallback("gCETCallback", null);
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleStartSharingEvent inside onSuccess", {});
|
||||||
|
if (status == "installed-enabled") {
|
||||||
|
JSLog.warn("Chrome Extension exists", {});
|
||||||
|
onSuccess("worked");
|
||||||
|
} else {
|
||||||
|
onFailure("No Chrome Extension");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ExternalInterface.addCallback("gCETCallback", success);
|
||||||
|
ExternalInterface.call("vertoExtensionGetChromeExtensionStatus", chromeExtensionKey, "gCETCallback");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onFailure("No chromeExtensionKey in config.xml");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onFailure("Web browser doesn't support WebRTC");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*handle start sharing event*/
|
||||||
|
public function handleStartSharingEvent(autoStart:Boolean):void {
|
||||||
|
LOGGER.debug("WebRTCDeskshareManager::handleStartSharingEvent");
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleStartSharingEvent", {});
|
||||||
|
|
||||||
|
var onFailure:Function = function(message:String):void {
|
||||||
|
JSLog.warn(message, {});
|
||||||
|
usingWebRTC = false;
|
||||||
|
// send out event to fallback to Java
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleStartSharingEvent - falling back to java", {});
|
||||||
|
globalDispatcher.dispatchEvent(new UseJavaModeCommand());
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
var onSuccess:Function = function(message:String):void {
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleStartSharingEvent onSuccess", {});
|
||||||
|
JSLog.warn(message, {});
|
||||||
|
usingWebRTC = true;
|
||||||
|
startWebRTCDeskshare();
|
||||||
|
};
|
||||||
|
|
||||||
|
canIUseVertoOnThisBrowser(onFailure, onSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleShareWindowCloseEvent():void {
|
||||||
|
publishWindowManager.handleShareWindowCloseEvent();
|
||||||
|
sharing = false;
|
||||||
|
stopWebRTCDeskshare();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleViewWindowCloseEvent():void {
|
||||||
|
LOGGER.debug("Received stop viewing command");
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleViewWindowCloseEvent", {});
|
||||||
|
viewWindowManager.handleViewWindowCloseEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleStreamStartEvent(e:WebRTCViewStreamEvent):void{
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleStreamStartEvent rtmp=", e.rtmp);
|
||||||
|
// if (!usingWebRTC) { return; } //TODO this was causing issues
|
||||||
|
if (sharing) return; //TODO must uncomment this for the non-webrtc desktop share
|
||||||
|
var isPresenter:Boolean = UserManager.getInstance().getConference().amIPresenter;
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleStreamStartEvent isPresenter=", isPresenter);
|
||||||
|
LOGGER.debug("Received start viewing command when isPresenter==[{0}]",[isPresenter]);
|
||||||
|
|
||||||
|
if(isPresenter) {
|
||||||
|
publishWindowManager.startViewing(e.rtmp, e.videoWidth, e.videoHeight);
|
||||||
|
} else {
|
||||||
|
viewWindowManager.startViewing(e.rtmp, e.videoWidth, e.videoHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
sharing = true; //TODO must uncomment this for the non-webrtc desktop share
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleUseJavaModeCommand():void {
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleUseJavaModeCommand", {});
|
||||||
|
usingWebRTC = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequestStartSharingEvent():void {
|
||||||
|
JSLog.warn("WebRTCDeskshareManager::handleRequestStartSharingEvent", {});
|
||||||
|
initDeskshare();
|
||||||
|
handleStartSharingEvent(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleStreamStartedEvent(event: WebRTCViewStreamEvent):void {
|
||||||
|
if (UsersUtil.amIPresenter()) {
|
||||||
|
} else {
|
||||||
|
/*handleStreamStartEvent(ScreenshareModel.getInstance().streamId, event.width, event.height);*/
|
||||||
|
handleStreamStartEvent(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var dispatcher:Dispatcher = new Dispatcher();
|
||||||
|
dispatcher.dispatchEvent(new WebRTCViewStreamEvent(WebRTCViewStreamEvent.START));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*public function handleIsSharingScreenEvent(event: IsSharingScreenEvent):void {*/
|
||||||
|
public function handleIsSharingScreenEvent():void {
|
||||||
|
if (UsersUtil.amIPresenter()) {
|
||||||
|
} else {
|
||||||
|
/*handleStreamStartEvent(ScreenshareModel.getInstance().streamId, event.width, event.height);*/
|
||||||
|
handleStreamStartEvent(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var dispatcher:Dispatcher = new Dispatcher();
|
||||||
|
dispatcher.dispatchEvent(new WebRTCViewStreamEvent(WebRTCViewStreamEvent.START));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.bigbluebutton.modules.screenshare.managers
|
||||||
|
{
|
||||||
|
import com.asfusion.mate.events.Dispatcher;
|
||||||
|
|
||||||
|
import flash.events.TimerEvent;
|
||||||
|
import flash.utils.Timer;
|
||||||
|
|
||||||
|
import org.as3commons.logging.api.ILogger;
|
||||||
|
import org.as3commons.logging.api.getClassLogger;
|
||||||
|
import org.bigbluebutton.common.IBbbModuleWindow;
|
||||||
|
import org.bigbluebutton.common.events.CloseWindowEvent;
|
||||||
|
import org.bigbluebutton.common.events.OpenWindowEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.services.WebRTCDeskshareService;
|
||||||
|
import org.bigbluebutton.modules.screenshare.view.components.WebRTCDesktopPublishWindow;
|
||||||
|
|
||||||
|
public class WebRTCPublishWindowManager {
|
||||||
|
private static const LOGGER:ILogger = getClassLogger(PublishWindowManager);
|
||||||
|
|
||||||
|
private var shareWindow:WebRTCDesktopPublishWindow;
|
||||||
|
private var globalDispatcher:Dispatcher;
|
||||||
|
private var service:WebRTCDeskshareService;
|
||||||
|
private var buttonShownOnToolbar:Boolean = false;
|
||||||
|
|
||||||
|
// Timer to auto-publish webcam. We need this timer to delay
|
||||||
|
// the auto-publishing until after the Viewers's window has loaded
|
||||||
|
// to receive the publishing events. Otherwise, the user joining next
|
||||||
|
// won't be able to view the webcam.
|
||||||
|
private var autoPublishTimer:Timer;
|
||||||
|
|
||||||
|
public function WebRTCPublishWindowManager(service:WebRTCDeskshareService) {
|
||||||
|
LOGGER.debug("PublishWindowManager init");
|
||||||
|
globalDispatcher = new Dispatcher();
|
||||||
|
this.service = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stopSharing():void {
|
||||||
|
if (shareWindow != null) shareWindow.stopSharing();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function autopublishTimerHandler(event:TimerEvent):void {
|
||||||
|
shareWindow.shareScreen(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleShareWindowCloseEvent():void {
|
||||||
|
closeWindow(shareWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function openWindow(window:IBbbModuleWindow):void {
|
||||||
|
var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
|
||||||
|
event.window = window;
|
||||||
|
globalDispatcher.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function closeWindow(window:IBbbModuleWindow):void {
|
||||||
|
var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
|
||||||
|
event.window = window;
|
||||||
|
globalDispatcher.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function startViewing(rtmp:String, videoWidth:Number, videoHeight:Number):void{
|
||||||
|
shareWindow = new WebRTCDesktopPublishWindow();
|
||||||
|
shareWindow.visible = true;
|
||||||
|
openWindow(shareWindow);
|
||||||
|
shareWindow.startVideo(rtmp, videoWidth, videoHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.bigbluebutton.modules.screenshare.managers
|
||||||
|
{
|
||||||
|
import com.asfusion.mate.events.Dispatcher;
|
||||||
|
|
||||||
|
import org.as3commons.logging.api.ILogger;
|
||||||
|
import org.as3commons.logging.api.getClassLogger;
|
||||||
|
import org.bigbluebutton.common.IBbbModuleWindow;
|
||||||
|
import org.bigbluebutton.common.events.CloseWindowEvent;
|
||||||
|
import org.bigbluebutton.common.events.OpenWindowEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.services.WebRTCDeskshareService;
|
||||||
|
import org.bigbluebutton.modules.screenshare.view.components.WebRTCDesktopPublishWindow;
|
||||||
|
import org.bigbluebutton.modules.screenshare.view.components.WebRTCDesktopViewWindow;
|
||||||
|
|
||||||
|
public class WebRTCViewerWindowManager {
|
||||||
|
private static const LOGGER:ILogger = getClassLogger(ViewerWindowManager);
|
||||||
|
|
||||||
|
private var viewWindow:WebRTCDesktopViewWindow;
|
||||||
|
private var shareWindow:WebRTCDesktopPublishWindow;
|
||||||
|
private var service:WebRTCDeskshareService;
|
||||||
|
private var isViewing:Boolean = false;
|
||||||
|
private var globalDispatcher:Dispatcher;
|
||||||
|
|
||||||
|
public function WebRTCViewerWindowManager(service:WebRTCDeskshareService) {
|
||||||
|
this.service = service;
|
||||||
|
globalDispatcher = new Dispatcher();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stopViewing():void {
|
||||||
|
if (isViewing) viewWindow.stopViewing();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function openWindow(window:IBbbModuleWindow):void{
|
||||||
|
var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
|
||||||
|
event.window = window;
|
||||||
|
globalDispatcher.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleViewWindowCloseEvent():void {
|
||||||
|
LOGGER.debug("ViewerWindowManager Received stop viewing command");
|
||||||
|
closeWindow(viewWindow);
|
||||||
|
isViewing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function closeWindow(window:IBbbModuleWindow):void {
|
||||||
|
var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
|
||||||
|
event.window = window;
|
||||||
|
globalDispatcher.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function startViewing(rtmp:String, videoWidth:Number, videoHeight:Number):void{
|
||||||
|
LOGGER.debug("ViewerWindowManager::startViewing");
|
||||||
|
|
||||||
|
viewWindow = new WebRTCDesktopViewWindow();
|
||||||
|
viewWindow.startVideo(rtmp, videoWidth, videoHeight);
|
||||||
|
openWindow(viewWindow);
|
||||||
|
isViewing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -43,6 +43,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|||||||
import org.bigbluebutton.modules.screenshare.events.ViewWindowEvent;
|
import org.bigbluebutton.modules.screenshare.events.ViewWindowEvent;
|
||||||
import org.bigbluebutton.modules.screenshare.managers.ScreenshareManager;
|
import org.bigbluebutton.modules.screenshare.managers.ScreenshareManager;
|
||||||
import org.bigbluebutton.modules.screenshare.services.red5.ConnectionEvent;
|
import org.bigbluebutton.modules.screenshare.services.red5.ConnectionEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.UseJavaModeCommand;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.DeskshareToolbarEvent;
|
||||||
]]>
|
]]>
|
||||||
</mx:Script>
|
</mx:Script>
|
||||||
<EventHandlers type="{FlexEvent.PREINITIALIZE}">
|
<EventHandlers type="{FlexEvent.PREINITIALIZE}">
|
||||||
@ -110,5 +112,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|||||||
<MethodInvoker generator="{ScreenshareManager}" method="handleStartModuleEvent" arguments="{event.module}"/>
|
<MethodInvoker generator="{ScreenshareManager}" method="handleStartModuleEvent" arguments="{event.module}"/>
|
||||||
</EventHandlers>
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{UseJavaModeCommand.USE_JAVA_MODE}">
|
||||||
|
<MethodInvoker generator="{ScreenshareManager}" method="handleUseJavaModeCommand"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{DeskshareToolbarEvent.STOP}">
|
||||||
|
<MethodInvoker generator="{ScreenshareManager}" method="handleDeskshareToolbarStopEvent"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
</EventMap>
|
</EventMap>
|
||||||
|
@ -0,0 +1,133 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
|
||||||
|
Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<EventMap xmlns:mx="http://www.adobe.com/2006/mxml"
|
||||||
|
xmlns="http://mate.asfusion.com/">
|
||||||
|
|
||||||
|
<mx:Script>
|
||||||
|
<![CDATA[
|
||||||
|
import mx.events.FlexEvent;
|
||||||
|
|
||||||
|
import org.bigbluebutton.main.events.BBBEvent;
|
||||||
|
import org.bigbluebutton.main.events.MadePresenterEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.ModuleEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.ShareEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.UseJavaModeCommand;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.WebRTCShareWindowEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.WebRTCStreamEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.WebRTCViewStreamEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.WebRTCViewWindowEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.managers.WebRTCDeskshareManager;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.RequestToStartSharing;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.RequestToStopSharing;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.ShareStartRequestResponseEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.StartedViewingEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.StreamStartedEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.IsSharingScreenEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.services.red5.WebRTCConnectionEvent;
|
||||||
|
]]>
|
||||||
|
</mx:Script>
|
||||||
|
|
||||||
|
<EventHandlers type="{FlexEvent.PREINITIALIZE}">
|
||||||
|
<!--
|
||||||
|
The FlexEvent.PREINITIALIZE event is a good place for creating and initializing managers.
|
||||||
|
-->
|
||||||
|
<ObjectBuilder generator="{WebRTCDeskshareManager}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{ShareEvent.START_SHARING}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleStartSharingEvent" arguments="{false}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{BBBEvent.START_DESKSHARE}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleStartSharingEvent" arguments="{true}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{RequestToStartSharing.REQUEST_SHARE_START}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleRequestStartSharingEvent"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{RequestToStopSharing.REQUEST_SHARE_STOP}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleRequestStopSharingEvent"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{ShareStartRequestResponseEvent.SHARE_START_REQUEST_RESPONSE}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleShareStartRequestResponseEvent" arguments="{event}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleMadePresenterEvent" arguments="{event}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleMadeViewerEvent" arguments="{event}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{WebRTCStreamEvent.STOP}" >
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleStreamStoppedEvent"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{WebRTCViewStreamEvent.START}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleStreamStartEvent" arguments="{event}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{WebRTCViewStreamEvent.STOP}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleStreamStopEvent" arguments="{event}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{StreamStartedEvent.STREAM_STARTED}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleStreamStartedEvent" arguments="{event}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{IsSharingScreenEvent.IS_SCREENSHARING}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleIsSharingScreenEvent" arguments="{event}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{WebRTCShareWindowEvent.CLOSE}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleShareWindowCloseEvent"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{WebRTCConnectionEvent.SUCCESS}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleConnectionSuccessEvent"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{StartedViewingEvent.STARTED_VIEWING_EVENT}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleStartedViewingEvent" arguments="{event.stream}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{WebRTCViewWindowEvent.CLOSE}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleViewWindowCloseEvent"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{ModuleEvent.STOP}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleStopModuleEvent"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{ModuleEvent.START}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleStartModuleEvent" arguments="{event.module}"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
<EventHandlers type="{UseJavaModeCommand.USE_JAVA_MODE}">
|
||||||
|
<MethodInvoker generator="{WebRTCDeskshareManager}" method="handleUseJavaModeCommand"/>
|
||||||
|
</EventHandlers>
|
||||||
|
|
||||||
|
</EventMap>
|
@ -19,15 +19,17 @@
|
|||||||
package org.bigbluebutton.modules.screenshare.model
|
package org.bigbluebutton.modules.screenshare.model
|
||||||
{
|
{
|
||||||
import org.bigbluebutton.core.BBB;
|
import org.bigbluebutton.core.BBB;
|
||||||
|
|
||||||
public class ScreenshareOptions
|
public class ScreenshareOptions
|
||||||
{
|
{
|
||||||
[Bindable] public var showButton:Boolean = true;
|
[Bindable] public var showButton:Boolean = true;
|
||||||
[Bindable] public var autoStart:Boolean = false;
|
[Bindable] public var autoStart:Boolean = false;
|
||||||
[Bindable] public var autoFullScreen:Boolean = false;
|
[Bindable] public var autoFullScreen:Boolean = false;
|
||||||
[Bindable] public var baseTabIndex:int;
|
[Bindable] public var baseTabIndex:int;
|
||||||
|
[Bindable] public var useWebRTCIfAvailable:Boolean = true;
|
||||||
|
[Bindable] public var chromeExtensionKey:String = null;
|
||||||
[Bindable] public var helpUrl:String;
|
[Bindable] public var helpUrl:String;
|
||||||
|
|
||||||
public function parseOptions():void {
|
public function parseOptions():void {
|
||||||
var vxml:XML = BBB.getConfigForModule("ScreenshareModule");
|
var vxml:XML = BBB.getConfigForModule("ScreenshareModule");
|
||||||
if (vxml != null) {
|
if (vxml != null) {
|
||||||
@ -44,7 +46,13 @@ package org.bigbluebutton.modules.screenshare.model
|
|||||||
baseTabIndex = 201;
|
baseTabIndex = 201;
|
||||||
}
|
}
|
||||||
if (vxml.@showButton != undefined){
|
if (vxml.@showButton != undefined){
|
||||||
showButton = (vxml.@showButton.toString().toUpperCase() == "TRUE") ? true : false;
|
showButton = (vxml.@showButton.toString().toUpperCase() == "TRUE") ? true : false;
|
||||||
|
}
|
||||||
|
if (vxml.@useWebRTCIfAvailable != undefined) {
|
||||||
|
useWebRTCIfAvailable = (vxml.@useWebRTCIfAvailable.toString().toUpperCase() == "TRUE") ? true : false;
|
||||||
|
}
|
||||||
|
if (vxml.@chromeExtensionKey != undefined) {
|
||||||
|
chromeExtensionKey = vxml.@chromeExtensionKey.toString();
|
||||||
}
|
}
|
||||||
if (vxml.@help != undefined){
|
if (vxml.@help != undefined){
|
||||||
helpUrl = vxml.@help;
|
helpUrl = vxml.@help;
|
||||||
@ -52,4 +60,4 @@ package org.bigbluebutton.modules.screenshare.model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.bigbluebutton.modules.screenshare.services
|
||||||
|
{
|
||||||
|
import com.asfusion.mate.events.Dispatcher;
|
||||||
|
|
||||||
|
import flash.net.NetConnection;
|
||||||
|
|
||||||
|
import org.as3commons.logging.api.ILogger;
|
||||||
|
import org.as3commons.logging.api.getClassLogger;
|
||||||
|
import org.bigbluebutton.modules.screenshare.services.red5.WebRTCConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DeskShareProxy communicates with the Red5 deskShare server application
|
||||||
|
* @author Snap
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class WebRTCDeskshareService
|
||||||
|
{
|
||||||
|
private static const LOGGER:ILogger = getClassLogger(ScreenshareService);
|
||||||
|
|
||||||
|
private var conn:WebRTCConnection;
|
||||||
|
|
||||||
|
private var module:ScreenshareModule;
|
||||||
|
private var dispatcher:Dispatcher;
|
||||||
|
|
||||||
|
private var uri:String;
|
||||||
|
private var room:String;
|
||||||
|
|
||||||
|
public function WebRTCDeskshareService() {
|
||||||
|
this.dispatcher = new Dispatcher();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleStartModuleEvent(module:ScreenshareModule):void {
|
||||||
|
LOGGER.debug("Deskshare Module starting");
|
||||||
|
this.module = module;
|
||||||
|
connect(module.uri, module.getRoom());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connect(uri:String, room:String):void {
|
||||||
|
this.uri = uri;
|
||||||
|
this.room = room;
|
||||||
|
LOGGER.debug("Deskshare Service connecting to {0}", [uri]);
|
||||||
|
conn = new WebRTCConnection(room); //to red5 deskshare
|
||||||
|
|
||||||
|
conn.setURI(uri);
|
||||||
|
conn.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConnection():NetConnection{
|
||||||
|
return conn.getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disconnect():void{
|
||||||
|
conn.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,323 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.bigbluebutton.modules.screenshare.services.red5
|
||||||
|
{
|
||||||
|
import com.asfusion.mate.events.Dispatcher;
|
||||||
|
|
||||||
|
import flash.events.AsyncErrorEvent;
|
||||||
|
import flash.events.NetStatusEvent;
|
||||||
|
import flash.events.SecurityErrorEvent;
|
||||||
|
import flash.events.TimerEvent;
|
||||||
|
import flash.net.NetConnection;
|
||||||
|
import flash.net.ObjectEncoding;
|
||||||
|
import flash.net.Responder;
|
||||||
|
import flash.utils.Timer;
|
||||||
|
|
||||||
|
import mx.utils.ObjectUtil;
|
||||||
|
|
||||||
|
import org.as3commons.logging.api.ILogger;
|
||||||
|
import org.as3commons.logging.api.getClassLogger;
|
||||||
|
import org.bigbluebutton.core.BBB;
|
||||||
|
import org.bigbluebutton.core.UsersUtil;
|
||||||
|
import org.bigbluebutton.core.managers.ReconnectionManager;
|
||||||
|
import org.bigbluebutton.main.events.BBBEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.WebRTCViewStreamEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.services.red5.WebRTCConnectionEvent;
|
||||||
|
|
||||||
|
public class WebRTCConnection {
|
||||||
|
private static const LOGGER:ILogger = getClassLogger(Connection);
|
||||||
|
|
||||||
|
private var nc:NetConnection;
|
||||||
|
private var uri:String;
|
||||||
|
private var retryTimer:Timer = null;
|
||||||
|
private var retryCount:int = 0;
|
||||||
|
private const MAX_RETRIES:int = 5;
|
||||||
|
private var responder:Responder;
|
||||||
|
private var width:Number;
|
||||||
|
private var height:Number;
|
||||||
|
private var room:String;
|
||||||
|
private var logoutOnUserCommand:Boolean = false;
|
||||||
|
private var reconnecting:Boolean = false;
|
||||||
|
private var wasPresenterBeforeDisconnect:Boolean = false;
|
||||||
|
|
||||||
|
private var dispatcher:Dispatcher = new Dispatcher();
|
||||||
|
|
||||||
|
public function WebRTCConnection(room:String) {
|
||||||
|
this.room = room;
|
||||||
|
|
||||||
|
responder = new Responder(
|
||||||
|
function(result:Object):void {
|
||||||
|
if (result != null && (result.publishing as Boolean)){
|
||||||
|
width = result.width as Number;
|
||||||
|
height = result.height as Number;
|
||||||
|
LOGGER.debug("Desk Share stream is streaming [{0},{1}]", [width, height]);
|
||||||
|
var event:WebRTCViewStreamEvent = new WebRTCViewStreamEvent(WebRTCViewStreamEvent.START);
|
||||||
|
event.videoWidth = width;
|
||||||
|
event.videoHeight = height;
|
||||||
|
dispatcher.dispatchEvent(event); //TODO why?
|
||||||
|
} else {
|
||||||
|
LOGGER.debug("No screenshare stream being published");
|
||||||
|
var connEvent:WebRTCConnectionEvent = new WebRTCConnectionEvent();
|
||||||
|
connEvent.status = WebRTCConnectionEvent.NO_DESKSHARE_STREAM;
|
||||||
|
dispatcher.dispatchEvent(connEvent); //TODO why?
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(status:Object):void{
|
||||||
|
var checkFailedEvent:WebRTCConnectionEvent = new WebRTCConnectionEvent();
|
||||||
|
checkFailedEvent.status = WebRTCConnectionEvent.FAIL_CHECK_FOR_DESKSHARE_STREAM;
|
||||||
|
dispatcher.dispatchEvent(checkFailedEvent);
|
||||||
|
LOGGER.debug("Error while trying to call remote mathod on server");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connect(retry:Boolean = false):void {
|
||||||
|
nc = new NetConnection();
|
||||||
|
nc.proxyType = "best";
|
||||||
|
nc.objectEncoding = ObjectEncoding.AMF0;
|
||||||
|
nc.client = this;
|
||||||
|
|
||||||
|
nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, debugAsyncErrorHandler);
|
||||||
|
nc.addEventListener(NetStatusEvent.NET_STATUS, debugNetStatusHandler);
|
||||||
|
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
|
||||||
|
nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
|
||||||
|
|
||||||
|
if (getURI().length == 0){
|
||||||
|
LOGGER.error("please provide a valid URI connection string. URI Connection String missing");
|
||||||
|
return;
|
||||||
|
} else if (nc.connected){
|
||||||
|
LOGGER.error("You are already connected to {0}", [getURI()]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.debug("Trying to connect to [{0}] retry=[{1}]", [getURI(), retry]);
|
||||||
|
if (! (retryCount > 0)) {
|
||||||
|
var ce:WebRTCConnectionEvent = new WebRTCConnectionEvent();
|
||||||
|
ce.status = WebRTCConnectionEvent.CONNECTING;
|
||||||
|
|
||||||
|
dispatcher.dispatchEvent(ce);
|
||||||
|
}
|
||||||
|
|
||||||
|
nc.connect(getURI(), UsersUtil.getInternalMeetingID());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function connectTimeoutHandler(e:TimerEvent):void {
|
||||||
|
LOGGER.debug("Connection attempt to [{0}] timedout. Retrying.", [getURI()]);
|
||||||
|
retryTimer.stop();
|
||||||
|
retryTimer = null;
|
||||||
|
|
||||||
|
nc.close();
|
||||||
|
nc = null;
|
||||||
|
|
||||||
|
var ce:WebRTCConnectionEvent = new WebRTCConnectionEvent();;
|
||||||
|
|
||||||
|
retryCount++;
|
||||||
|
if (retryCount < MAX_RETRIES) {
|
||||||
|
ce.status = WebRTCConnectionEvent.CONNECTING_RETRY;
|
||||||
|
ce.retryAttempts = retryCount;
|
||||||
|
dispatcher.dispatchEvent(ce);
|
||||||
|
|
||||||
|
connect(false);
|
||||||
|
} else {
|
||||||
|
ce.status = WebRTCConnectionEvent.CONNECTING_MAX_RETRY;
|
||||||
|
dispatcher.dispatchEvent(ce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close():void{
|
||||||
|
nc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setURI(p_URI:String):void{
|
||||||
|
uri = p_URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURI():String{
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onBWCheck(... rest):Number {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onBWDone(... rest):void {
|
||||||
|
var p_bw:Number;
|
||||||
|
if (rest.length > 0) p_bw = rest[0];
|
||||||
|
// your application should do something here
|
||||||
|
// when the bandwidth check is complete
|
||||||
|
LOGGER.debug("bandwidth = {0} Kbps.", [p_bw]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function netStatusHandler(event:NetStatusEvent):void {
|
||||||
|
LOGGER.debug("Connected to [" + getURI() + "]. [" + event.info.code + "]");
|
||||||
|
|
||||||
|
if (retryTimer) {
|
||||||
|
retryCount = 0;
|
||||||
|
LOGGER.debug("Cancelling retry timer.");
|
||||||
|
retryTimer.stop();
|
||||||
|
retryTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ce:WebRTCConnectionEvent = new WebRTCConnectionEvent();
|
||||||
|
|
||||||
|
switch(event.info.code){
|
||||||
|
case "NetConnection.Connect.Failed":
|
||||||
|
if (reconnecting) {
|
||||||
|
var attemptFailedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_CONNECTION_ATTEMPT_FAILED_EVENT);
|
||||||
|
attemptFailedEvent.payload.type = ReconnectionManager.DESKSHARE_CONNECTION;
|
||||||
|
dispatcher.dispatchEvent(attemptFailedEvent);
|
||||||
|
}
|
||||||
|
ce.status = WebRTCConnectionEvent.FAILED;
|
||||||
|
|
||||||
|
dispatcher.dispatchEvent(ce);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.Success":
|
||||||
|
ce.status = WebRTCConnectionEvent.SUCCESS;
|
||||||
|
if (reconnecting) {
|
||||||
|
reconnecting = false;
|
||||||
|
if (wasPresenterBeforeDisconnect) {
|
||||||
|
wasPresenterBeforeDisconnect = false;
|
||||||
|
// stopSharingDesktop(room, room) //TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
var attemptSucceeded:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_CONNECTION_ATTEMPT_SUCCEEDED_EVENT);
|
||||||
|
attemptSucceeded.payload.type = ReconnectionManager.DESKSHARE_CONNECTION;
|
||||||
|
dispatcher.dispatchEvent(attemptSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
// request desktop sharing info (as a late joiner)
|
||||||
|
LOGGER.debug("Sending [desktopSharing.requestDeskShareInfo] to server.");
|
||||||
|
var _nc:ConnectionManager = BBB.initConnectionManager();
|
||||||
|
_nc.sendMessage("desktopSharing.requestDeskShareInfo",
|
||||||
|
function(result:String):void { // On successful result
|
||||||
|
LOGGER.debug(result);
|
||||||
|
},
|
||||||
|
function(status:String):void { // status - On error occurred
|
||||||
|
LOGGER.error(status);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatcher.dispatchEvent(ce);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.Rejected":
|
||||||
|
ce.status = WebRTCConnectionEvent.REJECTED;
|
||||||
|
dispatcher.dispatchEvent(ce);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.Closed":
|
||||||
|
LOGGER.debug("Deskshare connection closed.");
|
||||||
|
ce.status = WebRTCConnectionEvent.CLOSED;
|
||||||
|
if (UsersUtil.amIPresenter()) {
|
||||||
|
// Let's keep our presenter status before disconnected. We can't
|
||||||
|
// tell the other user's to stop desktop sharing as our connection is broken. (ralam july 24, 2015)
|
||||||
|
wasPresenterBeforeDisconnect = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// stopViewing(); //TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!logoutOnUserCommand) {
|
||||||
|
reconnecting = true;
|
||||||
|
|
||||||
|
var disconnectedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_DISCONNECTED_EVENT);
|
||||||
|
disconnectedEvent.payload.type = ReconnectionManager.DESKSHARE_CONNECTION;
|
||||||
|
disconnectedEvent.payload.callback = connect;
|
||||||
|
disconnectedEvent.payload.callbackParameters = [];
|
||||||
|
dispatcher.dispatchEvent(disconnectedEvent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.InvalidApp":
|
||||||
|
ce.status = WebRTCConnectionEvent.INVALIDAPP;
|
||||||
|
dispatcher.dispatchEvent(ce);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.AppShutdown":
|
||||||
|
ce.status = WebRTCConnectionEvent.APPSHUTDOWN;
|
||||||
|
dispatcher.dispatchEvent(ce);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.NetworkChange":
|
||||||
|
LOGGER.info("Detected network change. User might be on a wireless and temporarily dropped connection. Doing nothing. Just making a note.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
// I dispatch DISCONNECTED incase someone just simply wants to know if we're not connected'
|
||||||
|
// rather than having to subscribe to the events individually
|
||||||
|
ce.status = WebRTCConnectionEvent.DISCONNECTED;
|
||||||
|
dispatcher.dispatchEvent(ce);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function securityErrorHandler(event:SecurityErrorEvent):void{
|
||||||
|
var ce:WebRTCConnectionEvent = new WebRTCConnectionEvent();
|
||||||
|
ce.status = WebRTCConnectionEvent.SECURITYERROR;
|
||||||
|
dispatcher.dispatchEvent(ce);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if anybody is publishing the stream for this room
|
||||||
|
* This method is useful for clients which have joined a room where somebody is already publishing
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function checkIfStreamIsPublishing(room: String):void{
|
||||||
|
LOGGER.debug("checking if desk share stream is publishing");
|
||||||
|
var event:WebRTCConnectionEvent = new WebRTCConnectionEvent();
|
||||||
|
event.status = WebRTCConnectionEvent.CHECK_FOR_DESKSHARE_STREAM;
|
||||||
|
dispatcher.dispatchEvent(event); // TODO anton send to akka-bbb-apps
|
||||||
|
|
||||||
|
nc.call("screenshare.checkIfStreamIsPublishing", responder, room);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disconnect():void{
|
||||||
|
logoutOnUserCommand = true;
|
||||||
|
if (nc != null) nc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connectionSuccessHandler():void{
|
||||||
|
LOGGER.debug("Successully connection to {0}", [uri]);
|
||||||
|
|
||||||
|
checkIfStreamIsPublishing(room);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function debugNetStatusHandler(e:NetStatusEvent):void {
|
||||||
|
LOGGER.debug("netStatusHandler target={0} info={1}", [e.target, ObjectUtil.toString(e.info)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function debugAsyncErrorHandler(e:AsyncErrorEvent):void {
|
||||||
|
LOGGER.debug("asyncErrorHandler target={0} info={1}", [e.target, e.text]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConnection():NetConnection{
|
||||||
|
return nc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connectionFailedHandler(e:WebRTCConnectionEvent):void{
|
||||||
|
LOGGER.error("connection failed to {0} with message {1}", [uri, e.toString()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connectionRejectedHandler(e:WebRTCConnectionEvent):void{
|
||||||
|
LOGGER.error("connection rejected to {0} with message {1}", [uri, e.toString()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.bigbluebutton.modules.screenshare.services.red5
|
||||||
|
{
|
||||||
|
import flash.events.Event;
|
||||||
|
|
||||||
|
public class WebRTCConnectionEvent extends Event {
|
||||||
|
public static const DESKSHARE_CONNECTION_EVENT:String = "webrtcDeskshare connection event";
|
||||||
|
|
||||||
|
public static const SUCCESS:String = "connection success";
|
||||||
|
public static const FAILED:String = "connection failed";
|
||||||
|
public static const CLOSED:String = "connection closed";
|
||||||
|
public static const REJECTED:String = "connection rejected";
|
||||||
|
public static const INVALIDAPP:String = "connection invalidApp";
|
||||||
|
public static const APPSHUTDOWN:String = "connection appShutdown";
|
||||||
|
public static const SECURITYERROR:String = "connection securityError";
|
||||||
|
public static const DISCONNECTED:String = "connection disconnected";
|
||||||
|
public static const CONNECTING:String = "connection connecting";
|
||||||
|
public static const CONNECTING_RETRY:String = "connection retry";
|
||||||
|
public static const CONNECTING_MAX_RETRY:String = "connection max retry";
|
||||||
|
public static const CHECK_FOR_DESKSHARE_STREAM:String = "connection check webrtcDeskshare publishing";
|
||||||
|
public static const NO_DESKSHARE_STREAM:String = "connection webrtcDeskshare publishing";
|
||||||
|
public static const FAIL_CHECK_FOR_DESKSHARE_STREAM:String = "connection failed check webrtcDeskshare publishing";
|
||||||
|
|
||||||
|
public var status:String = "";
|
||||||
|
|
||||||
|
public var retryAttempts:int = 0;
|
||||||
|
|
||||||
|
public function WebRTCConnectionEvent():void {
|
||||||
|
super(DESKSHARE_CONNECTION_EVENT, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.bigbluebutton.modules.screenshare.utils
|
||||||
|
{
|
||||||
|
import flash.external.ExternalInterface;
|
||||||
|
import org.bigbluebutton.core.BBB;
|
||||||
|
import flash.system.Capabilities;
|
||||||
|
import org.as3commons.logging.api.getClassLogger;
|
||||||
|
import org.as3commons.logging.api.ILogger;
|
||||||
|
|
||||||
|
public class BrowserCheck {
|
||||||
|
private static const LOGGER:ILogger = getClassLogger(BrowserCheck);
|
||||||
|
|
||||||
|
public static function isChrome42OrHigher():Boolean {
|
||||||
|
var browser:Array = ExternalInterface.call("determineBrowser");
|
||||||
|
return ((browser[0] == "Chrome") && (parseInt(browser[1]) >= 42));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isUsingLessThanChrome38OnMac():Boolean {
|
||||||
|
var browser:Array = ExternalInterface.call("determineBrowser");
|
||||||
|
return ((browser[0] == "Chrome") && (parseInt(browser[1]) <= 38) && (Capabilities.os.indexOf("Mac") >= 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isWebRTCSupported():Boolean {
|
||||||
|
/*LOGGER.debug("isWebRTCSupported - ExternalInterface.available=[{0}], isWebRTCAvailable=[{1}]", [ExternalInterface.available, ExternalInterface.call("isWebRTCAvailable")]);*/
|
||||||
|
return (ExternalInterface.available && ExternalInterface.call("isWebRTCAvailable"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isUsingEdgePluginUnsupported():Boolean {
|
||||||
|
var browser:Array = ExternalInterface.call("determineBrowser");
|
||||||
|
/* Currently no browser version of Edge supports plugins */
|
||||||
|
return browser[0] == "Edge";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isChrome():Boolean {
|
||||||
|
var browser:Array = ExternalInterface.call("determineBrowser");
|
||||||
|
return browser[0] == "Chrome";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isFirefox():Boolean {
|
||||||
|
var browser:Array = ExternalInterface.call("determineBrowser");
|
||||||
|
return browser[0] == "Firefox";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,384 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
|
||||||
|
Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<dspub:CustomMdiWindow
|
||||||
|
xmlns:mx="http://www.adobe.com/2006/mxml"
|
||||||
|
implements="org.bigbluebutton.common.IBbbModuleWindow"
|
||||||
|
xmlns:mate="http://mate.asfusion.com/"
|
||||||
|
xmlns:dspub="org.bigbluebutton.common.*"
|
||||||
|
backgroundColor="#C0C0C0"
|
||||||
|
initialize="init()"
|
||||||
|
creationComplete="onCreationComplete()"
|
||||||
|
verticalScrollPolicy="off" horizontalScrollPolicy="off"
|
||||||
|
width="365" height="350"
|
||||||
|
title="{ResourceUtil.getInstance().getString('bbb.desktopPublish.title')}"
|
||||||
|
resizable="false">
|
||||||
|
|
||||||
|
<mate:Listener type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" method="onChangedPresenter" />
|
||||||
|
<mate:Listener type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}" method="onChangedPresenter" />
|
||||||
|
<mate:Listener type="{WebRTCViewStreamEvent.STOP}" method="closePublishWindow" />
|
||||||
|
<mate:Listener type="{LocaleChangeEvent.LOCALE_CHANGED}" method="localeChanged" />
|
||||||
|
<mate:Listener type="{StopSharingButtonEvent.STOP_SHARING}" method="stopSharingEvent" />
|
||||||
|
<mate:Listener type="{ShortcutEvent.REMOTE_FOCUS_DESKTOP}" method="remoteFocus" />
|
||||||
|
|
||||||
|
|
||||||
|
<mx:Script>
|
||||||
|
<![CDATA[
|
||||||
|
import com.asfusion.mate.events.Dispatcher;
|
||||||
|
|
||||||
|
import mx.core.UIComponent;
|
||||||
|
|
||||||
|
import org.as3commons.logging.api.ILogger;
|
||||||
|
import org.as3commons.logging.api.getClassLogger;
|
||||||
|
import org.bigbluebutton.common.IBbbModuleWindow;
|
||||||
|
import org.bigbluebutton.common.Images;
|
||||||
|
import org.bigbluebutton.common.events.LocaleChangeEvent;
|
||||||
|
import org.bigbluebutton.main.events.BBBEvent;
|
||||||
|
import org.bigbluebutton.main.events.MadePresenterEvent;
|
||||||
|
import org.bigbluebutton.main.events.ShortcutEvent;
|
||||||
|
import org.bigbluebutton.main.views.MainCanvas;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.WebRTCShareWindowEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.StopSharingButtonEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.WebRTCStreamEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.WebRTCViewStreamEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.model.ScreenshareOptions;
|
||||||
|
import org.bigbluebutton.modules.screenshare.services.red5.WebRTCConnectionEvent;
|
||||||
|
import org.bigbluebutton.util.i18n.ResourceUtil;
|
||||||
|
import org.bigbluebutton.main.api.JSLog;
|
||||||
|
|
||||||
|
private static const LOGGER:ILogger = getClassLogger(WebRTCDesktopPublishWindow);
|
||||||
|
|
||||||
|
public static const SCALE:Number = 5;
|
||||||
|
private static const VID_HEIGHT_PAD:Number = 73;
|
||||||
|
private static const VID_WIDTH_PAD:Number = 6;
|
||||||
|
|
||||||
|
private var images:Images = new Images();
|
||||||
|
[Bindable] public var bbbLogo:Class = images.bbb_logo;
|
||||||
|
|
||||||
|
private var connection:NetConnection;
|
||||||
|
private var uri:String;
|
||||||
|
private var useTLS:Boolean;
|
||||||
|
private var room:String;
|
||||||
|
private var streaming:Boolean = false;
|
||||||
|
|
||||||
|
private var video:Video;
|
||||||
|
private var ns:NetStream;
|
||||||
|
[Bindable] private var videoHolder:UIComponent;
|
||||||
|
private var stream:String;
|
||||||
|
private var videoHeight:Number;
|
||||||
|
private var videoWidth:Number;
|
||||||
|
private var captureHeight:Number = Capabilities.screenResolutionY;
|
||||||
|
private var captureWidth:Number = Capabilities.screenResolutionX;
|
||||||
|
private var autoStart:Boolean = false;
|
||||||
|
private var globalDispatcher:Dispatcher = new Dispatcher();
|
||||||
|
|
||||||
|
[Bindable] private var dsOptions:ScreenshareOptions;
|
||||||
|
|
||||||
|
private function init():void {
|
||||||
|
dsOptions = new ScreenshareOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onCreationComplete():void {
|
||||||
|
windowControls.maximizeRestoreBtn.enabled = false;
|
||||||
|
|
||||||
|
setCurrentState("dispFullRegionControlBar"); //TODO ANTON
|
||||||
|
resourcesChanged();
|
||||||
|
|
||||||
|
titleBarOverlay.tabIndex = dsOptions.baseTabIndex;
|
||||||
|
titleBarOverlay.focusEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function remoteFocus(e:ShortcutEvent):void{
|
||||||
|
focusManager.setFocus(minimizeBtn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get defaultWidth():int{
|
||||||
|
return this.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get defaultHeight():int{
|
||||||
|
return this.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set defaultHeight(height:int):void{
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set defaultWidth(width:int):void{
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrefferedPosition():String{
|
||||||
|
return MainCanvas.DESKTOP_SHARING_PUBLISH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implement resizeable interface.
|
||||||
|
*/
|
||||||
|
public function resetWidthAndHeight():void{/* do nothing */}
|
||||||
|
|
||||||
|
public function initWindow(connection:NetConnection, uri:String, useTLS:Boolean , room:String, autoStart:Boolean, autoFullScreen:Boolean):void {
|
||||||
|
this.connection = connection;
|
||||||
|
this.uri = uri;
|
||||||
|
this.useTLS = useTLS;
|
||||||
|
this.room = room;
|
||||||
|
this.autoStart = autoStart;
|
||||||
|
/*if(autoFullScreen)
|
||||||
|
shareScreen(true);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shareScreen(fullScreen:Boolean):void {
|
||||||
|
LOGGER.debug("Calling shareScreen");
|
||||||
|
startSharing(connection, uri, useTLS , room, fullScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function startSharing(connection:NetConnection, uri:String , useTLS:Boolean , room:String, fullScreen:Boolean):void {
|
||||||
|
var captureX:Number = 0;
|
||||||
|
var captureY:Number = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stopSharing():void{
|
||||||
|
if (streaming) {
|
||||||
|
stopStream();
|
||||||
|
var streamEvent:WebRTCStreamEvent = new WebRTCStreamEvent(WebRTCStreamEvent.STOP);
|
||||||
|
dispatchEvent(streamEvent);
|
||||||
|
}
|
||||||
|
streaming = false;
|
||||||
|
closeWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stopSharingEvent(evt:StopSharingButtonEvent):void{
|
||||||
|
JSLog.warn("stopSharingEvent WebRTCDesktopPublishWindow.mxml", {});
|
||||||
|
stopSharing();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO make this function private and trigger it via message
|
||||||
|
public function startVideo(rtmp:String, videoWidth:Number, videoHeight:Number):void {
|
||||||
|
var myArray :Array = rtmp.split('/');
|
||||||
|
var meetingUrl:String = rtmp.substring(0, rtmp.lastIndexOf('/'));
|
||||||
|
stream = rtmp.substring(rtmp.lastIndexOf('/')+1, rtmp.length);
|
||||||
|
LOGGER.debug("WebRTCDesktopPublishWindow::startVideo meetingurl=[{0}] and stream=[{1}]",[meetingUrl, stream]);
|
||||||
|
|
||||||
|
JSLog.warn("WebRTCDesktopPublishWindow::startVideo meetingurl= ",meetingUrl);
|
||||||
|
JSLog.warn("WebRTCDesktopPublishWindow::startVideo stream=", stream);
|
||||||
|
|
||||||
|
|
||||||
|
connection = new NetConnection();
|
||||||
|
connection.proxyType = "best";
|
||||||
|
connection.objectEncoding = ObjectEncoding.AMF0;
|
||||||
|
connection.client = this;
|
||||||
|
|
||||||
|
connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
|
||||||
|
connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
|
||||||
|
connection.connect(meetingUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function netStatusHandler(event:NetStatusEvent):void {
|
||||||
|
var ce:WebRTCConnectionEvent = new WebRTCConnectionEvent();
|
||||||
|
LOGGER.debug("netStatusHandler [{0}]",[event.info.code]);
|
||||||
|
switch(event.info.code){
|
||||||
|
case "NetConnection.Connect.Failed":
|
||||||
|
ce.status = WebRTCConnectionEvent.FAILED;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.Success":
|
||||||
|
ce.status = WebRTCConnectionEvent.SUCCESS;
|
||||||
|
startPreviewStream(stream, videoWidth, videoHeight);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.Rejected":
|
||||||
|
ce.status = WebRTCConnectionEvent.REJECTED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.Closed":
|
||||||
|
trace("Deskshare connection closed.");
|
||||||
|
ce.status = WebRTCConnectionEvent.CLOSED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.InvalidApp":
|
||||||
|
ce.status = WebRTCConnectionEvent.INVALIDAPP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.AppShutdown":
|
||||||
|
ce.status = WebRTCConnectionEvent.APPSHUTDOWN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.NetworkChange":
|
||||||
|
trace("Detected network change. User might be on a wireless and " +
|
||||||
|
"temporarily dropped connection. Doing nothing. Just making a note.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function securityErrorHandler(event:SecurityErrorEvent):void {
|
||||||
|
LOGGER.debug("ERROR WebRTCDesktopPublishWindow::securityErrorHandler ");
|
||||||
|
}
|
||||||
|
|
||||||
|
private function startPreviewStream(streamName:String, capWidth:Number, capHeight:Number):void{
|
||||||
|
streaming = true;
|
||||||
|
|
||||||
|
videoHolder = new UIComponent();
|
||||||
|
|
||||||
|
var vidW:Number = captureWidth;
|
||||||
|
var vidH:Number = captureHeight;
|
||||||
|
|
||||||
|
// Don't scale if capture dimension is smaller than window.
|
||||||
|
if((captureWidth > this.width - VID_WIDTH_PAD) && (captureHeight < this.height - VID_HEIGHT_PAD)){
|
||||||
|
vidW = this.width - VID_WIDTH_PAD;
|
||||||
|
vidH = (captureHeight / captureWidth) * vidW;
|
||||||
|
}
|
||||||
|
else if( ((captureWidth < this.width - VID_WIDTH_PAD) && (captureHeight > this.height - VID_HEIGHT_PAD))
|
||||||
|
|| ((captureWidth > this.width - VID_WIDTH_PAD) && (captureHeight > this.height - VID_HEIGHT_PAD)) ){
|
||||||
|
vidH = this.height - VID_HEIGHT_PAD;
|
||||||
|
vidW = (captureWidth / captureHeight) * vidH;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
vidW = captureWidth;
|
||||||
|
vidH = captureHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.debug("webrtcDeskshare preview[{0},{1}][{2},{3}]", [captureWidth, captureHeight, vidW, vidH]);
|
||||||
|
video = new Video(vidW, vidH);
|
||||||
|
video.width = vidW;
|
||||||
|
video.height = vidH;
|
||||||
|
videoHolder.width = vidW;
|
||||||
|
videoHolder.height = vidH;
|
||||||
|
video.x = videoHolder.x = (this.width - VID_WIDTH_PAD - vidW) / 2;
|
||||||
|
video.y = videoHolder.y = (this.height - VID_HEIGHT_PAD - vidH) / 2;
|
||||||
|
|
||||||
|
videoHolder.addChild(video);
|
||||||
|
this.addChild(videoHolder);
|
||||||
|
|
||||||
|
ns = new NetStream(connection);
|
||||||
|
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
|
||||||
|
ns.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus );
|
||||||
|
ns.client = this;
|
||||||
|
ns.bufferTime = 0;
|
||||||
|
ns.receiveVideo(true);
|
||||||
|
ns.receiveAudio(false);
|
||||||
|
video.attachNetStream(ns);
|
||||||
|
|
||||||
|
ns.play(stream);
|
||||||
|
|
||||||
|
btnClosePublish.enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function stopStream():void{
|
||||||
|
streaming = false;
|
||||||
|
captureHeight = Capabilities.screenResolutionY;
|
||||||
|
captureWidth = Capabilities.screenResolutionX;
|
||||||
|
ns.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onAsyncError(e:AsyncErrorEvent):void{
|
||||||
|
LOGGER.debug("VIdeoWindow::asyncerror {0}", [e.toString()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onNetStatus(e:NetStatusEvent):void{
|
||||||
|
switch(e.info.code){
|
||||||
|
case "NetStream.Publish.Start":
|
||||||
|
LOGGER.debug("NetStream.Publish.Start for broadcast stream {0}", [stream]);
|
||||||
|
break;
|
||||||
|
case "NetStream.Play.UnpublishNotify":
|
||||||
|
LOGGER.debug("NetStream.Play.UnpublishNotify for broadcast stream {0}", [stream]);
|
||||||
|
stopSharing();
|
||||||
|
break;
|
||||||
|
case "NetStream.Play.Start":
|
||||||
|
LOGGER.debug("Netstatus: {0}", [e.info.code]);
|
||||||
|
globalDispatcher.dispatchEvent(new BBBEvent(BBBEvent.DESKSHARE_STARTED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onChangedPresenter(e:Event):void{
|
||||||
|
stopSharing();
|
||||||
|
closeWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function closeWindow():void {
|
||||||
|
// LOGGER.debug("Calling stopApplet in closeWindow()");
|
||||||
|
dispatchEvent(new WebRTCShareWindowEvent(WebRTCShareWindowEvent.CLOSE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Override the close handler. We want the Event Map to send a message to
|
||||||
|
* the MDIManager to close this window;
|
||||||
|
*/
|
||||||
|
override public function close(event:MouseEvent = null):void {
|
||||||
|
stopSharing();
|
||||||
|
closeWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected function resourcesChanged():void{
|
||||||
|
super.resourcesChanged();
|
||||||
|
this.title = ResourceUtil.getInstance().getString('bbb.desktopPublish.title');
|
||||||
|
|
||||||
|
if (titleBarOverlay != null) {
|
||||||
|
titleBarOverlay.accessibilityName = ResourceUtil.getInstance().getString('bbb.desktopPublish.title');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowControls != null) {
|
||||||
|
minimizeBtn.toolTip = ResourceUtil.getInstance().getString('bbb.desktopPublish.minimizeBtn.toolTip');
|
||||||
|
minimizeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopPublish.minimizeBtn.accessibilityName");
|
||||||
|
|
||||||
|
maximizeRestoreBtn.toolTip = ResourceUtil.getInstance().getString('bbb.desktopPublish.maximizeRestoreBtn.toolTip');
|
||||||
|
maximizeRestoreBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopPublish.maximizeRestoreBtn.accessibilityName");
|
||||||
|
|
||||||
|
closeBtn.toolTip = ResourceUtil.getInstance().getString('bbb.desktopPublish.closeBtn.toolTip');
|
||||||
|
closeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopPublish.closeBtn.accessibilityName");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function localeChanged(e:Event):void{
|
||||||
|
resourcesChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function closePublishWindow(event:WebRTCViewStreamEvent):void{
|
||||||
|
stopStream();
|
||||||
|
closeWindow();
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</mx:Script>
|
||||||
|
|
||||||
|
<dspub:TabIndexer startIndex="{dsOptions.baseTabIndex + 1}"
|
||||||
|
tabIndices="{[minimizeBtn, maximizeRestoreBtn, closeBtn, btnClosePublish]}"/>
|
||||||
|
<dspub:states>
|
||||||
|
<mx:State name="dispFullRegionControlBar">
|
||||||
|
<mx:AddChild>
|
||||||
|
<mx:ControlBar id="fullRegionBottomBar">
|
||||||
|
<mx:VBox width="100%" height="100%" horizontalAlign="center">
|
||||||
|
<mx:HBox horizontalAlign="center">
|
||||||
|
<mx:Button id="btnClosePublish"
|
||||||
|
toolTip="{ResourceUtil.getInstance().getString('bbb.desktopPublish.stop.tooltip')}"
|
||||||
|
label="{ResourceUtil.getInstance().getString('bbb.desktopPublish.stop.label')}"
|
||||||
|
visible="true"
|
||||||
|
enabled="false"
|
||||||
|
click="stopSharing()" />
|
||||||
|
</mx:HBox>
|
||||||
|
</mx:VBox>
|
||||||
|
</mx:ControlBar>
|
||||||
|
</mx:AddChild>
|
||||||
|
</mx:State>
|
||||||
|
</dspub:states>
|
||||||
|
|
||||||
|
</dspub:CustomMdiWindow>
|
@ -0,0 +1,388 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
|
||||||
|
Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
|
||||||
|
xmlns:mx="http://www.adobe.com/2006/mxml"
|
||||||
|
xmlns:common="org.bigbluebutton.common.*"
|
||||||
|
width="600" height="400"
|
||||||
|
initialize="init()"
|
||||||
|
implements="org.bigbluebutton.common.IBbbModuleWindow"
|
||||||
|
xmlns:mate="http://mate.asfusion.com/"
|
||||||
|
title="{ResourceUtil.getInstance().getString('bbb.desktopView.title')}"
|
||||||
|
showCloseButton="false"
|
||||||
|
resize="fitToWindow()" >
|
||||||
|
|
||||||
|
<mate:Listener type="{ViewStreamEvent.STOP}" method="onStopViewStreamEvent" />
|
||||||
|
<mate:Listener type="{LocaleChangeEvent.LOCALE_CHANGED}" method="localeChanged" />
|
||||||
|
|
||||||
|
<mx:Script>
|
||||||
|
<![CDATA[
|
||||||
|
import mx.core.UIComponent;
|
||||||
|
|
||||||
|
import flexlib.mdi.events.MDIWindowEvent;
|
||||||
|
|
||||||
|
import org.as3commons.logging.api.ILogger;
|
||||||
|
import org.as3commons.logging.api.getClassLogger;
|
||||||
|
import org.bigbluebutton.common.IBbbModuleWindow;
|
||||||
|
import org.bigbluebutton.common.Images;
|
||||||
|
import org.bigbluebutton.common.events.LocaleChangeEvent;
|
||||||
|
import org.bigbluebutton.main.views.MainCanvas;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.ViewStreamEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.events.ViewWindowEvent;
|
||||||
|
import org.bigbluebutton.modules.screenshare.model.ScreenshareOptions;
|
||||||
|
import org.bigbluebutton.util.i18n.ResourceUtil;
|
||||||
|
import org.bigbluebutton.modules.screenshare.services.red5.WebRTCConnectionEvent;
|
||||||
|
|
||||||
|
public static const LOG:String = "Deskshare::DesktopViewWindow - ";
|
||||||
|
private var screenHeight:Number = Capabilities.screenResolutionY;
|
||||||
|
private var screenWidth:Number = Capabilities.screenResolutionX;
|
||||||
|
|
||||||
|
private var images:Images = new Images();
|
||||||
|
[Bindable] public var fitToWidthIcon:Class = images.magnifier;
|
||||||
|
[Bindable] public var fitToActualSizeIcon:Class = images.mag_reset;
|
||||||
|
|
||||||
|
private var video:Video;
|
||||||
|
private var ns:NetStream;
|
||||||
|
private var videoHolder:UIComponent = new UIComponent();
|
||||||
|
private var stream:String;
|
||||||
|
private var videoHeight:Number;
|
||||||
|
private var videoWidth:Number;
|
||||||
|
|
||||||
|
private static const LOGGER:ILogger = getClassLogger(WebRTCDesktopViewWindow);
|
||||||
|
|
||||||
|
private static const VIDEO_WIDTH_PADDING:int = 7;
|
||||||
|
private static const VIDEO_HEIGHT_PADDING:int = 65;
|
||||||
|
|
||||||
|
// The following code block is to deal with a bug in FLexLib
|
||||||
|
// with MDI windows not responding well to being maximized
|
||||||
|
private var savedWindowWidth:Number;
|
||||||
|
private var savedWindowHeight:Number;
|
||||||
|
private var savedX:Number;
|
||||||
|
private var savedY:Number;
|
||||||
|
private var isMaximized:Boolean = false;
|
||||||
|
private var streamID:String;
|
||||||
|
private var nc:NetConnection;
|
||||||
|
|
||||||
|
[Bindable] private var baseIndex:int;
|
||||||
|
|
||||||
|
[Bindable] private var dsOptions:ScreenshareOptions;
|
||||||
|
|
||||||
|
private function init():void{
|
||||||
|
dsOptions = new ScreenshareOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function displayVideo():void{
|
||||||
|
videoHolder.addChild(video);
|
||||||
|
this.addChild(videoHolder);
|
||||||
|
videoHolder.percentWidth = 100;
|
||||||
|
videoHolder.percentHeight = 100;
|
||||||
|
addEventListener(MDIWindowEvent.RESIZE_END, onResizeEndEvent);
|
||||||
|
fitToActualSize();
|
||||||
|
maximize();
|
||||||
|
|
||||||
|
resourcesChanged();
|
||||||
|
|
||||||
|
titleBarOverlay.tabIndex = dsOptions.baseTabIndex;
|
||||||
|
minimizeBtn.tabIndex = baseIndex+1;
|
||||||
|
maximizeRestoreBtn.tabIndex = baseIndex+2;
|
||||||
|
closeBtn.tabIndex = baseIndex+3;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onResizeEndEvent(event:MDIWindowEvent):void {
|
||||||
|
if (event.window == this) {
|
||||||
|
fitToWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function startVideo(rtmp:String, width:Number, height:Number):void{
|
||||||
|
var videoURL:String;
|
||||||
|
|
||||||
|
// split rtmp extract the streamId
|
||||||
|
this.videoWidth = width;
|
||||||
|
this.videoHeight = height;
|
||||||
|
|
||||||
|
var myArray :Array = rtmp.split('/');
|
||||||
|
// myArray.forEach ( function ( item:*, i:int, arr:Array) : void { JSLog.debug("^^^^" + i +"aa=" + item, logData); } );
|
||||||
|
|
||||||
|
streamID = myArray[5]; // Grab the streamID from the end of the rtmp string
|
||||||
|
videoURL = rtmp.substring(0, rtmp.lastIndexOf('/'));
|
||||||
|
|
||||||
|
connect(videoURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connect(rtmpUrl: String):void {
|
||||||
|
nc = new NetConnection();
|
||||||
|
nc.proxyType = "best";
|
||||||
|
nc.objectEncoding = ObjectEncoding.AMF0;
|
||||||
|
nc.client = this;
|
||||||
|
|
||||||
|
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
|
||||||
|
nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
|
||||||
|
nc.connect(rtmpUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connectionSuccessHandler():void{
|
||||||
|
LOGGER.debug("SUCCESS DesktopViewWindow::connectionSuccessHandler SUCCESS" + videoHeight + videoWidth + streamID);
|
||||||
|
ns = new NetStream(nc);
|
||||||
|
ns.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus );
|
||||||
|
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
|
||||||
|
ns.client = this;
|
||||||
|
|
||||||
|
ns.bufferTime = 0;
|
||||||
|
ns.receiveVideo(true);
|
||||||
|
ns.receiveAudio(false);
|
||||||
|
|
||||||
|
video = new Video(videoWidth, videoHeight);
|
||||||
|
|
||||||
|
video.attachNetStream(ns);
|
||||||
|
ns.play(streamID);
|
||||||
|
displayVideo();
|
||||||
|
this.title = "Viewing Remote Desktop";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private function netStatusHandler(event:NetStatusEvent):void {
|
||||||
|
// trace(LOG + "Connected to [" + getURI() + "]. [" + event.info.code + "]");
|
||||||
|
var ce:WebRTCConnectionEvent = new WebRTCConnectionEvent();
|
||||||
|
|
||||||
|
switch(event.info.code){
|
||||||
|
case "NetConnection.Connect.Failed":
|
||||||
|
ce.status = WebRTCConnectionEvent.FAILED;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.Success":
|
||||||
|
ce.status = WebRTCConnectionEvent.SUCCESS;
|
||||||
|
connectionSuccessHandler();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.Rejected":
|
||||||
|
ce.status = WebRTCConnectionEvent.REJECTED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.Closed":
|
||||||
|
trace(LOG + "Deskshare connection closed.");
|
||||||
|
ce.status = WebRTCConnectionEvent.CLOSED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.InvalidApp":
|
||||||
|
ce.status = WebRTCConnectionEvent.INVALIDAPP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.AppShutdown":
|
||||||
|
ce.status = WebRTCConnectionEvent.APPSHUTDOWN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NetConnection.Connect.NetworkChange":
|
||||||
|
trace(LOG + "Detected network change. User might be on a wireless and temporarily dropped connection. Doing nothing. Just making a note.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function securityErrorHandler(event:SecurityErrorEvent):void {
|
||||||
|
LOGGER.debug("ERROR DesktopViewWindow::securityErrorHandler ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stopViewing():void {
|
||||||
|
ns.close();
|
||||||
|
closeWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onStopViewStreamEvent(event:ViewStreamEvent):void {
|
||||||
|
stopViewing();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function updateButtonsPosition():void {
|
||||||
|
if (this.width < bottomBar.width) {
|
||||||
|
bottomBar.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bottomBar.visible == false) {
|
||||||
|
bottomBar.y = bottomBar.x = 0;
|
||||||
|
} else {
|
||||||
|
bottomBar.y = (this.height - bottomBar.height) / 2;
|
||||||
|
bottomBar.x = (this.width - bottomBar.width) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onAsyncError(e:AsyncErrorEvent):void{
|
||||||
|
LOGGER.debug("VIdeoWindow::asyncerror {0}", [e.toString()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onNetStatus(e:NetStatusEvent):void{
|
||||||
|
LOGGER.debug("onNetStatus info={0}", [e.info.text]);
|
||||||
|
|
||||||
|
switch(e.info.code){
|
||||||
|
case "NetStream.Play.Start":
|
||||||
|
LOGGER.debug("NetStream.Publish.Start for broadcast stream {0}", [stream]);
|
||||||
|
LOGGER.debug("Dispatching start viewing event");
|
||||||
|
|
||||||
|
// TODO - do we want to know when a client has displayed ds view?
|
||||||
|
// var dispatcher: Dispatcher = new Dispatcher();
|
||||||
|
// var viewEvent:StartedViewingEvent = new StartedViewingEvent(StartedViewingEvent.STARTED_VIEWING_EVENT);
|
||||||
|
|
||||||
|
// viewEvent.stream = stream;
|
||||||
|
// dispatcher.dispatchEvent(viewEvent);
|
||||||
|
break;
|
||||||
|
case "NetStream.Play.UnpublishNotify":
|
||||||
|
LOGGER.debug("NetStream.Play.UnpublishNotify for broadcast stream {0}", [stream]);
|
||||||
|
stopViewing();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onBWCheck(... rest):Number {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onBWDone(... rest):void {
|
||||||
|
var p_bw:Number;
|
||||||
|
if (rest.length > 0) p_bw = rest[0];
|
||||||
|
// your application should do something here
|
||||||
|
// when the bandwidth check is complete
|
||||||
|
trace("bandwidth = " + p_bw + " Kbps.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrefferedPosition():String{
|
||||||
|
return MainCanvas.DESKTOP_SHARING_VIEW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resizes the desktop sharing video to fit to this window
|
||||||
|
*/
|
||||||
|
private function fitToWindow():void{
|
||||||
|
if (videoIsSmallerThanWindow()) {
|
||||||
|
fitWindowToVideo();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if we are displaying the actual size of the video
|
||||||
|
if (! btnActualSize.selected) {
|
||||||
|
fitVideoToWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fitVideoToWindow():void {
|
||||||
|
if (this.width < this.height) {
|
||||||
|
fitToWidthAndAdjustHeightToMaintainAspectRatio();
|
||||||
|
} else {
|
||||||
|
fitToHeightAndAdjustWidthToMaintainAspectRatio();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fitWindowToVideo():void {
|
||||||
|
video.width = videoWidth;
|
||||||
|
videoHolder.width = videoWidth;
|
||||||
|
video.height = videoHeight;
|
||||||
|
videoHolder.height = videoHeight;
|
||||||
|
this.height = videoHeight + VIDEO_HEIGHT_PADDING;
|
||||||
|
this.width = videoWidth + VIDEO_WIDTH_PADDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function videoIsSmallerThanWindow():Boolean {
|
||||||
|
return (videoHeight < this.height) && (videoWidth < this.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function fitToWidthAndAdjustHeightToMaintainAspectRatio():void {
|
||||||
|
video.width = this.width - VIDEO_WIDTH_PADDING;
|
||||||
|
videoHolder.width = video.width;
|
||||||
|
// Maintain aspect-ratio
|
||||||
|
video.height = (videoHeight * video.width) / videoWidth;
|
||||||
|
videoHolder.height = video.height;
|
||||||
|
this.height = video.height + VIDEO_HEIGHT_PADDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fitToHeightAndAdjustWidthToMaintainAspectRatio():void {
|
||||||
|
video.height = this.height - VIDEO_HEIGHT_PADDING;
|
||||||
|
videoHolder.height = video.height;
|
||||||
|
// Maintain aspect-ratio
|
||||||
|
video.width = (videoWidth * video.height) / videoHeight;
|
||||||
|
videoHolder.width = video.width;
|
||||||
|
this.width = video.width + VIDEO_WIDTH_PADDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resizes the desktop sharing video to actual video resolution
|
||||||
|
*/
|
||||||
|
private function fitToActualSize():void{
|
||||||
|
if (videoIsSmallerThanWindow()) {
|
||||||
|
fitWindowToVideo();
|
||||||
|
} else {
|
||||||
|
video.width = videoWidth;
|
||||||
|
videoHolder.width = videoWidth;
|
||||||
|
video.height = videoHeight;
|
||||||
|
videoHolder.height = videoHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function determineHowToDisplayVideo():void {
|
||||||
|
if (btnActualSize.selected) {
|
||||||
|
fitToActualSize();
|
||||||
|
btnActualSize.toolTip = ResourceUtil.getInstance().getString('bbb.desktopView.fitToWindow');
|
||||||
|
btnActualSize.label = ResourceUtil.getInstance().getString('bbb.desktopView.fitToWindow');
|
||||||
|
} else {
|
||||||
|
fitToWindow();
|
||||||
|
btnActualSize.toolTip = ResourceUtil.getInstance().getString('bbb.desktopView.actualSize');
|
||||||
|
btnActualSize.label = ResourceUtil.getInstance().getString('bbb.desktopView.actualSize');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function closeWindow():void {
|
||||||
|
dispatchEvent(new ViewWindowEvent(ViewWindowEvent.CLOSE));
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected function resourcesChanged():void{
|
||||||
|
super.resourcesChanged();
|
||||||
|
this.title = ResourceUtil.getInstance().getString('bbb.desktopView.title');
|
||||||
|
|
||||||
|
if (windowControls != null) {
|
||||||
|
minimizeBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.minimizeBtn.toolTip");
|
||||||
|
minimizeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopView.minimizeBtn.accessibilityName");
|
||||||
|
|
||||||
|
maximizeRestoreBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.maximizeRestoreBtn.toolTip");
|
||||||
|
maximizeRestoreBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopView.maximizeRestoreBtn.accessibilityName");
|
||||||
|
|
||||||
|
closeBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.closeBtn.toolTip");
|
||||||
|
closeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.desktopView.closeBtn.accessibilityName");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function localeChanged(e:Event):void{
|
||||||
|
resourcesChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
]]>
|
||||||
|
</mx:Script>
|
||||||
|
|
||||||
|
<common:TabIndexer startIndex="{dsOptions.baseTabIndex + 1}" tabIndices="{[minimizeBtn, maximizeRestoreBtn, closeBtn, btnActualSize]}"/>
|
||||||
|
|
||||||
|
<mx:HBox id="bottomBar" visible="true" height="30" horizontalAlign="center" paddingTop="0" paddingBottom="0" width="100%" >
|
||||||
|
<mx:Button id="btnActualSize" paddingTop="0" paddingBottom="0" styleName="deskshareControlButtonStyle"
|
||||||
|
toggle="true"
|
||||||
|
click="determineHowToDisplayVideo()"
|
||||||
|
selected="false"
|
||||||
|
height="90%"
|
||||||
|
label="{btnActualSize.selected ? ResourceUtil.getInstance().getString('bbb.desktopView.fitToWindow') : ResourceUtil.getInstance().getString('bbb.desktopView.actualSize')}"
|
||||||
|
toolTip="{btnActualSize.selected ? ResourceUtil.getInstance().getString('bbb.desktopView.fitToWindow') : ResourceUtil.getInstance().getString('bbb.desktopView.actualSize')}"/>
|
||||||
|
</mx:HBox>
|
||||||
|
</CustomMdiWindow>
|
@ -53,8 +53,8 @@ package org.bigbluebutton.modules.users.services
|
|||||||
import org.bigbluebutton.modules.present.events.RemovePresentationEvent;
|
import org.bigbluebutton.modules.present.events.RemovePresentationEvent;
|
||||||
import org.bigbluebutton.modules.present.events.UploadEvent;
|
import org.bigbluebutton.modules.present.events.UploadEvent;
|
||||||
import org.bigbluebutton.modules.users.events.MeetingMutedEvent;
|
import org.bigbluebutton.modules.users.events.MeetingMutedEvent;
|
||||||
import org.bigbluebutton.modules.deskshare.events.ViewStreamEvent;
|
import org.bigbluebutton.modules.screenshare.events.ViewStreamEvent;
|
||||||
import org.bigbluebutton.modules.deskshare.events.WebRTCViewStreamEvent;
|
import org.bigbluebutton.modules.screenshare.events.WebRTCViewStreamEvent;
|
||||||
import org.bigbluebutton.main.api.JSLog;
|
import org.bigbluebutton.main.api.JSLog;
|
||||||
import org.bigbluebutton.modules.users.events.MeetingMutedEvent;
|
import org.bigbluebutton.modules.users.events.MeetingMutedEvent;
|
||||||
|
|
||||||
@ -175,6 +175,8 @@ package org.bigbluebutton.modules.users.services
|
|||||||
|
|
||||||
private function handleDeskShareRTMPBroadcastNotification(msg:Object):void {
|
private function handleDeskShareRTMPBroadcastNotification(msg:Object):void {
|
||||||
LOGGER.debug("*** handleDeskShareRTMPBroadcastNotification **** \n", [msg]);
|
LOGGER.debug("*** handleDeskShareRTMPBroadcastNotification **** \n", [msg]);
|
||||||
|
JSLog.warn("*** handleDeskShareRTMPBroadcastNotification **** url=", msg.rtmpUrl);
|
||||||
|
JSLog.warn("*** handleDeskShareRTMPBroadcastNotification **** broadcasting=", msg.broadcasting);
|
||||||
|
|
||||||
var event:WebRTCViewStreamEvent;
|
var event:WebRTCViewStreamEvent;
|
||||||
if (msg.broadcasting) {
|
if (msg.broadcasting) {
|
||||||
|
@ -32,8 +32,9 @@ function loadLib(libname, success, fail) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const failCallback = function (cb) {
|
const failCallback = function (cb, issue) {
|
||||||
console.log(`failed to load lib - ${this}`);
|
console.error(`failed to load lib - ${this}`);
|
||||||
|
console.error(issue);
|
||||||
if (typeof (cb) == 'function' || cb instanceof Function) {
|
if (typeof (cb) == 'function' || cb instanceof Function) {
|
||||||
cb();
|
cb();
|
||||||
}
|
}
|
||||||
@ -49,12 +50,9 @@ Meteor.startup(() => {
|
|||||||
loadLib('bbblogger.js');
|
loadLib('bbblogger.js');
|
||||||
loadLib('jquery.json-2.4.min.js');
|
loadLib('jquery.json-2.4.min.js');
|
||||||
loadLib('jquery.FSRTC.js');
|
loadLib('jquery.FSRTC.js');
|
||||||
loadLib('jquery.verto.js', function () {
|
loadLib('jquery.verto.js');
|
||||||
loadLib('verto_extension.js');
|
loadLib('verto_extension.js');
|
||||||
});
|
|
||||||
|
|
||||||
loadLib('jquery.jsonrpcclient.js');
|
loadLib('jquery.jsonrpcclient.js');
|
||||||
loadLib('verto_extension_share.js');
|
|
||||||
|
|
||||||
render((
|
render((
|
||||||
<IntlProvider locale={locale} messages={messages}>
|
<IntlProvider locale={locale} messages={messages}>
|
||||||
|
@ -58,14 +58,6 @@ clientConfig.media = {};
|
|||||||
|
|
||||||
clientConfig.media.WebRTCHangupRetryInterval = 2000;
|
clientConfig.media.WebRTCHangupRetryInterval = 2000;
|
||||||
|
|
||||||
// IP address of FreeSWITCH server for use of mod_verto and WebRTC deshsharing
|
|
||||||
clientConfig.media.vertoServerAddress = 'HOST';
|
|
||||||
|
|
||||||
// Allows a caller to access a FreeSWITCH dialplan
|
|
||||||
clientConfig.media.freeswitchProfilePassword = '1234';
|
|
||||||
|
|
||||||
clientConfig.media.vertoPort = '8082';
|
|
||||||
|
|
||||||
// specifies whether to use SIP.js for audio over mod_verto
|
// specifies whether to use SIP.js for audio over mod_verto
|
||||||
clientConfig.media.useSIPAudio = true;
|
clientConfig.media.useSIPAudio = true;
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import Meetings from '/imports/api/meetings';
|
|||||||
import Auth from '/imports/ui/services/auth';
|
import Auth from '/imports/ui/services/auth';
|
||||||
import {callServer} from '/imports/ui/services/api';
|
import {callServer} from '/imports/ui/services/api';
|
||||||
import {clientConfig} from '/config';
|
import {clientConfig} from '/config';
|
||||||
import {createVertoUserName, joinVertoAudio} from '/imports/api/verto';
|
import {vertoExitAudio, vertoJoinListenOnly, vertoJoinMicrophone} from '/imports/api/verto';
|
||||||
|
|
||||||
let triedHangup = false;
|
let triedHangup = false;
|
||||||
|
|
||||||
@ -18,10 +18,9 @@ function amIListenOnly() {
|
|||||||
|
|
||||||
// Periodically check the status of the WebRTC call, when a call has been established attempt to
|
// Periodically check the status of the WebRTC call, when a call has been established attempt to
|
||||||
// hangup, retry if a call is in progress, send the leave voice conference message to BBB
|
// hangup, retry if a call is in progress, send the leave voice conference message to BBB
|
||||||
function exitVoiceCall(afterExitCall) {
|
function exitAudio(afterExitCall) {
|
||||||
if (!clientConfig.media.useSIPAudio) {
|
if (!clientConfig.media.useSIPAudio) {
|
||||||
window.leaveWebRTCVoiceConference_verto();
|
vertoExitAudio();
|
||||||
window.cur_call = null;
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// To be called when the hangup is initiated
|
// To be called when the hangup is initiated
|
||||||
@ -72,7 +71,7 @@ function exitVoiceCall(afterExitCall) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// join the conference. If listen only send the request to the server
|
// join the conference. If listen only send the request to the server
|
||||||
function joinVoiceCall(options) {
|
function joinVoiceCallSIP(options) {
|
||||||
const extension = getVoiceBridge();
|
const extension = getVoiceBridge();
|
||||||
console.log(options);
|
console.log(options);
|
||||||
if (clientConfig.media.useSIPAudio) {
|
if (clientConfig.media.useSIPAudio) {
|
||||||
@ -82,10 +81,6 @@ function joinVoiceCall(options) {
|
|||||||
console.log('Beginning WebRTC Conference Call');
|
console.log('Beginning WebRTC Conference Call');
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.isListenOnly) {
|
|
||||||
callServer('listenOnlyRequestToggle', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.BBB = {};
|
window.BBB = {};
|
||||||
window.BBB.getMyUserInfo = function (callback) {
|
window.BBB.getMyUserInfo = function (callback) {
|
||||||
const uid = Auth.userID;
|
const uid = Auth.userID;
|
||||||
@ -104,12 +99,24 @@ function joinVoiceCall(options) {
|
|||||||
|
|
||||||
callIntoConference(extension, function () {}, options.isListenOnly);
|
callIntoConference(extension, function () {}, options.isListenOnly);
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
const conferenceUsername = createVertoUserName();
|
|
||||||
conferenceIdNumber = '1009';
|
|
||||||
joinVertoAudio({ extension, conferenceUsername, conferenceIdNumber,
|
|
||||||
listenOnly: options.isListenOnly, });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { joinVoiceCall, exitVoiceCall, getVoiceBridge, };
|
function joinListenOnly() {
|
||||||
|
callServer('listenOnlyRequestToggle', true);
|
||||||
|
if (clientConfig.media.useSIPAudio) {
|
||||||
|
joinVoiceCallSIP({ isListenOnly: true });
|
||||||
|
} else {
|
||||||
|
vertoJoinListenOnly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinMicrophone() {
|
||||||
|
if (clientConfig.media.useSIPAudio) {
|
||||||
|
joinVoiceCallSIP({ isListenOnly: false });
|
||||||
|
} else {
|
||||||
|
vertoJoinMicrophone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { joinListenOnly, joinMicrophone, exitAudio, getVoiceBridge, };
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import {getInStorage} from '/imports/ui/components/app/service';
|
||||||
|
import Users from '/imports/api/users';
|
||||||
import Auth from '/imports/ui/services/auth';
|
import Auth from '/imports/ui/services/auth';
|
||||||
import { clientConfig } from '/config';
|
import { clientConfig } from '/config';
|
||||||
import { getVoiceBridge } from '/imports/api/phone';
|
import { getVoiceBridge } from '/imports/api/phone';
|
||||||
@ -9,61 +11,50 @@ function createVertoUserName() {
|
|||||||
return conferenceUsername;
|
return conferenceUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
function joinVertoAudio(options) {
|
function vertoExitAudio() {
|
||||||
joinVertoCall(options);
|
window.vertoExitAudio();
|
||||||
}
|
}
|
||||||
|
|
||||||
function watchVertoVideo(options) {
|
function vertoJoinListenOnly() {
|
||||||
joinVertoCall(options);
|
window.vertoJoinListenOnly(
|
||||||
|
'remote-media',
|
||||||
|
getVoiceBridge(),
|
||||||
|
createVertoUserName(),
|
||||||
|
null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function joinVertoCall(options) {
|
function vertoJoinMicrophone() {
|
||||||
console.log('joinVertoCall');
|
window.vertoJoinMicrophone(
|
||||||
const extension = options.extension || getVoiceBridge();
|
'remote-media',
|
||||||
|
getVoiceBridge(),
|
||||||
|
createVertoUserName(),
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!isWebRTCAvailable()) {
|
function vertoWatchVideo() {
|
||||||
return;
|
window.vertoWatchVideo(
|
||||||
}
|
'deskshareVideo',
|
||||||
|
getVoiceBridge(),
|
||||||
|
createVertoUserName(),
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!clientConfig.useSIPAudio) {
|
function shareVertoScreen() {
|
||||||
const vertoServerCredentials = {
|
vertoManager.shareScreen(
|
||||||
vertoPort: clientConfig.media.vertoPort,
|
'deskshareVideo',
|
||||||
hostName: clientConfig.media.vertoServerAddress,
|
getVoiceBridge(),
|
||||||
login: conferenceIdNumber,
|
createVertoUserName(),
|
||||||
password: clientConfig.media.freeswitchProfilePassword,
|
null,
|
||||||
};
|
);
|
||||||
|
|
||||||
let wasCallSuccessful = false;
|
|
||||||
let conferenceUsername = createVertoUserName();
|
|
||||||
let debuggerCallback = function (message) {
|
|
||||||
console.log('CALLBACK: ' + JSON.stringify(message));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Beginning of hacky method to make Firefox media calls succeed.
|
|
||||||
// Always fail the first time. Retry on failure.
|
|
||||||
//
|
|
||||||
if (!!navigator.mozGetUserMedia && message.errorcode == 1001) {
|
|
||||||
const logCallback = function (m) {
|
|
||||||
console.log('CALLBACK: ' + JSON.stringify(m));
|
|
||||||
};
|
|
||||||
|
|
||||||
callIntoConference_verto(extension, conferenceUsername, conferenceIdNumber, logCallback,
|
|
||||||
'webcam', options, vertoServerCredentials);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// End of hacky method
|
|
||||||
//
|
|
||||||
};
|
|
||||||
|
|
||||||
callIntoConference_verto(extension, conferenceUsername, conferenceIdNumber, debuggerCallback,
|
|
||||||
'webcam', options, vertoServerCredentials);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
createVertoUserName,
|
vertoJoinListenOnly,
|
||||||
joinVertoAudio,
|
vertoJoinMicrophone,
|
||||||
watchVertoVideo,
|
vertoWatchVideo,
|
||||||
|
vertoExitAudio,
|
||||||
|
shareVertoScreen,
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||||||
export default class DeskshareComponent extends React.Component {
|
export default class DeskshareComponent extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<video id="webcam" style={{ height: '100%', width: '100%', }} controls/>
|
<video id="deskshareVideo" style={{ height: '100%', width: '100%', }} controls/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Deskshare from '/imports/api/deskshare';
|
import Deskshare from '/imports/api/deskshare';
|
||||||
import {createVertoUserName, joinVertoAudio, watchVertoVideo} from '/imports/api/verto';
|
import {createVertoUserName, watchVertoVideo} from '/imports/api/verto';
|
||||||
import Auth from '/imports/ui/services/auth';
|
import Auth from '/imports/ui/services/auth';
|
||||||
import {getVoiceBridge} from '/imports/api/phone';
|
import {getVoiceBridge} from '/imports/api/phone';
|
||||||
|
|
||||||
@ -27,14 +27,6 @@ function videoIsBroadcasting() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function watchDeskshare(options) {
|
|
||||||
const extension = options.extension || getVoiceBridge();
|
|
||||||
const conferenceUsername = createVertoUserName();
|
|
||||||
conferenceIdNumber = '1009';
|
|
||||||
watchVertoVideo({ extension, conferenceUsername, conferenceIdNumber,
|
|
||||||
watchOnly: true, });
|
|
||||||
}
|
|
||||||
|
|
||||||
// if remote deskshare has been ended disconnect and hide the video stream
|
// if remote deskshare has been ended disconnect and hide the video stream
|
||||||
function presenterDeskshareHasEnded() {
|
function presenterDeskshareHasEnded() {
|
||||||
// exitVoiceCall();
|
// exitVoiceCall();
|
||||||
@ -42,13 +34,9 @@ function presenterDeskshareHasEnded() {
|
|||||||
|
|
||||||
// if remote deskshare has been started connect and display the video stream
|
// if remote deskshare has been started connect and display the video stream
|
||||||
function presenterDeskshareHasStarted() {
|
function presenterDeskshareHasStarted() {
|
||||||
const voiceBridge = Deskshare.findOne().deskshare.voiceBridge;
|
vertoWatchVideo();
|
||||||
watchDeskshare({
|
|
||||||
watchOnly: true,
|
|
||||||
extension: voiceBridge,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { videoIsBroadcasting, watchDeskshare, presenterDeskshareHasEnded,
|
export {
|
||||||
presenterDeskshareHasStarted
|
videoIsBroadcasting, presenterDeskshareHasEnded, presenterDeskshareHasStarted
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,7 @@ import Modal from 'react-modal';
|
|||||||
import Icon from '/imports/ui/components/icon/component';
|
import Icon from '/imports/ui/components/icon/component';
|
||||||
import Button from '/imports/ui/components/button/component';
|
import Button from '/imports/ui/components/button/component';
|
||||||
import BaseMenu from './BaseMenu';
|
import BaseMenu from './BaseMenu';
|
||||||
import {joinVoiceCall, exitVoiceCall} from '/imports/api/phone';
|
import {joinListenOnly, joinMicrophone, exitAudio} from '/imports/api/phone';
|
||||||
|
|
||||||
export default class AudioMenu extends BaseMenu {
|
export default class AudioMenu extends BaseMenu {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -14,24 +14,6 @@ export default class AudioMenu extends BaseMenu {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>inside audio menu</p>
|
<p>inside audio menu</p>
|
||||||
|
|
||||||
<button onClick={
|
|
||||||
function () {
|
|
||||||
exitVoiceCall(function () {console.log('exit callback');});
|
|
||||||
}
|
|
||||||
}>exit voice call</button>
|
|
||||||
<br/>
|
|
||||||
<button onClick={
|
|
||||||
function () {
|
|
||||||
joinVoiceCall({ isListenOnly: true });
|
|
||||||
}
|
|
||||||
}>listen only</button>
|
|
||||||
|
|
||||||
<button onClick={
|
|
||||||
function () {
|
|
||||||
joinVoiceCall({ isListenOnly: false });
|
|
||||||
}
|
|
||||||
}>join mic</button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ dependencies {
|
|||||||
|
|
||||||
//redis
|
//redis
|
||||||
compile 'redis.clients:jedis:2.0.0'
|
compile 'redis.clients:jedis:2.0.0'
|
||||||
providedCompile 'commons-pool:commons-pool:1.5.6'
|
compile 'commons-pool:commons-pool:1.5.6'
|
||||||
compile 'com.google.code.gson:gson:1.7.1'
|
compile 'com.google.code.gson:gson:1.7.1'
|
||||||
|
|
||||||
compile 'org.bigbluebutton:bbb-common-message:0.0.18-SNAPSHOT'
|
compile 'org.bigbluebutton:bbb-common-message:0.0.18-SNAPSHOT'
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
cd /var/lib/red5/webapps
|
||||||
|
echo 'Starting with:'
|
||||||
|
ls -dl video-broadcast
|
||||||
|
sudo chown root:root video-broadcast
|
||||||
|
sudo chmod -R 777 video-broadcast
|
||||||
|
|
||||||
|
cd video-broadcast
|
||||||
|
|
||||||
|
ls -al
|
||||||
|
sudo chown root:root META-INF
|
||||||
|
sudo chown red5:red5 streams
|
||||||
|
sudo chown root:root WEB-INF
|
||||||
|
|
||||||
|
echo 'After the procedure:'
|
||||||
|
ls -al
|
Loading…
Reference in New Issue
Block a user