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);
|
||||
|
||||
// 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 deskShareRTMPBroadcastStarted(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: UserTalkingInVoiceConfMessage => handleUserTalkingInVoiceConfMessage(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
|
||||
}
|
||||
|
||||
@ -151,6 +146,7 @@ class BigBlueButtonActor(val system: ActorSystem,
|
||||
/** Subscribe to meeting and voice events. **/
|
||||
eventBus.subscribe(m.actorRef, m.mProps.meetingID)
|
||||
eventBus.subscribe(m.actorRef, m.mProps.voiceBridge)
|
||||
eventBus.subscribe(m.actorRef, m.mProps.deskshareBridge)
|
||||
|
||||
meetings += m.mProps.meetingID -> m
|
||||
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))
|
||||
}
|
||||
|
||||
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.record,
|
||||
msg.payload.voiceConfId,
|
||||
msg.payload.voiceConfId + "-DESKSHARE", // WebRTC Desktop conference id
|
||||
msg.payload.durationInMinutes,
|
||||
msg.payload.autoStartRecording,
|
||||
msg.payload.allowStartStopRecording,
|
||||
@ -498,8 +499,11 @@ class BigBlueButtonInGW(
|
||||
* Message Interface for DeskShare
|
||||
* *****************************************************************
|
||||
*/
|
||||
def deskShareStarted(meetingId: String, callerId: String, callerIdName: String) {
|
||||
eventBus.publish(BigBlueButtonEvent(meetingId, new DeskShareStartedRequest(meetingId, callerId, callerIdName)))
|
||||
def deskShareStarted(confId: String, callerId: String, callerIdName: String) {
|
||||
println("____BigBlueButtonInGW::deskShareStarted " + confId + callerId + " " +
|
||||
callerIdName)
|
||||
eventBus.publish(BigBlueButtonEvent(confId, new DeskShareStartedRequest(confId, callerId,
|
||||
callerIdName)))
|
||||
}
|
||||
|
||||
def deskShareStopped(meetingId: String, callerId: String, callerIdName: String) {
|
||||
|
@ -163,4 +163,80 @@ class LiveMeeting(val mProps: MeetingProperties,
|
||||
def permissionsEqual(other: Permissions): Boolean = {
|
||||
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: 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
|
||||
}
|
||||
|
||||
// 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 class MeetingProperties(meetingID: String, externalMeetingID: String, meetingName: String, recorded: Boolean,
|
||||
voiceBridge: String, duration: Int, autoStartRecording: Boolean, allowStartStopRecording: Boolean,
|
||||
moderatorPass: String, viewerPass: String, createTime: Long, createDate: String,
|
||||
red5DeskShareIP: String, red5DeskShareApp: String, isBreakout: Boolean)
|
||||
voiceBridge: String, deskshareBridge: String, duration: Int, autoStartRecording: Boolean,
|
||||
allowStartStopRecording: Boolean, moderatorPass: String, viewerPass: String, createTime: Long,
|
||||
createDate: String, red5DeskShareIP: String, red5DeskShareApp: String, isBreakout: Boolean)
|
||||
|
||||
case class MeetingExtensionProp(maxExtensions: Int = 2, numExtensions: Int = 0, extendByMinutes: Int = 20,
|
||||
sendNotice: Boolean = true, sent15MinNotice: Boolean = false,
|
||||
|
@ -7,6 +7,7 @@ trait AppsTestFixtures {
|
||||
val meetingName = "test meeting"
|
||||
val record = false
|
||||
val voiceConfId = "85115"
|
||||
val deskshareConfId = "85115-DESKSHARE"
|
||||
val durationInMinutes = 10
|
||||
val autoStartRecording = false
|
||||
val allowStartStopRecording = false
|
||||
@ -18,7 +19,7 @@ trait AppsTestFixtures {
|
||||
|
||||
val mProps = new MeetingProperties(meetingId, externalMeetingId,
|
||||
meetingName, record,
|
||||
voiceConfId,
|
||||
voiceConfId, deskshareConfId,
|
||||
durationInMinutes,
|
||||
autoStartRecording, allowStartStopRecording,
|
||||
moderatorPassword, viewerPassword,
|
||||
|
@ -13,20 +13,12 @@
|
||||
<include>
|
||||
<context name="default">
|
||||
<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="transfer" data="${destination_number} XML public"/>
|
||||
</condition>
|
||||
</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 -->
|
||||
|
||||
</context>
|
||||
|
@ -16,10 +16,10 @@
|
||||
<!-- other extensions -->
|
||||
|
||||
<extension name="public_extensions">
|
||||
<condition field="destination_number" expression="^\d{5}$">
|
||||
<action application="log" data="INFO ************ redirecting ${destination_number} to ${destination_number}-DESKSHARE@video-mcu-stereo ***********" />
|
||||
<condition field="destination_number" expression="^\d{5}-DESKSHARE$">
|
||||
<action application="log" data="INFO ************WEBRTC DESKSHARE EXT***********" />
|
||||
<action application="answer"/>
|
||||
<action application="conference" data="${destination_number}-DESKSHARE@video-mcu-stereo"/>
|
||||
<action application="conference" data="${destination_number}@video-mcu-stereo"/>
|
||||
</condition>
|
||||
</extension>
|
||||
|
||||
|
@ -28,8 +28,6 @@ public class ESLEventListener implements IEslEventListener {
|
||||
private static final String STOP_RECORDING_EVENT = "stop-recording";
|
||||
|
||||
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;
|
||||
|
||||
@ -68,54 +66,54 @@ public class ESLEventListener implements IEslEventListener {
|
||||
|
||||
String voiceUserId = callerIdName;
|
||||
|
||||
System.out.println("User joined voice conference, user=[" + callerIdName + "], conf=[" + confName + "]");
|
||||
|
||||
Matcher gapMatcher = GLOBAL_AUDION_PATTERN.matcher(callerIdName);
|
||||
if (gapMatcher.matches()) {
|
||||
System.out.println("Ignoring GLOBAL AUDIO USER [" + callerIdName + "]");
|
||||
return;
|
||||
}
|
||||
|
||||
// Deskstop sharing conferences have their name in the form ddddd-DESKSHARE
|
||||
// Deskstop sharing conferences have the user with the desktop video displayed in this way:
|
||||
// username (Screen) and usernum (screen)
|
||||
if (confName.endsWith(DESKSHARE_CONFERENCE_NAME_SUFFIX) &&
|
||||
callerId.endsWith(DESKSHARE_CALLER_ID_SUFFIX) &&
|
||||
callerIdName.endsWith(DESKSHARE_CALLER_NAME_SUFFIX)) {
|
||||
// (WebRTC) Deskstop sharing conferences' name is of the form ddddd-DESKSHARE
|
||||
// Voice conferences' name is of the form ddddd
|
||||
if (confName.endsWith(DESKSHARE_CONFERENCE_NAME_SUFFIX)) {
|
||||
System.out.println("User joined deskshare conference, user=[" + callerIdName + "], " +
|
||||
"conf=[" + confName + "] callerId=[" + callerId + "]");
|
||||
DeskShareStartedEvent dsStart = new DeskShareStartedEvent(confName, callerId, callerIdName);
|
||||
conferenceEventListener.handleConferenceEvent(dsStart);
|
||||
}
|
||||
|
||||
} else {
|
||||
Matcher matcher = CALLERNAME_PATTERN.matcher(callerIdName);
|
||||
if (matcher.matches()) {
|
||||
voiceUserId = matcher.group(1).trim();
|
||||
callerIdName = matcher.group(2).trim();
|
||||
}
|
||||
|
||||
System.out.println("User joined voice conference, user=[" + callerIdName + "], conf=[" +
|
||||
confName + "] callerId=[" + callerId + "]");
|
||||
|
||||
VoiceUserJoinedEvent pj = new VoiceUserJoinedEvent(voiceUserId, memberId.toString(), confName, callerId, callerIdName, muted, speaking, "");
|
||||
conferenceEventListener.handleConferenceEvent(pj);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void conferenceEventLeave(String uniqueId, String confName, int confSize, EslEvent event) {
|
||||
Integer memberId = this.getMemberIdFromEvent(event);
|
||||
System.out.println("User left voice conference, user=[" + memberId.toString() + "], conf=[" + confName + "]");
|
||||
String callerId = this.getCallerIdFromEvent(event);
|
||||
String callerIdName = this.getCallerIdNameFromEvent(event);
|
||||
|
||||
// Deskstop sharing conferences have their name in the form ddddd-DESKSHARE
|
||||
// Deskstop sharing conferences have the user with the desktop video displayed in this way:
|
||||
// username (Screen) and usernum (screen)
|
||||
if (confName.endsWith(DESKSHARE_CONFERENCE_NAME_SUFFIX) &&
|
||||
callerId.endsWith(DESKSHARE_CALLER_ID_SUFFIX) &&
|
||||
callerIdName.endsWith(DESKSHARE_CALLER_NAME_SUFFIX)) {
|
||||
// (WebRTC) Deskstop sharing conferences' name is of the form ddddd-DESKSHARE
|
||||
// Voice conferences' name is of the form ddddd
|
||||
if (confName.endsWith(DESKSHARE_CONFERENCE_NAME_SUFFIX)) {
|
||||
System.out.println("User left deskshare conference, user=[" + memberId.toString() +
|
||||
"], " + "conf=[" + confName + "]");
|
||||
DeskShareEndedEvent dsEnd = new DeskShareEndedEvent(confName, callerId, callerIdName);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void conferenceEventMute(String uniqueId, String confName, int confSize, EslEvent event) {
|
||||
@ -231,7 +229,8 @@ public class ESLEventListener implements IEslEventListener {
|
||||
|
||||
@Override
|
||||
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)) {
|
||||
//// setChanged();
|
||||
// notifyObservers(event);
|
||||
|
@ -14,8 +14,7 @@ import org.bigbluebutton.common.messages.DeskShareRTMPBroadcastStoppedEventMessa
|
||||
|
||||
class VoiceConferenceService(sender: RedisPublisher) extends IVoiceConferenceService {
|
||||
|
||||
val FROM_VOICE_CONF_SYSTEM_CHAN = "bigbluebutton:from-voice-conf:system";
|
||||
private final val DESKSHARE_CONFERENCE_NAME_SUFFIX = "-DESKSHARE"
|
||||
val FROM_VOICE_CONF_SYSTEM_CHAN = "bigbluebutton:from-voice-conf:system"
|
||||
|
||||
def voiceConfRecordingStarted(voiceConfId: String, recordStream: String, recording: java.lang.Boolean, timestamp: String) {
|
||||
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,
|
||||
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)
|
||||
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
||||
}
|
||||
|
||||
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)
|
||||
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) {
|
||||
val trimmedVoiceConfId = voiceConfId.replace(DESKSHARE_CONFERENCE_NAME_SUFFIX, "")
|
||||
println("******** FreeswitchConferenceService send deskShareStarted to BBB " + trimmedVoiceConfId)
|
||||
val msg = new DeskShareStartedEventMessage(trimmedVoiceConfId, callerIdNum, callerIdName)
|
||||
println("******** FreeswitchConferenceService send deskShareStarted to BBB " + voiceConfId)
|
||||
val msg = new DeskShareStartedEventMessage(voiceConfId, callerIdNum, callerIdName)
|
||||
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
||||
}
|
||||
|
||||
def deskShareEnded(voiceConfId: String, callerIdNum: String, callerIdName: String) {
|
||||
val trimmedVoiceConfId = voiceConfId.replace(DESKSHARE_CONFERENCE_NAME_SUFFIX, "")
|
||||
println("******** FreeswitchConferenceService send deskShareStopped to BBB " + trimmedVoiceConfId)
|
||||
val msg = new DeskShareStoppedEventMessage(trimmedVoiceConfId, callerIdNum, callerIdName)
|
||||
println("******** FreeswitchConferenceService send deskShareStopped to BBB " + voiceConfId)
|
||||
val msg = new DeskShareStoppedEventMessage(voiceConfId, callerIdNum, callerIdName)
|
||||
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) {
|
||||
val trimmedVoiceConfId = voiceConfId.replace(DESKSHARE_CONFERENCE_NAME_SUFFIX, "")
|
||||
println("******** FreeswitchConferenceService send deskShareRTMPBroadcastStarted to BBB " + trimmedVoiceConfId)
|
||||
val msg = new DeskShareRTMPBroadcastStartedEventMessage(trimmedVoiceConfId, streamname, vw, vh, timestamp)
|
||||
println("******** FreeswitchConferenceService send deskShareRTMPBroadcastStarted to BBB " + voiceConfId)
|
||||
val msg = new DeskShareRTMPBroadcastStartedEventMessage(voiceConfId, streamname, vw, vh, timestamp)
|
||||
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) {
|
||||
val trimmedVoiceConfId = voiceConfId.replace(DESKSHARE_CONFERENCE_NAME_SUFFIX, "")
|
||||
println("******** FreeswitchConferenceService send deskShareRTMPBroadcastStopped to BBB " + trimmedVoiceConfId)
|
||||
val msg = new DeskShareRTMPBroadcastStoppedEventMessage(trimmedVoiceConfId, streamname, vw, vh, timestamp)
|
||||
println("******** FreeswitchConferenceService send deskShareRTMPBroadcastStopped to BBB " + voiceConfId)
|
||||
val msg = new DeskShareRTMPBroadcastStoppedEventMessage(voiceConfId, streamname, vw, vh, timestamp)
|
||||
sender.publish(FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson())
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,8 @@
|
||||
autoStart="false"
|
||||
autoFullScreen="false"
|
||||
baseTabIndex="201"
|
||||
useWebRTCIfAvailable="false"
|
||||
chromeExtensionKey=""
|
||||
help="http://HOST/client/help/screenshare-help.html"
|
||||
/>
|
||||
|
||||
|
@ -105,7 +105,6 @@
|
||||
<script src="lib/jquery.verto.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_share.js" 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>
|
||||
|
@ -92,8 +92,6 @@ var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
|
||||
var isChrome = !!window.chrome && !isOpera;
|
||||
|
||||
function getChromeExtensionStatus(extensionid, callback) {
|
||||
callback = normalizeCallback(callback);
|
||||
|
||||
if (isFirefox) return callback('not-chrome');
|
||||
|
||||
if (chromeMediaSource == 'desktop') return callback('installed-enabled');
|
||||
|
@ -103,7 +103,7 @@
|
||||
|
||||
if (moz) {
|
||||
this.constraints = {
|
||||
offerToReceiveAudio: true,
|
||||
offerToReceiveAudio: this.options.useSpeak === "none" ? false : true,
|
||||
offerToReceiveVideo: this.options.useVideo ? true : false,
|
||||
};
|
||||
} else {
|
||||
@ -111,7 +111,7 @@
|
||||
optional: [{
|
||||
'DtlsSrtpKeyAgreement': 'true'
|
||||
}],mandatory: {
|
||||
OfferToReceiveAudio: true,
|
||||
OfferToReceiveAudio: this.options.useSpeak === "none" ? false : true,
|
||||
OfferToReceiveVideo: this.options.useVideo ? true : false,
|
||||
}
|
||||
};
|
||||
@ -342,8 +342,8 @@
|
||||
if(typeof self.options.localVideoStream.stop == 'function') {
|
||||
self.options.localVideoStream.stop();
|
||||
} else {
|
||||
if (self.localVideoStream.active){
|
||||
var tracks = self.localVideoStream.getTracks();
|
||||
if (self.options.localVideoStream.active){
|
||||
var tracks = self.options.localVideoStream.getTracks();
|
||||
console.error(tracks);
|
||||
tracks.forEach(function(track, index){
|
||||
console.log(track);
|
||||
@ -513,7 +513,7 @@
|
||||
audio = false;
|
||||
} else {
|
||||
audio = {
|
||||
mandatory: obj.options.audioParams,
|
||||
mandatory: {},
|
||||
optional: []
|
||||
};
|
||||
|
||||
@ -521,6 +521,15 @@
|
||||
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) {
|
||||
@ -558,8 +567,9 @@
|
||||
video.optional.push({sourceId: obj.options.useCamera});
|
||||
}
|
||||
|
||||
if (bestFrameRate && !window.moz) {
|
||||
if (bestFrameRate) {
|
||||
video.optional.push({minFrameRate: bestFrameRate});
|
||||
video.optional.push({maxFrameRate: bestFrameRate});
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -603,15 +613,7 @@
|
||||
onICEComplete: function() {
|
||||
return onICEComplete(self);
|
||||
},
|
||||
onRemoteStream: screen ? function(stream) {
|
||||
// Added by Dan Perrone (perroned)
|
||||
// https://github.com/perroned
|
||||
// Date: January 13, 2016
|
||||
// Commit: 279f40a4c280bba11052adc621fddbb3135ccb6d
|
||||
|
||||
verto_afterStreamPublish();} :
|
||||
// ----------------------------------------------------
|
||||
function(stream) {
|
||||
onRemoteStream: screen ? function(stream) {} : function(stream) {
|
||||
return onRemoteStream(self, stream);
|
||||
},
|
||||
onOfferSDP: function(sdp) {
|
||||
@ -633,58 +635,12 @@
|
||||
function onError(e) {
|
||||
onStreamError(self, e);
|
||||
}
|
||||
|
||||
var mediaParams = getMediaParams(self);
|
||||
|
||||
console.log("Audio constraints", mediaParams.audio);
|
||||
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) {
|
||||
|
||||
getUserMedia({
|
||||
@ -1078,41 +1034,13 @@
|
||||
var n = navigator,
|
||||
media;
|
||||
n.getMedia = n.webkitGetUserMedia || n.mozGetUserMedia;
|
||||
|
||||
// Added by Dan Perrone (perroned)
|
||||
// https://github.com/perroned
|
||||
// Date: February 17, 2016
|
||||
// Commit: 05488dda5d9d1048e286b0bdee27515d217b15a5
|
||||
|
||||
var constraints = {};
|
||||
var errorCallback = null;
|
||||
if (window.firefoxDesksharePresent) {
|
||||
window.firefoxDesksharePresent = false;
|
||||
constraints = {
|
||||
audio: false,
|
||||
video: {
|
||||
mediaSource: 'window',
|
||||
mozMediaSource: 'window'
|
||||
}
|
||||
};
|
||||
} else {
|
||||
constraints = options.constraints || {
|
||||
n.getMedia(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 ||
|
||||
},
|
||||
streaming, options.onerror ||
|
||||
function(e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
n.getMedia(constraints, streaming, function() {
|
||||
errorCallback({'status': 'Failed to getUserMedia on Firefox', 'errorcode': 2000});
|
||||
});
|
||||
|
||||
function streaming(stream) {
|
||||
|
@ -132,8 +132,13 @@
|
||||
}
|
||||
});
|
||||
|
||||
var tag = verto.options.tag;
|
||||
if (typeof(tag) === "function") {
|
||||
tag = tag();
|
||||
}
|
||||
|
||||
if (verto.options.ringFile && verto.options.tag) {
|
||||
verto.ringer = $("#" + verto.options.tag);
|
||||
verto.ringer = $("#" + tag);
|
||||
}
|
||||
|
||||
verto.rpcClient.call('login', {});
|
||||
@ -1308,11 +1313,15 @@
|
||||
this.modCommand("vid-write-png", null, file);
|
||||
};
|
||||
|
||||
$.verto.conf.prototype.setVideoLayout = function(layout) {
|
||||
$.verto.conf.prototype.setVideoLayout = function(layout, canvasID) {
|
||||
if (!this.params.hasVid) {
|
||||
throw 'Conference has no video';
|
||||
}
|
||||
if (canvasID) {
|
||||
this.modCommand("vid-layout", null, [layout, canvasID]);
|
||||
} else {
|
||||
this.modCommand("vid-layout", null, layout);
|
||||
}
|
||||
};
|
||||
|
||||
$.verto.conf.prototype.kick = function(memberID) {
|
||||
@ -1439,7 +1448,7 @@
|
||||
|
||||
var vlhtml = "<div id='" + vlayout_id + "'><br>" +
|
||||
"<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>";
|
||||
jq.append(vlhtml);
|
||||
}
|
||||
@ -1881,6 +1890,11 @@
|
||||
$.verto.dialog = function(direction, verto, params) {
|
||||
var dialog = this;
|
||||
|
||||
var tag = verto.options.tag;
|
||||
if (typeof(tag) === "function") {
|
||||
tag = tag();
|
||||
}
|
||||
|
||||
dialog.params = $.extend({
|
||||
useVideo: verto.options.useVideo,
|
||||
useStereo: verto.options.useStereo,
|
||||
@ -1888,7 +1902,7 @@
|
||||
useCamera: verto.options.deviceParams.useCamera,
|
||||
useMic: verto.options.deviceParams.useMic,
|
||||
useSpeak: verto.options.deviceParams.useSpeak,
|
||||
tag: verto.options.tag,
|
||||
tag: tag,
|
||||
localTag: verto.options.localTag,
|
||||
login: verto.options.login,
|
||||
videoParams: verto.options.videoParams
|
||||
@ -2154,7 +2168,7 @@
|
||||
var speaker = dialog.useSpeak;
|
||||
console.info("Using Speaker: ", speaker);
|
||||
|
||||
if (speaker && speaker !== "any") {
|
||||
if (speaker && speaker !== "any" && speaker !== "none") {
|
||||
setTimeout(function() {
|
||||
dialog.setAudioPlaybackDevice(speaker);
|
||||
}, 500);
|
||||
@ -2181,6 +2195,11 @@
|
||||
dialog.setState($.verto.enum.state.destroy);
|
||||
break;
|
||||
case $.verto.enum.state.destroy:
|
||||
|
||||
if (typeof(dialog.verto.options.tag) === "function") {
|
||||
$('#' + dialog.params.tag).remove();
|
||||
}
|
||||
|
||||
delete dialog.verto.dialogs[dialog.callID];
|
||||
if (dialog.params.screenShare) {
|
||||
dialog.rtc.stopPeer();
|
||||
|
@ -1,14 +1,76 @@
|
||||
var callback = function(message){console.log(message);}; // holds the user's callback for a global scope
|
||||
callbacks = {};
|
||||
var callICEConnected = false;
|
||||
var callPurposefullyEnded = false; // used to determine whether the user ended the call or the call was ended from somewhere else outside
|
||||
var callTimeout = null; // function that will run if there is no call established
|
||||
var toDisplayDisconnectCallback = true; // if a call is dropped only display the error the first time
|
||||
var wasCallSuccessful = false; // when the websocket connection is closed this determines whether a call was ever successfully established
|
||||
webcamStream = "webcamStream";
|
||||
window[webcamStream] = null;
|
||||
verto = null;
|
||||
videoTag = null;
|
||||
Verto = function (
|
||||
tag,
|
||||
voiceBridge,
|
||||
conferenceUsername,
|
||||
userCallback,
|
||||
onFail = null,
|
||||
chromeExtension = null) {
|
||||
|
||||
voiceBridge += "-DESKSHARE";
|
||||
this.cur_call = 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
|
||||
// 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
|
||||
// that when invokved will invoke the actionscript registered callback
|
||||
// and passes along parameters
|
||||
function normalizeCallback(callback) {
|
||||
if (typeof callback == "function") {
|
||||
Verto.normalizeCallback = function (callback) {
|
||||
if (typeof callback == 'function') {
|
||||
return callback;
|
||||
} else {
|
||||
return function(args) {
|
||||
document.getElementById("BigBlueButton")[callback](args);
|
||||
return function (args) {
|
||||
document.getElementById('BigBlueButton')[callback](args);
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// save a copy of the hangup function registered for the verto object
|
||||
var oldHangup = $.verto.prototype.hangup;
|
||||
// overwrite the verto hangup handler with my own handler
|
||||
$.verto.prototype.hangup = function(callID, userCallback) {
|
||||
console.log("call state callbacks - bye");
|
||||
if (userCallback) {
|
||||
callback = userCallback;
|
||||
}
|
||||
callActive = false;
|
||||
|
||||
if (cur_call) {
|
||||
console.log('call ended ' + cur_call.audioStream.currentTime); // the duration of the call
|
||||
if (callPurposefullyEnded === true) { // the user ended the call themself
|
||||
callback({'status':'ended'});
|
||||
Verto.prototype.onWSLogin = function (v, success) {
|
||||
this.cur_call = null;
|
||||
if (success) {
|
||||
this.callWasSuccessful = true;
|
||||
this.mediaCallback();
|
||||
return;
|
||||
} else {
|
||||
callback({'status':'failed', 'errorcode': 1005}); // Call ended unexpectedly
|
||||
// error logging verto into freeswitch
|
||||
this.logError({ status: 'failed', errorcode: '10XX' });
|
||||
this.callWasSuccessful = false;
|
||||
this.onFail();
|
||||
return;
|
||||
}
|
||||
clearTimeout(callTimeout);
|
||||
};
|
||||
|
||||
Verto.prototype.registerCallbacks = function () {
|
||||
var callbacks = {
|
||||
onMessage: function () {},
|
||||
|
||||
onDialogState: function (d) {},
|
||||
|
||||
onWSLogin: this.onWSLogin.bind(this),
|
||||
|
||||
onWSClose: function (v, success) {
|
||||
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
|
||||
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
|
||||
if (this.callWasSuccessful) {
|
||||
// the connection was dropped in an already established call
|
||||
console.log("websocket disconnected");
|
||||
callback({'status':'failed', 'errorcode': 1001}); // WebSocket disconnected
|
||||
this.logError('websocket disconnected');
|
||||
|
||||
// WebSocket disconnected
|
||||
this.logError({ status: 'failed', errorcode: 1001 });
|
||||
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");
|
||||
this.logError('websocket connection could not be established');
|
||||
|
||||
if (success) {
|
||||
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);
|
||||
// Could not make a WebSocket connection
|
||||
this.logError({ status: 'failed', errorcode: 1002 });
|
||||
this.onFail();
|
||||
return;
|
||||
}
|
||||
}.bind(this),
|
||||
};
|
||||
this.callbacks = callbacks;
|
||||
};
|
||||
|
||||
Verto.prototype.hold = function () {
|
||||
this.cur_call.toggleHold();
|
||||
};
|
||||
|
||||
Verto.prototype.hangup = function () {
|
||||
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 (this.share_call) {
|
||||
// the duration of the call
|
||||
this.logger('call ended ' + this.share_call.audioStream.currentTime);
|
||||
this.share_call.hangup();
|
||||
this.share_call = null;
|
||||
}
|
||||
|
||||
// the user ended the call themself
|
||||
// if (callPurposefullyEnded === true) {
|
||||
if (true) {
|
||||
this.logger({ status: 'ended' });
|
||||
} else {
|
||||
callback({'status':'failed', 'errorcode': '10XX'}); // eror logging verto into freeswitch
|
||||
// Call ended unexpectedly
|
||||
this.logError({ status: 'failed', errorcode: 1005 });
|
||||
}
|
||||
};
|
||||
|
||||
Verto.prototype.mute = function () {
|
||||
this.cur_call.dtmf('0');
|
||||
};
|
||||
|
||||
Verto.prototype.localmute = function () {
|
||||
// var muted = cur_call.setMute('toggle');
|
||||
// if (muted) {
|
||||
// display('Talking to: ' + cur_call.cidString() + ' [LOCALLY MUTED]');
|
||||
// } else {
|
||||
// display('Talking to: ' + cur_call.cidString());
|
||||
// }
|
||||
};
|
||||
|
||||
Verto.prototype.localvidmute = function () {
|
||||
// var muted = cur_call.setVideoMute('toggle');
|
||||
// if (muted) {
|
||||
// display('Talking to: ' + cur_call.cidString() + ' [VIDEO LOCALLY MUTED]');
|
||||
// } else {
|
||||
// display('Talking to: ' + cur_call.cidString());
|
||||
// }
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
// set up verto
|
||||
// $.verto.init({}, init(videoTag));
|
||||
init(videoTag, vertoServerCredentials);
|
||||
|
||||
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 {
|
||||
console.log("already logged into verto, going straight to making a call");
|
||||
webrtc_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, callback, options);
|
||||
this.mediaCallback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
checkSupport = function(callback) {
|
||||
if(!isWebRTCAvailable_verto()) {
|
||||
callback({'status': 'failed', 'errorcode': 1003}); // Browser version not supported
|
||||
}
|
||||
|
||||
if (!navigator.getUserMedia) {
|
||||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
||||
}
|
||||
|
||||
if (!navigator.getUserMedia){
|
||||
callback({'status': 'failed', 'errorcode': '10XX'}); // getUserMedia not supported in this browser
|
||||
}
|
||||
}
|
||||
|
||||
configStuns = function(callbacks, callback, videoTag, vertoServerCredentials) {
|
||||
console.log("Fetching STUN/TURN server info for Verto initialization");
|
||||
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) {
|
||||
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});
|
||||
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) {
|
||||
|
||||
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']
|
||||
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});
|
||||
}) : []);
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
docall_verto = function(extension, conferenceUsername, conferenceIdNumber, callbacks, options) {
|
||||
console.log(extension + ", " + conferenceUsername + ", " + conferenceIdNumber);
|
||||
|
||||
if (cur_call) { // only allow for one call
|
||||
console.log("Quitting: Call already in progress");
|
||||
return;
|
||||
}
|
||||
// determine the resolution the user chose for webcam video
|
||||
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({
|
||||
destination_number: extension,
|
||||
caller_id_name: conferenceUsername,
|
||||
caller_id_number: conferenceIdNumber,
|
||||
outgoingBandwidth: outgoingBandwidth,
|
||||
incomingBandwidth: incomingBandwidth,
|
||||
useStereo: true,
|
||||
useVideo: useVideo,
|
||||
useCamera: useCamera,
|
||||
useMic: useMic,
|
||||
dedEnc: false,
|
||||
mirrorInput: false
|
||||
});
|
||||
|
||||
if (callbacks != null) { // add user supplied callbacks to the current call
|
||||
cur_call.rtc.options.callbacks = $.extend(cur_call.rtc.options.callbacks, callbacks);
|
||||
}
|
||||
}
|
||||
|
||||
// check if logged into verto by seeing if there is a ready websocket connection
|
||||
function isLoggedIntoVerto() {
|
||||
return (verto != null ? (ref = verto.rpcClient) != null ? ref.socketReady() : void 0 : void 0);
|
||||
}
|
||||
|
||||
// overwrite and substitute my own init function
|
||||
init = function(videoTag, vertoServerCredentials) {
|
||||
videoTag = window.videoTag;
|
||||
cur_call = null;
|
||||
share_call = null;
|
||||
incomingBandwidth = "default";
|
||||
configStuns(callbacks, callback, videoTag, vertoServerCredentials);
|
||||
}
|
||||
};
|
||||
|
||||
// checks whether Google Chrome or Firefox have the WebRTCPeerConnection object
|
||||
function isWebRTCAvailable_verto() {
|
||||
return (typeof window.webkitRTCPeerConnection !== 'undefined' || typeof window.mozRTCPeerConnection !== 'undefined');
|
||||
}
|
||||
Verto.prototype.isWebRTCAvailable = function () {
|
||||
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();
|
||||
}
|
||||
this.VertoManager = function () {
|
||||
this.vertoAudio = null;
|
||||
this.vertoVideo = null;
|
||||
this.vertoScreenShare = null;
|
||||
window.vertoHandle = null;
|
||||
};
|
||||
|
||||
function make_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, userCallback, server, recall, options) {
|
||||
if (userCallback) {
|
||||
callback = userCallback;
|
||||
}
|
||||
callPurposefullyEnded = false;
|
||||
Verto.prototype.logout = function () {
|
||||
this.exitAudio();
|
||||
this.exitVideo();
|
||||
this.exitScreenShare();
|
||||
window.vertoHandle.logout();
|
||||
};
|
||||
|
||||
// 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);
|
||||
VertoManager.prototype.exitAudio = function () {
|
||||
if (this.vertoAudio != null) {
|
||||
console.log('Hanging up vertoAudio');
|
||||
this.vertoAudio.hangup();
|
||||
this.vertoAudio = null;
|
||||
}
|
||||
};
|
||||
this.RTCPeerConnectionCallbacks = RTCPeerConnectionCallbacks;
|
||||
|
||||
window.verto_afterStreamPublish = function() {}
|
||||
VertoManager.prototype.exitVideo = function () {
|
||||
if (this.vertoVideo != null) {
|
||||
console.log('Hanging up vertoVideo');
|
||||
this.vertoVideo.hangup();
|
||||
this.vertoVideo = null;
|
||||
}
|
||||
};
|
||||
|
||||
function webrtc_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, userCallback, options) {
|
||||
if (userCallback) {
|
||||
callback = userCallback;
|
||||
VertoManager.prototype.exitScreenShare = function () {
|
||||
if (this.vertoScreenShare != null) {
|
||||
console.log('Hanging up vertoScreenShare');
|
||||
this.vertoScreenShare.hangup();
|
||||
this.vertoScreenShare = null;
|
||||
}
|
||||
console.log("webrtc_call\n"+voiceBridge + ", " + conferenceUsername + ", " + conferenceIdNumber + ", " + callback);
|
||||
};
|
||||
|
||||
if(!isWebRTCAvailable()) {
|
||||
callback({'status': 'failed', 'errorcode': 1003}); // Browser version not supported
|
||||
return;
|
||||
}
|
||||
VertoManager.prototype.joinListenOnly = function (tag) {
|
||||
this.exitAudio();
|
||||
var obj = Object.create(Verto.prototype);
|
||||
Verto.apply(obj, arguments);
|
||||
this.vertoAudio = obj;
|
||||
this.vertoAudio.setListenOnly(tag);
|
||||
};
|
||||
|
||||
var server = window.document.location.hostname;
|
||||
console.log("user " + conferenceUsername + " calling to " + voiceBridge);
|
||||
if (isLoggedIntoVerto()) {
|
||||
make_call_verto(voiceBridge, conferenceUsername, conferenceIdNumber, callback, "", false, options);
|
||||
}
|
||||
}
|
||||
VertoManager.prototype.joinMicrophone = function (tag) {
|
||||
this.exitAudio();
|
||||
var obj = Object.create(Verto.prototype);
|
||||
Verto.apply(obj, arguments);
|
||||
this.vertoAudio = obj;
|
||||
this.vertoAudio.setMicrophone(tag);
|
||||
};
|
||||
|
||||
function webrtc_hangup_verto(userCallback) {
|
||||
if (userCallback) {
|
||||
callback = userCallback;
|
||||
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();
|
||||
}
|
||||
callPurposefullyEnded = true;
|
||||
console.log("Hanging up current session");
|
||||
if(verto) {
|
||||
verto.hangup(false, callback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
@ -21,11 +21,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
|
||||
xmlns:maps="org.bigbluebutton.modules.deskShare.maps.*"
|
||||
|
||||
implements="org.bigbluebutton.common.IBigBlueButtonModule"
|
||||
creationComplete="onCreationComplete()" xmlns:maps1="org.bigbluebutton.modules.screenshare.maps.*">
|
||||
|
||||
<maps1:ScreenshareEventMap id="deskshareGlobalEventMap" />
|
||||
<maps1:WebRTCDeskshareEventMap id="webRTCDeskshareEventMap" />
|
||||
|
||||
<mx:Script>
|
||||
<![CDATA[
|
||||
|
@ -109,23 +109,26 @@ package org.bigbluebutton.modules.deskshare.managers
|
||||
private function startWebRTCDeskshare():void {
|
||||
LOGGER.debug("DeskshareManager::startWebRTCDeskshare");
|
||||
|
||||
var result:String;
|
||||
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 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 {
|
||||
JSLog.warn("onFail - as", args);
|
||||
JSLog.warn("WebRTCDeskshareManager::startWebRTCDeskshare - falling back to java", {});
|
||||
globalDispatcher.dispatchEvent(new UseJavaModeCommand())
|
||||
};
|
||||
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.ScreenshareOptions;
|
||||
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 {
|
||||
private static const LOGGER:ILogger = getClassLogger(ScreenshareManager);
|
||||
@ -43,6 +46,7 @@ package org.bigbluebutton.modules.screenshare.managers {
|
||||
private var service:ScreenshareService;
|
||||
private var globalDispatcher:Dispatcher;
|
||||
private var sharing:Boolean = false;
|
||||
private var usingJava:Boolean = true;
|
||||
|
||||
public function ScreenshareManager() {
|
||||
service = new ScreenshareService();
|
||||
@ -109,7 +113,6 @@ package org.bigbluebutton.modules.screenshare.managers {
|
||||
dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
||||
}
|
||||
|
||||
|
||||
private function initDeskshare():void {
|
||||
sharing = false;
|
||||
var option:ScreenshareOptions = new ScreenshareOptions();
|
||||
@ -141,10 +144,16 @@ package org.bigbluebutton.modules.screenshare.managers {
|
||||
toolbarButtonManager.startedSharing();
|
||||
var option:ScreenshareOptions = new ScreenshareOptions();
|
||||
option.parseOptions();
|
||||
|
||||
if (option.useWebRTCIfAvailable && !BrowserCheck.isWebRTCSupported()) {
|
||||
usingJava = true;
|
||||
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 {
|
||||
@ -187,8 +196,19 @@ package org.bigbluebutton.modules.screenshare.managers {
|
||||
|
||||
private function handleStreamStartEvent(streamId:String, videoWidth:Number, videoHeight:Number):void {
|
||||
LOGGER.debug("Received start vieweing command");
|
||||
if (!usingJava) { return; }
|
||||
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.managers.ScreenshareManager;
|
||||
import org.bigbluebutton.modules.screenshare.services.red5.ConnectionEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.UseJavaModeCommand;
|
||||
import org.bigbluebutton.modules.screenshare.events.DeskshareToolbarEvent;
|
||||
]]>
|
||||
</mx:Script>
|
||||
<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}"/>
|
||||
</EventHandlers>
|
||||
|
||||
<EventHandlers type="{UseJavaModeCommand.USE_JAVA_MODE}">
|
||||
<MethodInvoker generator="{ScreenshareManager}" method="handleUseJavaModeCommand"/>
|
||||
</EventHandlers>
|
||||
|
||||
<EventHandlers type="{DeskshareToolbarEvent.STOP}">
|
||||
<MethodInvoker generator="{ScreenshareManager}" method="handleDeskshareToolbarStopEvent"/>
|
||||
</EventHandlers>
|
||||
|
||||
</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>
|
@ -26,6 +26,8 @@ package org.bigbluebutton.modules.screenshare.model
|
||||
[Bindable] public var autoStart:Boolean = false;
|
||||
[Bindable] public var autoFullScreen:Boolean = false;
|
||||
[Bindable] public var baseTabIndex:int;
|
||||
[Bindable] public var useWebRTCIfAvailable:Boolean = true;
|
||||
[Bindable] public var chromeExtensionKey:String = null;
|
||||
[Bindable] public var helpUrl:String;
|
||||
|
||||
public function parseOptions():void {
|
||||
@ -46,6 +48,12 @@ package org.bigbluebutton.modules.screenshare.model
|
||||
if (vxml.@showButton != undefined){
|
||||
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){
|
||||
helpUrl = vxml.@help;
|
||||
}
|
||||
|
@ -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.UploadEvent;
|
||||
import org.bigbluebutton.modules.users.events.MeetingMutedEvent;
|
||||
import org.bigbluebutton.modules.deskshare.events.ViewStreamEvent;
|
||||
import org.bigbluebutton.modules.deskshare.events.WebRTCViewStreamEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.ViewStreamEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.WebRTCViewStreamEvent;
|
||||
import org.bigbluebutton.main.api.JSLog;
|
||||
import org.bigbluebutton.modules.users.events.MeetingMutedEvent;
|
||||
|
||||
@ -175,6 +175,8 @@ package org.bigbluebutton.modules.users.services
|
||||
|
||||
private function handleDeskShareRTMPBroadcastNotification(msg:Object):void {
|
||||
LOGGER.debug("*** handleDeskShareRTMPBroadcastNotification **** \n", [msg]);
|
||||
JSLog.warn("*** handleDeskShareRTMPBroadcastNotification **** url=", msg.rtmpUrl);
|
||||
JSLog.warn("*** handleDeskShareRTMPBroadcastNotification **** broadcasting=", msg.broadcasting);
|
||||
|
||||
var event:WebRTCViewStreamEvent;
|
||||
if (msg.broadcasting) {
|
||||
|
@ -32,8 +32,9 @@ function loadLib(libname, success, fail) {
|
||||
}
|
||||
};
|
||||
|
||||
const failCallback = function (cb) {
|
||||
console.log(`failed to load lib - ${this}`);
|
||||
const failCallback = function (cb, issue) {
|
||||
console.error(`failed to load lib - ${this}`);
|
||||
console.error(issue);
|
||||
if (typeof (cb) == 'function' || cb instanceof Function) {
|
||||
cb();
|
||||
}
|
||||
@ -49,12 +50,9 @@ Meteor.startup(() => {
|
||||
loadLib('bbblogger.js');
|
||||
loadLib('jquery.json-2.4.min.js');
|
||||
loadLib('jquery.FSRTC.js');
|
||||
loadLib('jquery.verto.js', function () {
|
||||
loadLib('jquery.verto.js');
|
||||
loadLib('verto_extension.js');
|
||||
});
|
||||
|
||||
loadLib('jquery.jsonrpcclient.js');
|
||||
loadLib('verto_extension_share.js');
|
||||
|
||||
render((
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
|
@ -58,14 +58,6 @@ clientConfig.media = {};
|
||||
|
||||
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
|
||||
clientConfig.media.useSIPAudio = true;
|
||||
|
||||
|
@ -3,7 +3,7 @@ import Meetings from '/imports/api/meetings';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import {callServer} from '/imports/ui/services/api';
|
||||
import {clientConfig} from '/config';
|
||||
import {createVertoUserName, joinVertoAudio} from '/imports/api/verto';
|
||||
import {vertoExitAudio, vertoJoinListenOnly, vertoJoinMicrophone} from '/imports/api/verto';
|
||||
|
||||
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
|
||||
// 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) {
|
||||
window.leaveWebRTCVoiceConference_verto();
|
||||
window.cur_call = null;
|
||||
vertoExitAudio();
|
||||
return;
|
||||
} else {
|
||||
// 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
|
||||
function joinVoiceCall(options) {
|
||||
function joinVoiceCallSIP(options) {
|
||||
const extension = getVoiceBridge();
|
||||
console.log(options);
|
||||
if (clientConfig.media.useSIPAudio) {
|
||||
@ -82,10 +81,6 @@ function joinVoiceCall(options) {
|
||||
console.log('Beginning WebRTC Conference Call');
|
||||
};
|
||||
|
||||
if (options.isListenOnly) {
|
||||
callServer('listenOnlyRequestToggle', true);
|
||||
}
|
||||
|
||||
window.BBB = {};
|
||||
window.BBB.getMyUserInfo = function (callback) {
|
||||
const uid = Auth.userID;
|
||||
@ -104,12 +99,24 @@ function joinVoiceCall(options) {
|
||||
|
||||
callIntoConference(extension, function () {}, options.isListenOnly);
|
||||
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 { clientConfig } from '/config';
|
||||
import { getVoiceBridge } from '/imports/api/phone';
|
||||
@ -9,61 +11,50 @@ function createVertoUserName() {
|
||||
return conferenceUsername;
|
||||
}
|
||||
|
||||
function joinVertoAudio(options) {
|
||||
joinVertoCall(options);
|
||||
function vertoExitAudio() {
|
||||
window.vertoExitAudio();
|
||||
}
|
||||
|
||||
function watchVertoVideo(options) {
|
||||
joinVertoCall(options);
|
||||
function vertoJoinListenOnly() {
|
||||
window.vertoJoinListenOnly(
|
||||
'remote-media',
|
||||
getVoiceBridge(),
|
||||
createVertoUserName(),
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
function joinVertoCall(options) {
|
||||
console.log('joinVertoCall');
|
||||
const extension = options.extension || getVoiceBridge();
|
||||
function vertoJoinMicrophone() {
|
||||
window.vertoJoinMicrophone(
|
||||
'remote-media',
|
||||
getVoiceBridge(),
|
||||
createVertoUserName(),
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
if (!isWebRTCAvailable()) {
|
||||
return;
|
||||
}
|
||||
function vertoWatchVideo() {
|
||||
window.vertoWatchVideo(
|
||||
'deskshareVideo',
|
||||
getVoiceBridge(),
|
||||
createVertoUserName(),
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
if (!clientConfig.useSIPAudio) {
|
||||
const vertoServerCredentials = {
|
||||
vertoPort: clientConfig.media.vertoPort,
|
||||
hostName: clientConfig.media.vertoServerAddress,
|
||||
login: conferenceIdNumber,
|
||||
password: clientConfig.media.freeswitchProfilePassword,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
function shareVertoScreen() {
|
||||
vertoManager.shareScreen(
|
||||
'deskshareVideo',
|
||||
getVoiceBridge(),
|
||||
createVertoUserName(),
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
createVertoUserName,
|
||||
joinVertoAudio,
|
||||
watchVertoVideo,
|
||||
vertoJoinListenOnly,
|
||||
vertoJoinMicrophone,
|
||||
vertoWatchVideo,
|
||||
vertoExitAudio,
|
||||
shareVertoScreen,
|
||||
};
|
||||
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||
export default class DeskshareComponent extends React.Component {
|
||||
render() {
|
||||
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 {createVertoUserName, joinVertoAudio, watchVertoVideo} from '/imports/api/verto';
|
||||
import {createVertoUserName, watchVertoVideo} from '/imports/api/verto';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
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
|
||||
function presenterDeskshareHasEnded() {
|
||||
// exitVoiceCall();
|
||||
@ -42,13 +34,9 @@ function presenterDeskshareHasEnded() {
|
||||
|
||||
// if remote deskshare has been started connect and display the video stream
|
||||
function presenterDeskshareHasStarted() {
|
||||
const voiceBridge = Deskshare.findOne().deskshare.voiceBridge;
|
||||
watchDeskshare({
|
||||
watchOnly: true,
|
||||
extension: voiceBridge,
|
||||
});
|
||||
vertoWatchVideo();
|
||||
};
|
||||
|
||||
export { videoIsBroadcasting, watchDeskshare, presenterDeskshareHasEnded,
|
||||
presenterDeskshareHasStarted
|
||||
export {
|
||||
videoIsBroadcasting, presenterDeskshareHasEnded, presenterDeskshareHasStarted
|
||||
};
|
||||
|
@ -3,7 +3,7 @@ import Modal from 'react-modal';
|
||||
import Icon from '/imports/ui/components/icon/component';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
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 {
|
||||
constructor(props) {
|
||||
@ -14,24 +14,6 @@ export default class AudioMenu extends BaseMenu {
|
||||
return (
|
||||
<div>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ dependencies {
|
||||
|
||||
//redis
|
||||
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 '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