Merge branch 'master' of https://github.com/bigbluebutton/bigbluebutton into closed-captioning-ui

This commit is contained in:
Oleksandr Zhurbenko 2016-10-04 13:56:13 -07:00
commit 8fcd97d278
225 changed files with 3550 additions and 4588 deletions

View File

@ -111,8 +111,8 @@ public interface IBigBlueButtonInGW {
// Caption
void sendCaptionHistory(String meetingID, String requesterID);
void updateCaptionOwner(String meetingID, String locale, String ownerID);
void editCaptionHistory(String meetingID, String userID, Integer startIndex, Integer endIndex, String locale, String text);
void updateCaptionOwner(String meetingID, String locale, String localeCode, String ownerID);
void editCaptionHistory(String meetingID, String userID, Integer startIndex, Integer endIndex, String locale, String localeCode, String text);
// DeskShare
void deskShareStarted(String confId, String callerId, String callerIdName);

View File

@ -32,10 +32,10 @@ public class CaptionMessageReceiver implements MessageHandler{
bbbGW.sendCaptionHistory(msg.meetingID, msg.requesterID);
} else if (UpdateCaptionOwnerMessage.UPDATE_CAPTION_OWNER.equals(messageName)) {
UpdateCaptionOwnerMessage msg = UpdateCaptionOwnerMessage.fromJson(message);
bbbGW.updateCaptionOwner(msg.meetingID, msg.locale, msg.ownerID);
bbbGW.updateCaptionOwner(msg.meetingID, msg.locale, msg.localeCode, msg.ownerID);
} else if (EditCaptionHistoryMessage.EDIT_CAPTION_HISTORY.equals(messageName)) {
EditCaptionHistoryMessage msg = EditCaptionHistoryMessage.fromJson(message);
bbbGW.editCaptionHistory(msg.meetingID, msg.userID, msg.startIndex, msg.endIndex, msg.locale, msg.text);
bbbGW.editCaptionHistory(msg.meetingID, msg.userID, msg.startIndex, msg.endIndex, msg.locale, msg.localeCode, msg.text);
}
}
}

View File

@ -23,6 +23,7 @@ public class EditCaptionHistoryRecordEvent extends AbstractCaptionRecordEvent {
private static final String START_INDEX = "startIndex";
private static final String END_INDEX = "endIndex";
private static final String LOCALE = "locale";
private static final String LOCALE_CODE = "localeCode";
private static final String TEXT = "text";
public EditCaptionHistoryRecordEvent() {
@ -33,7 +34,7 @@ public class EditCaptionHistoryRecordEvent extends AbstractCaptionRecordEvent {
public void setStartIndex(String startIndex) {
eventMap.put(START_INDEX, startIndex);
}
public void setEndIndex(String endIndex) {
eventMap.put(END_INDEX, endIndex);
}
@ -42,6 +43,10 @@ public class EditCaptionHistoryRecordEvent extends AbstractCaptionRecordEvent {
eventMap.put(LOCALE, locale);
}
public void setLocaleCode(String localeCode) {
eventMap.put(LOCALE_CODE, localeCode);
}
public void setText(String text) {
eventMap.put(TEXT, text);
}

View File

@ -28,6 +28,10 @@ public class ParticipantJoinRecordEvent extends AbstractParticipantRecordEvent {
public void setUserId(String userId) {
eventMap.put("userId", userId);
}
public void setExternalUserId(String externalUserId) {
eventMap.put("externalUserId", externalUserId);
}
public void setName(String name){
eventMap.put("name",name);

View File

@ -43,7 +43,6 @@ http {
services {
bbbWebAPI = "http://192.168.23.33/bigbluebutton/api"
sharedSecret = "changeme"
defaultPresentationURL = "http://localhost/default.pdf"
}
red5 {

View File

@ -18,7 +18,6 @@ trait SystemConfiguration {
lazy val bbbWebSharedSecret = Try(config.getString("services.sharedSecret")).getOrElse("changeme")
lazy val bbbWebModeratorPassword = Try(config.getString("services.moderatorPassword")).getOrElse("changeme")
lazy val bbbWebViewerPassword = Try(config.getString("services.viewerPassword")).getOrElse("changeme")
lazy val bbbWebDefaultPresentationURL = Try(config.getString("services.defaultPresentationURL")).getOrElse("changeme")
lazy val keysExpiresInSec = Try(config.getInt("redis.keyExpiry")).getOrElse(14 * 86400) // 14 days
lazy val red5DeskShareIP = Try(config.getString("red5.deskshareip")).getOrElse("127.0.0.1")
lazy val red5DeskShareApp = Try(config.getString("red5.deskshareapp")).getOrElse("")

View File

@ -39,7 +39,7 @@ class BigBlueButtonInGW(
case msg: StartCustomPollRequestMessage => {
eventBus.publish(
BigBlueButtonEvent(
"meeting-manager",
msg.payload.meetingId,
new StartCustomPollRequest(
msg.payload.meetingId,
msg.payload.requesterId,
@ -558,11 +558,11 @@ class BigBlueButtonInGW(
eventBus.publish(BigBlueButtonEvent(meetingID, new SendCaptionHistoryRequest(meetingID, requesterID)))
}
def updateCaptionOwner(meetingID: String, locale: String, ownerID: String) {
eventBus.publish(BigBlueButtonEvent(meetingID, new UpdateCaptionOwnerRequest(meetingID, locale, ownerID)))
def updateCaptionOwner(meetingID: String, locale: String, localeCode: String, ownerID: String) {
eventBus.publish(BigBlueButtonEvent(meetingID, new UpdateCaptionOwnerRequest(meetingID, locale, localeCode, ownerID)))
}
def editCaptionHistory(meetingID: String, userID: String, startIndex: Integer, endIndex: Integer, locale: String, text: String) {
eventBus.publish(BigBlueButtonEvent(meetingID, new EditCaptionHistoryRequest(meetingID, userID, startIndex, endIndex, locale, text)))
def editCaptionHistory(meetingID: String, userID: String, startIndex: Integer, endIndex: Integer, locale: String, localeCode: String, text: String) {
eventBus.publish(BigBlueButtonEvent(meetingID, new EditCaptionHistoryRequest(meetingID, userID, startIndex, endIndex, locale, localeCode, text)))
}
}

View File

@ -94,7 +94,7 @@ class JsonMessageSenderActor(val service: MessageSender)
private def handleCreateBreakoutRoom(msg: CreateBreakoutRoom) {
val payload = new CreateBreakoutRoomRequestPayload(msg.room.breakoutId, msg.room.parentId, msg.room.name,
msg.room.voiceConfId, msg.room.viewerPassword, msg.room.moderatorPassword,
msg.room.durationInMinutes, msg.room.defaultPresentationURL, msg.room.record)
msg.room.durationInMinutes, msg.room.sourcePresentationId, msg.room.sourcePresentationSlide, msg.room.record)
val request = new CreateBreakoutRoomRequest(payload)
service.send(MessagingConstants.FROM_MEETING_CHANNEL, request.toJson())
}

View File

@ -117,7 +117,7 @@ class LiveMeeting(val mProps: MeetingProperties,
meetingModel.meetingHasEnded
/**
* See if this meeting has breakout rooms. If so, we also need to end them.
* Check if this meeting has breakout rooms. If so, we also need to end them.
*/
handleEndAllBreakoutRooms(new EndAllBreakoutRooms(msg.meetingId))

View File

@ -33,7 +33,7 @@ object UserMessagesProtocol extends DefaultJsonProtocol {
implicit val inMsgHeaderFormat = jsonFormat1(InMessageHeader)
implicit val outMsgHeaderFormat = jsonFormat1(OutMsgHeader)
implicit val outMsgEnvelopeHeaderFormat = jsonFormat2(OutMsgEnvelopeHeader)
implicit val createBreakoutRoomOutMsgPayloadFormat = jsonFormat8(CreateBreakoutRoomOutMsgPayload)
implicit val createBreakoutRoomOutMsgPayloadFormat = jsonFormat10(CreateBreakoutRoomOutMsgPayload)
implicit val createBreakoutRoomOutMsgEnvelopePayloadFormat = jsonFormat2(CreateBreakoutRoomOutMsgEnvelopePayload)
implicit val createBreakoutRoomOutMsgEnvelopeFormat = jsonFormat2(CreateBreakoutRoomOutMsgEnvelope)

View File

@ -5,12 +5,10 @@ case class OutMsgEnvelopeHeader(`type`: MessageType.MessageType, address: String
trait OutMessage
case class CreateBreakoutRoomOutMsgEnvelope(header: OutMsgEnvelopeHeader,
payload: CreateBreakoutRoomOutMsgEnvelopePayload)
case class CreateBreakoutRoomOutMsgEnvelopePayload(header: OutMsgHeader,
payload: CreateBreakoutRoomOutMsgPayload)
case class CreateBreakoutRoomOutMsgEnvelope(header: OutMsgEnvelopeHeader, payload: CreateBreakoutRoomOutMsgEnvelopePayload)
case class CreateBreakoutRoomOutMsgEnvelopePayload(header: OutMsgHeader, payload: CreateBreakoutRoomOutMsgPayload)
case class CreateBreakoutRoomOutMsgPayload(breakoutId: String, name: String, parentId: String,
voiceConfId: String, durationInMinutes: Int,
moderatorPassword: String, viewerPassword: String,
defaultPresentationUrl: String)
sourcePresentationId: String, sourcePresentationSlide: Int, record: Boolean)

View File

@ -196,6 +196,7 @@ class RecorderActor(val recorder: RecorderApplication)
val ev = new ParticipantJoinRecordEvent();
ev.setTimestamp(TimestampGenerator.generateTimestamp);
ev.setUserId(msg.user.userID);
ev.setExternalUserId(msg.user.externUserID);
ev.setName(msg.user.name);
ev.setMeetingId(msg.meetingID);
ev.setRole(msg.user.role.toString());
@ -452,6 +453,7 @@ class RecorderActor(val recorder: RecorderApplication)
ev.setStartIndex(msg.startIndex.toString());
ev.setEndIndex(msg.endIndex.toString());
ev.setLocale(msg.locale);
ev.setLocaleCode(msg.localeCode);
ev.setText(msg.text);
recorder.record(msg.meetingID, ev);
}

View File

@ -187,8 +187,8 @@ case class GetAllMeetingsRequest(meetingID: String /** Not used. Just to satisfy
// Caption
case class SendCaptionHistoryRequest(meetingID: String, requesterID: String) extends InMessage
case class UpdateCaptionOwnerRequest(meetingID: String, locale: String, ownerID: String) extends InMessage
case class EditCaptionHistoryRequest(meetingID: String, userID: String, startIndex: Integer, endIndex: Integer, locale: String, text: String) extends InMessage
case class UpdateCaptionOwnerRequest(meetingID: String, locale: String, localeCode: String, ownerID: String) extends InMessage
case class EditCaptionHistoryRequest(meetingID: String, userID: String, startIndex: Integer, endIndex: Integer, locale: String, localeCode: String, text: String) extends InMessage
// DeskShare
case class DeskShareStartedRequest(conferenceName: String, callerId: String, callerIdName: String) extends InMessage
case class DeskShareStoppedRequest(conferenceName: String, callerId: String, callerIdName: String) extends InMessage

View File

@ -33,7 +33,7 @@ case class CreateBreakoutRoom(meetingId: String, room: BreakoutRoomOutPayload) e
case class EndBreakoutRoom(breakoutId: String) extends IOutMessage
case class BreakoutRoomOutPayload(breakoutId: String, name: String, parentId: String,
voiceConfId: String, durationInMinutes: Int, moderatorPassword: String, viewerPassword: String,
defaultPresentationURL: String, record: Boolean)
sourcePresentationId: String, sourcePresentationSlide: Int, record: Boolean)
case class BreakoutRoomJoinURLOutMessage(meetingId: String, recorded: Boolean, breakoutId: String, userId: String, joinURL: String) extends IOutMessage
case class BreakoutRoomStartedOutMessage(meetingId: String, recorded: Boolean, breakout: BreakoutRoomBody) extends IOutMessage
case class BreakoutRoomBody(name: String, breakoutId: String)
@ -146,10 +146,10 @@ case class WhiteboardEnabledEvent(meetingID: String, recorded: Boolean, requeste
case class IsWhiteboardEnabledReply(meetingID: String, recorded: Boolean, requesterID: String, enabled: Boolean, replyTo: String) extends IOutMessage
case class GetAllMeetingsReply(meetings: Array[MeetingInfo]) extends IOutMessage
// Chat
// Caption
case class SendCaptionHistoryReply(meetingID: String, recorded: Boolean, requesterID: String, history: Map[String, Array[String]]) extends IOutMessage
case class UpdateCaptionOwnerReply(meetingID: String, recorded: Boolean, locale: String, ownerID: String) extends IOutMessage
case class EditCaptionHistoryReply(meetingID: String, recorded: Boolean, userID: String, startIndex: Integer, endIndex: Integer, locale: String, text: String) extends IOutMessage
case class UpdateCaptionOwnerReply(meetingID: String, recorded: Boolean, locale: String, localeCode: String, ownerID: String) extends IOutMessage
case class EditCaptionHistoryReply(meetingID: String, recorded: Boolean, userID: String, startIndex: Integer, endIndex: Integer, locale: String, localeCode: String, text: String) extends IOutMessage
// DeskShare
case class DeskShareStartRTMPBroadcast(conferenceName: String, streamPath: String) extends IOutMessage
case class DeskShareStopRTMPBroadcast(conferenceName: String, streamPath: String) extends IOutMessage

View File

@ -20,15 +20,6 @@ trait BreakoutRoomApp extends SystemConfiguration {
val outGW: OutMessageGateway
val eventBus: IncomingEventBus
def getDefaultPresentationURL(): String = {
var presURL = bbbWebDefaultPresentationURL
val page = presModel.getCurrentPage()
page foreach { p =>
presURL = BreakoutRoomsUtil.fromSWFtoPDF(p.swfUri)
}
presURL
}
def handleBreakoutRoomsList(msg: BreakoutRoomsListMessage) {
val breakoutRooms = breakoutModel.getRooms().toVector map { r => new BreakoutRoomBody(r.name, r.id) }
outGW.send(new BreakoutRoomsListOutMessage(mProps.meetingID, breakoutRooms, breakoutModel.pendingRoomsNumber == 0 && breakoutRooms.length > 0));
@ -40,17 +31,20 @@ trait BreakoutRoomApp extends SystemConfiguration {
log.warning("CreateBreakoutRooms event received while {} are pending to be created for meeting {}", breakoutModel.pendingRoomsNumber, mProps.meetingID)
return
}
var i = 0
val sourcePresentationId = presModel.getCurrentPresentation().get.id
val sourcePresentationSlide = presModel.getCurrentPage().get.num
breakoutModel.pendingRoomsNumber = msg.rooms.length;
for (room <- msg.rooms) {
i += 1
val presURL = bbbWebDefaultPresentationURL
val breakoutMeetingId = BreakoutRoomsUtil.createMeetingId(mProps.meetingID, i)
val voiceConfId = BreakoutRoomsUtil.createVoiceConfId(mProps.voiceBridge, i)
val r = breakoutModel.createBreakoutRoom(breakoutMeetingId, room.name, voiceConfId, room.users, presURL)
val r = breakoutModel.createBreakoutRoom(breakoutMeetingId, room.name, voiceConfId, room.users)
val p = new BreakoutRoomOutPayload(r.id, r.name, mProps.meetingID,
r.voiceConfId, msg.durationInMinutes, mProps.moderatorPass, mProps.viewerPass,
r.defaultPresentationURL, msg.record)
sourcePresentationId, sourcePresentationSlide, msg.record)
outGW.send(new CreateBreakoutRoom(mProps.meetingID, p))
}
meetingModel.breakoutRoomsdurationInMinutes = msg.durationInMinutes;
@ -85,7 +79,7 @@ trait BreakoutRoomApp extends SystemConfiguration {
breakoutModel.getRooms().foreach { room =>
breakoutModel.getAssignedUsers(room.id) foreach { users =>
users.foreach { u =>
log.debug("## Sending Join URL for users: {}", u);
log.debug("Sending Join URL for users: {}", u);
sendJoinURL(u, room.id)
}
}
@ -181,7 +175,7 @@ object BreakoutRoomsUtil {
}
def joinParams(username: String, userId: String, isBreakout: Boolean, breakoutId: String,
password: String, redirect: Boolean): mutable.Map[String, String] = {
password: String, redirect: Boolean): mutable.Map[String, String] = {
val params = new collection.mutable.HashMap[String, String]
params += "fullName" -> urlEncode(username)
params += "userID" -> urlEncode(userId + "-" + breakoutId.substring(breakoutId.lastIndexOf("-") + 1));

View File

@ -5,7 +5,7 @@ import scala.collection.immutable.HashMap
case class BreakoutUser(id: String, name: String)
case class BreakoutRoom(id: String, name: String, voiceConfId: String,
assignedUsers: Vector[String], users: Vector[BreakoutUser], defaultPresentationURL: String)
assignedUsers: Vector[String], users: Vector[BreakoutUser])
class BreakoutRoomModel {
private var rooms = new collection.immutable.HashMap[String, BreakoutRoom]
@ -22,8 +22,8 @@ class BreakoutRoomModel {
}
def createBreakoutRoom(id: String, name: String, voiceConfId: String,
assignedUsers: Vector[String], defaultPresentationURL: String): BreakoutRoom = {
val room = new BreakoutRoom(id, name, voiceConfId, assignedUsers, Vector(), defaultPresentationURL)
assignedUsers: Vector[String]): BreakoutRoom = {
val room = new BreakoutRoom(id, name, voiceConfId, assignedUsers, Vector())
add(room)
}

View File

@ -13,7 +13,7 @@ trait CaptionApp {
def handleSendCaptionHistoryRequest(msg: SendCaptionHistoryRequest) {
var history = captionModel.getHistory()
//println("Caption history requested " + history)
outGW.send(new SendCaptionHistoryReply(mProps.meetingID, mProps.recorded, msg.requesterID, history))
}
@ -24,17 +24,17 @@ trait CaptionApp {
captionModel.changeTranscriptOwner(t, "")
// send notification that owner has changed
outGW.send(new UpdateCaptionOwnerReply(mProps.meetingID, mProps.recorded, t, ""))
outGW.send(new UpdateCaptionOwnerReply(mProps.meetingID, mProps.recorded, t, captionModel.findLocaleCodeByLocale(t), ""))
})
}
// create the locale if it doesn't exist
if (captionModel.transcripts contains msg.locale) {
captionModel.changeTranscriptOwner(msg.locale, msg.ownerID)
} else { // change the owner if it does exist
captionModel.newTranscript(msg.locale, msg.ownerID)
captionModel.newTranscript(msg.locale, msg.localeCode, msg.ownerID)
}
outGW.send(new UpdateCaptionOwnerReply(mProps.meetingID, mProps.recorded, msg.locale, msg.ownerID))
outGW.send(new UpdateCaptionOwnerReply(mProps.meetingID, mProps.recorded, msg.locale, msg.localeCode, msg.ownerID))
}
def handleEditCaptionHistoryRequest(msg: EditCaptionHistoryRequest) {
@ -42,7 +42,7 @@ trait CaptionApp {
if (t == msg.locale) {
captionModel.editHistory(msg.startIndex, msg.endIndex, msg.locale, msg.text)
outGW.send(new EditCaptionHistoryReply(mProps.meetingID, mProps.recorded, msg.userID, msg.startIndex, msg.endIndex, msg.locale, msg.text))
outGW.send(new EditCaptionHistoryReply(mProps.meetingID, mProps.recorded, msg.userID, msg.startIndex, msg.endIndex, msg.locale, msg.localeCode, msg.text))
}
})
}
@ -52,7 +52,7 @@ trait CaptionApp {
captionModel.changeTranscriptOwner(t, "")
// send notification that owner has changed
outGW.send(new UpdateCaptionOwnerReply(mProps.meetingID, mProps.recorded, t, ""))
outGW.send(new UpdateCaptionOwnerReply(mProps.meetingID, mProps.recorded, t, captionModel.findLocaleCodeByLocale(t), ""))
})
}
}

View File

@ -6,8 +6,8 @@ import scala.collection.immutable.HashMap
class CaptionModel {
var transcripts = Map[String, Array[String]]()
def newTranscript(locale: String, ownerId: String) {
transcripts += locale -> Array(ownerId, "")
def newTranscript(locale: String, localeCode: String, ownerId: String) {
transcripts += locale -> Array(ownerId, "", localeCode)
}
def findLocaleByOwnerId(userId: String): Option[String] = {
@ -18,6 +18,14 @@ class CaptionModel {
return None
}
def findLocaleCodeByLocale(locale: String): String = {
if (transcripts contains locale) {
return transcripts(locale)(2)
}
return ""
}
def changeTranscriptOwner(locale: String, ownerId: String) {
if (transcripts contains locale) {
transcripts(locale)(0) = ownerId
@ -28,25 +36,25 @@ class CaptionModel {
var history = Map[String, Array[String]]()
transcripts.foreach(t => {
history += t._1 -> Array(t._2(0), t._2(1))
history += t._1 -> Array(t._2(0), t._2(1), t._2(2))
})
history
}
def editHistory(startIndex: Integer, endIndex: Integer, locale: String, text: String) {
println("editHistory entered")
//println("editHistory entered")
if (transcripts contains locale) {
println("editHistory found locale:" + locale)
//println("editHistory found locale:" + locale)
var oText: String = transcripts(locale)(1)
if (startIndex >= 0 && endIndex <= oText.length && startIndex <= endIndex) {
println("editHistory passed index test")
//println("editHistory passed index test")
var sText: String = oText.substring(0, startIndex)
var eText: String = oText.substring(endIndex)
transcripts(locale)(1) = (sText + text + eText)
println("editHistory new history is: " + transcripts(locale)(1))
//println("editHistory new history is: " + transcripts(locale)(1))
}
}
}

View File

@ -94,16 +94,10 @@ trait PresentationApp {
}
def handleGotoSlide(msg: GotoSlide) {
// println("Received GotoSlide for meeting=[" + msg.meetingID + "] page=[" + msg.page + "]")
// println("*** Before change page ****")
// printPresentations
presModel.changePage(msg.page) foreach { page =>
// println("Switching page for meeting=[" + msg.meetingID + "] page=[" + page.id + "]")
log.debug("Switching page for meeting=[{}] page=[{}]", msg.meetingID, page.num);
outGW.send(new GotoSlideOutMsg(mProps.meetingID, mProps.recorded, page))
}
// println("*** After change page ****")
// printPresentations
usersModel.getCurrentPresenter() foreach { pres =>
handleStopPollRequest(StopPollRequest(mProps.meetingID, pres.userID))

View File

@ -23,6 +23,7 @@ object CaptionMessageToJsonConverter {
val payload = new java.util.HashMap[String, Any]()
payload.put(Constants.MEETING_ID, msg.meetingID)
payload.put(Constants.LOCALE, msg.locale)
payload.put(Constants.LOCALE_CODE, msg.localeCode)
payload.put(Constants.OWNER_ID, msg.ownerID)
val header = Util.buildHeader(MessageNames.UPDATE_CAPTION_OWNER, None)
@ -36,6 +37,7 @@ object CaptionMessageToJsonConverter {
payload.put(Constants.START_INDEX, msg.startIndex)
payload.put(Constants.END_INDEX, msg.endIndex)
payload.put(Constants.LOCALE, msg.locale)
payload.put(Constants.LOCALE_CODE, msg.localeCode)
payload.put(Constants.TEXT, msg.text)
val header = Util.buildHeader(MessageNames.EDIT_CAPTION_HISTORY, None)

View File

@ -29,7 +29,7 @@ import org.bigbluebutton.freeswitch.voice.freeswitch.actions.EjectUserCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.GetAllUsersCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.MuteUserCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.RecordConferenceCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.TransferUsetToMeetingCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.TransferUserToMeetingCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.*;
import org.freeswitch.esl.client.inbound.Client;
import org.freeswitch.esl.client.inbound.InboundConnectionFailure;
@ -128,7 +128,7 @@ public class ConnectionManager {
}
}
public void tranfer(TransferUsetToMeetingCommand tutmc) {
public void tranfer(TransferUserToMeetingCommand tutmc) {
Client c = manager.getESLClient();
if (c.canSend()) {
c.sendAsyncApiCommand(tutmc.getCommand(), tutmc.getCommandArgs());

View File

@ -31,7 +31,7 @@ import org.bigbluebutton.freeswitch.voice.freeswitch.actions.FreeswitchCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.GetAllUsersCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.MuteUserCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.RecordConferenceCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.TransferUsetToMeetingCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.TransferUserToMeetingCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.*;
public class FreeswitchApplication {
@ -48,9 +48,12 @@ public class FreeswitchApplication {
private final String USER = "0"; /* not used for now */
private volatile boolean sendMessages = false;
private final String audioProfile;
public FreeswitchApplication(ConnectionManager manager) {
public FreeswitchApplication(ConnectionManager manager, String profile) {
this.manager = manager;
this.audioProfile = profile;
}
private void queueMessage(FreeswitchCommand command) {
@ -62,12 +65,13 @@ public class FreeswitchApplication {
}
}
public void transferUserToMeeting(String voiceConfId,
String targetVoiceConfId, String voiceUserId) {
TransferUsetToMeetingCommand tutmc = new TransferUsetToMeetingCommand(
voiceConfId, targetVoiceConfId, voiceUserId, USER);
queueMessage(tutmc);
}
public void transferUserToMeeting(String voiceConfId,
String targetVoiceConfId, String voiceUserId) {
TransferUserToMeetingCommand tutmc = new TransferUserToMeetingCommand(
voiceConfId, targetVoiceConfId, voiceUserId, this.audioProfile,
USER);
queueMessage(tutmc);
}
public void start() {
sendMessages = true;
@ -153,8 +157,8 @@ public class FreeswitchApplication {
EjectAllUsersCommand cmd = (EjectAllUsersCommand) command;
System.out.println("Sending EjectAllUsersCommand for conference = [" + cmd.getRoom() + "]");
manager.ejectAll(cmd);
} else if (command instanceof TransferUsetToMeetingCommand) {
TransferUsetToMeetingCommand cmd = (TransferUsetToMeetingCommand) command;
} else if (command instanceof TransferUserToMeetingCommand) {
TransferUserToMeetingCommand cmd = (TransferUserToMeetingCommand) command;
System.out.println("Sending TransferUsetToMeetingCommand for conference = ["
+ cmd.getRoom() + "]");
manager.tranfer(cmd);

View File

@ -19,21 +19,23 @@
package org.bigbluebutton.freeswitch.voice.freeswitch.actions;
public class TransferUsetToMeetingCommand extends FreeswitchCommand {
public class TransferUserToMeetingCommand extends FreeswitchCommand {
private final String targetRoom;
private final String participant;
private final String targetRoom;
private final String participant;
private final String audioProfile;
public TransferUsetToMeetingCommand(String room, String targetRoom,
String participant, String requesterId) {
super(room, requesterId);
this.targetRoom = targetRoom;
this.participant = participant;
}
public TransferUserToMeetingCommand(String room, String targetRoom,
String participant, String profile, String requesterId) {
super(room, requesterId);
this.targetRoom = targetRoom;
this.participant = participant;
this.audioProfile = profile;
}
@Override
public String getCommandArgs() {
return room + SPACE + "transfer" + SPACE + targetRoom + SPACE
+ participant;
}
@Override
public String getCommandArgs() {
return room + SPACE + "transfer" + SPACE + targetRoom + "@"
+ this.audioProfile + SPACE + participant;
}
}

View File

@ -24,6 +24,9 @@ freeswitch {
port=8021
password="ClueCon"
}
conf {
profile="cdquality"
}
}
redis {

View File

@ -31,7 +31,7 @@ object Boot extends App with SystemConfiguration {
connManager.start()
val fsApplication = new FreeswitchApplication(connManager)
val fsApplication = new FreeswitchApplication(connManager, fsProfile)
fsApplication.start()
val redisMsgReceiver = new RedisMessageReceiver(fsApplication)

View File

@ -10,6 +10,7 @@ trait SystemConfiguration {
lazy val eslHost = Try(config.getString("freeswitch.esl.host")).getOrElse("127.0.0.1")
lazy val eslPort = Try(config.getInt("freeswitch.esl.port")).getOrElse(8021)
lazy val eslPassword = Try(config.getString("freeswitch.esl.password")).getOrElse("ClueCon")
lazy val fsProfile = Try(config.getString("freeswitch.conf.profile")).getOrElse("cdquality")
lazy val redisHost = Try(config.getString("redis.host")).getOrElse("127.0.0.1")
lazy val redisPort = Try(config.getInt("redis.port")).getOrElse(6379)

View File

@ -128,6 +128,7 @@ public class Constants {
public static final String START_INDEX = "start_index";
public static final String END_INDEX = "end_index";
public static final String LOCALE = "locale";
public static final String LOCALE_CODE = "locale_code";
public static final String TEXT = "text";
public static final String OWNER_ID = "owner_id";
public static final String CAPTION_HISTORY = "caption_history";

View File

@ -14,14 +14,16 @@ public class EditCaptionHistoryMessage implements ISubscribedMessage {
public final Integer startIndex;
public final Integer endIndex;
public final String locale;
public final String localeCode;
public final String text;
public EditCaptionHistoryMessage(String meetingID, String userID, Integer startIndex, Integer endIndex, String locale, String text) {
public EditCaptionHistoryMessage(String meetingID, String userID, Integer startIndex, Integer endIndex, String locale, String localeCode, String text) {
this.meetingID = meetingID;
this.userID = userID;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.locale = locale;
this.localeCode = localeCode;
this.text = text;
}
@ -32,6 +34,7 @@ public class EditCaptionHistoryMessage implements ISubscribedMessage {
payload.put(Constants.START_INDEX, startIndex);
payload.put(Constants.END_INDEX, endIndex);
payload.put(Constants.LOCALE, locale);
payload.put(Constants.LOCALE_CODE, localeCode);
payload.put(Constants.TEXT, text);
java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(EDIT_CAPTION_HISTORY, VERSION, null);
@ -55,15 +58,17 @@ public class EditCaptionHistoryMessage implements ISubscribedMessage {
&& payload.has(Constants.START_INDEX)
&& payload.has(Constants.END_INDEX)
&& payload.has(Constants.LOCALE)
&& payload.has(Constants.LOCALE_CODE)
&& payload.has(Constants.TEXT)) {
String meetingID = payload.get(Constants.MEETING_ID).getAsString();
String userID = payload.get(Constants.USER_ID).getAsString();
Integer startIndex = payload.get(Constants.START_INDEX).getAsInt();
Integer endIndex = payload.get(Constants.END_INDEX).getAsInt();
String locale = payload.get(Constants.LOCALE).getAsString();
String localeCode = payload.get(Constants.LOCALE_CODE).getAsString();
String text = payload.get(Constants.TEXT).getAsString();
return new EditCaptionHistoryMessage(meetingID, userID, startIndex, endIndex, locale, text);
return new EditCaptionHistoryMessage(meetingID, userID, startIndex, endIndex, locale, localeCode, text);
}
}
}

View File

@ -26,7 +26,7 @@ public class SendCaptionHistoryReplyMessage implements ISubscribedMessage {
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put(Constants.MEETING_ID, meetingID);
payload.put(Constants.REQUESTER_ID, requesterID);
payload.put(Constants.CHAT_HISTORY, captionHistory);
payload.put(Constants.CAPTION_HISTORY, captionHistory);
java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(SEND_CAPTION_HISTORY_REPLY, VERSION, null);
return MessageBuilder.buildJson(header, payload);

View File

@ -11,11 +11,13 @@ public class UpdateCaptionOwnerMessage implements ISubscribedMessage {
public final String meetingID;
public final String locale;
public final String localeCode;
public final String ownerID;
public UpdateCaptionOwnerMessage(String meetingID, String locale, String ownerID) {
public UpdateCaptionOwnerMessage(String meetingID, String locale, String localeCode, String ownerID) {
this.meetingID = meetingID;
this.locale = locale;
this.localeCode = localeCode;
this.ownerID = ownerID;
}
@ -23,6 +25,7 @@ public class UpdateCaptionOwnerMessage implements ISubscribedMessage {
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put(Constants.MEETING_ID, meetingID);
payload.put(Constants.LOCALE, locale);
payload.put(Constants.LOCALE_CODE, localeCode);
payload.put(Constants.OWNER_ID, ownerID);
java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(UPDATE_CAPTION_OWNER, VERSION, null);
@ -43,12 +46,14 @@ public class UpdateCaptionOwnerMessage implements ISubscribedMessage {
if (UPDATE_CAPTION_OWNER.equals(messageName)) {
if (payload.has(Constants.MEETING_ID)
&& payload.has(Constants.LOCALE)
&& payload.has(Constants.LOCALE_CODE)
&& payload.has(Constants.OWNER_ID)) {
String meetingID = payload.get(Constants.MEETING_ID).getAsString();
String locale = payload.get(Constants.LOCALE).getAsString();
String localeCode = payload.get(Constants.LOCALE_CODE). getAsString();
String ownerID = payload.get(Constants.OWNER_ID).getAsString();
return new UpdateCaptionOwnerMessage(meetingID, locale, ownerID);
return new UpdateCaptionOwnerMessage(meetingID, locale, localeCode, ownerID);
}
}
}

View File

@ -724,7 +724,7 @@ public class Util {
for (Map.Entry<String,JsonElement> entry : history.entrySet()) {
String locale = entry.getKey();
JsonArray values = entry.getValue().getAsJsonArray();
String[] localeValueArray = new String[2];
String[] localeValueArray = new String[3];
int i = 0;
Iterator<JsonElement> valuesIter = values.iterator();

View File

@ -1,27 +1,31 @@
package org.bigbluebutton.messages.payload;
public class CreateBreakoutRoomRequestPayload {
public final String breakoutId;
public final String parentId; // The main meeting internal id
public final String name; // The name of the breakout room
public final String voiceConfId; // The voice conference id
public final String viewerPassword;
public final String moderatorPassword;
public final Integer durationInMinutes; // The duration of the breakout room
public final String defaultPresentationURL;
public final Boolean record;
public CreateBreakoutRoomRequestPayload(String breakoutId, String parentId, String name,
String voiceConfId, String viewerPassword, String moderatorPassword,
Integer duration, String defaultPresentationURL, Boolean record) {
this.breakoutId = breakoutId;
this.parentId = parentId;
this.name = name;
this.voiceConfId = voiceConfId;
this.viewerPassword = viewerPassword;
this.moderatorPassword = moderatorPassword;
this.durationInMinutes = duration;
this.defaultPresentationURL = defaultPresentationURL;
this.record = record;
}
public final String breakoutId;
public final String parentId; // The main meeting internal id
public final String name; // The name of the breakout room
public final String voiceConfId; // The voice conference id
public final String viewerPassword;
public final String moderatorPassword;
public final Integer durationInMinutes; // The duration of the breakout room
public final String sourcePresentationId;
public final Integer sourcePresentationSlide;
public final Boolean record;
public CreateBreakoutRoomRequestPayload(String breakoutId, String parentId,
String name, String voiceConfId, String viewerPassword,
String moderatorPassword, Integer duration,
String sourcePresentationId, Integer sourcePresentationSlide,
Boolean record) {
this.breakoutId = breakoutId;
this.parentId = parentId;
this.name = name;
this.voiceConfId = voiceConfId;
this.viewerPassword = viewerPassword;
this.moderatorPassword = moderatorPassword;
this.durationInMinutes = duration;
this.sourcePresentationId = sourcePresentationId;
this.sourcePresentationSlide = sourcePresentationSlide;
this.record = record;
}
}

View File

@ -9,19 +9,20 @@ import com.google.gson.Gson;
public class CreateBreakoutRoomRequestTest {
@Test
public void testCreateBreakoutRoomRequest() {
String breakoutId = "abc123";
String breakoutId = "183f0bf3a0982a127bdb8161e0c44eb696b3e75c-1474984695664";
String parentId = "abc-123";
Integer durationInMinutes = 20;
String name = "Breakout room 1";
String voiceConfId = "851153";
String viewerPassword = "vp";
String moderatorPassword = "mp";
String defaultPresentationURL = "http://localhost/foo.pdf";
String sourcePresentationId = "d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1474984695907";
Integer sourePresentationSlide = 5;
Boolean record = false;
CreateBreakoutRoomRequestPayload payload =
new CreateBreakoutRoomRequestPayload(breakoutId, parentId, name, voiceConfId,
viewerPassword, moderatorPassword, durationInMinutes, defaultPresentationURL, record);
viewerPassword, moderatorPassword, durationInMinutes, sourcePresentationId, sourePresentationSlide, record);
CreateBreakoutRoomRequest msg = new CreateBreakoutRoomRequest(payload);
Gson gson = new Gson();
String json = gson.toJson(msg);
@ -36,7 +37,8 @@ public class CreateBreakoutRoomRequestTest {
Assert.assertEquals(rxMsg.payload.viewerPassword, viewerPassword);
Assert.assertEquals(rxMsg.payload.moderatorPassword, moderatorPassword);
Assert.assertEquals(rxMsg.payload.durationInMinutes, durationInMinutes);
Assert.assertEquals(rxMsg.payload.defaultPresentationURL, defaultPresentationURL);
Assert.assertEquals(rxMsg.payload.sourcePresentationId, sourcePresentationId);
Assert.assertEquals(rxMsg.payload.sourcePresentationSlide, sourePresentationSlide);
Assert.assertEquals(rxMsg.payload.record, record);
}
}

View File

@ -3,7 +3,6 @@
<title><g:message code="tool.view.title" /></title>
<link rel="shortcut icon" href="${assetPath(src: 'favicon.ico')}" type="image/x-icon">
<asset:stylesheet src="bootstrap.css"/>
<asset:stylesheet src="tool.css"/>
<asset:stylesheet src="dataTables.bootstrap.min.css"/>
<asset:javascript src="jquery.js"/>
<asset:javascript src="jquery.dataTables.min.js"/>

View File

@ -4,7 +4,7 @@
proxy_pass http://127.0.0.1:8080;
proxy_redirect default;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Forwarded-Proto $scheme;
# Allow 30M uploaded presentation document.
client_max_body_size 30m;

View File

@ -119,7 +119,7 @@ class Screenshare(val sessionManager: ScreenshareManager,
private var lastJwsStatusUpdate = 0L
private var sessionStartedTimestamp:Long = 0L
private val JWS_START_TIMEOUT = 60
private val JWS_START_TIMEOUT = 90
// The number of seconds we wait for the JWS to launch when
// resuming sharing. Sometimes, on PAUSE, the JWS crashes but

View File

@ -1,8 +1,18 @@
FFMPEG=ffmpeg-3.0.2-1.2-linux-x86.jar
cp $FFMPEG build/libs/ffmpeg-linux-x86-0.0.1.jar
mkdir workdir
cp $FFMPEG workdir/ffmpeg-linux-x86.jar
rm -rf src
rm -rf workdir
mkdir -p src/main/resources
mkdir -p src/main/java
cd workdir
jar xvf ffmpeg-linux-x86.jar
cp org/bytedeco/javacpp/linux-x86/*.so* ../src/main/resources
cd ..
gradle jar
cp build/libs/ffmpeg-linux-x86-0.0.1.jar ../unsigned-jars/ffmpeg-linux-x86-unsigned.jar
ant sign-jar
cp build/libs/ffmpeg-linux-x86-0.0.1.jar ../../../app/jws/lib/ffmpeg-linux-x86.jar
rm -rf workdir
rm -rf src

View File

@ -1,7 +1,17 @@
FFMPEG=ffmpeg-3.0.2-1.2-linux-x86_64.jar
mkdir workdir
rm -rf workdir
cp $FFMPEG build/libs/ffmpeg-linux-x86_64-0.0.1.jar
cp $FFMPEG workdir/ffmpeg-linux-x86_64.jar
rm -rf src
mkdir -p src/main/resources
mkdir -p src/main/java
cd workdir
jar xvf ffmpeg-linux-x86_64.jar
cp org/bytedeco/javacpp/linux-x86_64/*.so* ../src/main/resources
cd ..
gradle jar
cp build/libs/ffmpeg-linux-x86_64-0.0.1.jar ../unsigned-jars/ffmpeg-linux-x86_64-unsigned.jar
ant sign-jar
cp build/libs/ffmpeg-linux-x86_64-0.0.1.jar ../../../app/jws/lib/ffmpeg-linux-x86_64.jar
rm -rf workdir
rm -rf src

View File

@ -16,6 +16,7 @@ import org.bigbluebutton.screenshare.client.ExitCode;
import org.bigbluebutton.screenshare.client.ScreenShareInfo;
import org.bigbluebutton.screenshare.client.net.NetworkConnectionListener;
import org.bytedeco.javacpp.Loader;
import org.bytedeco.javacpp.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
@ -144,25 +145,27 @@ public class FfmpegScreenshare {
frame = grabber.grabImage();
if (frame != null) {
try {
long timestamp = now - startTime;
// Override timestamp from system screen grabber. Otherwise, we will have skewed recorded file.
// FfmpegFrameRecorder needs to propagate this timestamp into the avpacket sent to the server.
// ralam - Sept. 14, 2016
frame.timestamp = timestamp;
//System.out.println("frame timestamp=[" + frame.timestamp + "] ");
mainRecorder.record(frame);
} catch (Exception e) {
//System.out.println("CaptureScreen Exception 1");
if (!ignoreDisconnect) {
listener.networkConnectionException(ExitCode.INTERNAL_ERROR, null);
}
}
}
} catch (Exception e1) {
listener.networkConnectionException(ExitCode.INTERNAL_ERROR, null);
}
long sleepFramerate = (long) (1000 / frameRate);
long timestamp = now - startTime;
mainRecorder.setTimestamp(timestamp * 1000);
// System.out.println("i=[" + i + "] timestamp=[" + timestamp + "]");
//System.out.println("timestamp=[" + timestamp + "]");
mainRecorder.setFrameNumber(frameNumber);
// System.out.println("[ENCODER] encoded image " + frameNumber + " in " + (System.currentTimeMillis() - now));

View File

@ -45,7 +45,6 @@ public class NetworkHttpStreamSender {
private String host = "localhost";
private static final String SCREEN_CAPTURE__URL = "/tunnel/screenCapture";
private URL url;
private URLConnection conn;
private String meetingId;
private NetworkStreamListener listener;
private final SequenceNumberGenerator seqNumGenerator;
@ -113,7 +112,7 @@ public class NetworkHttpStreamSender {
sendMessages = false;
}
private void openConnection() throws ConnectionException {
private URLConnection openConnection() throws ConnectionException {
/**
* Need to re-establish connection each time, otherwise,
* we get java.net.ProtocolException: Cannot write output after reading input.
@ -121,13 +120,13 @@ public class NetworkHttpStreamSender {
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4382944
*
*/
long start = System.currentTimeMillis();
//long start = System.currentTimeMillis();
try {
url = new URL(host + SCREEN_CAPTURE__URL);
if (host.toLowerCase().startsWith("https://")) {
conn = (HttpsURLConnection)url.openConnection();
return (HttpsURLConnection)url.openConnection();
} else {
conn = url.openConnection();
return url.openConnection();
}
} catch (MalformedURLException e) {
e.printStackTrace();
@ -136,27 +135,20 @@ public class NetworkHttpStreamSender {
e.printStackTrace();
throw new ConnectionException("IOException while connecting to " + url.toString());
}
long end = System.currentTimeMillis();
//long end = System.currentTimeMillis();
//System.out.println("Http Open connection took [" + (end-start) + " ms]");
}
private void sendStartStreamMessage(ShareStartedMessage message) {
try {
//System.out.println("Http Open connection. In sendStartStreamMessage");
openConnection();
sendCaptureStartEvent(message.width, message.height, message.streamId, message.session);
} catch (ConnectionException e) {
System.out.println("Exception in sendStartStreamMessage");
System.out.print(e.toString());
//e.printStackTrace();
notifyNetworkStreamListener(ExitCode.DESKSHARE_SERVICE_UNAVAILABLE, null);
}
}
private void sendCaptureStartEvent(int width, int height, String streamId, String session) throws ConnectionException {
private void sendCaptureStartEvent(int width, int height, String streamId, String session) {
ClientHttpRequest chr;
try {
System.out.println(getTimeStamp() + " - Sending Start Sharing Event.");
URLConnection conn = openConnection();
chr = new ClientHttpRequest(conn);
chr.setParameter(MEETING_ID, meetingId);
chr.setParameter(STREAM_ID, streamId);
@ -173,28 +165,23 @@ public class NetworkHttpStreamSender {
//System.out.println("******* sendCaptureStartEvent response code = [" + status + "] ***************");
} catch (IOException e) {
e.printStackTrace();
throw new ConnectionException("IOException while sending capture start event.");
notifyNetworkStreamListener(ExitCode.DESKSHARE_SERVICE_UNAVAILABLE, null);
} catch (ConnectionException e) {
e.printStackTrace();
notifyNetworkStreamListener(ExitCode.DESKSHARE_SERVICE_UNAVAILABLE, null);
}
}
public void disconnect(String streamId, String session) throws ConnectionException {
try {
System.out.println("Http Open connection. In disconnect");
openConnection();
sendCaptureEndEvent(new ShareStoppedMessage(meetingId, streamId, session));
} catch (ConnectionException e) {
e.printStackTrace();
notifyNetworkStreamListener(ExitCode.DESKSHARE_SERVICE_UNAVAILABLE, null);
throw e;
} finally {
}
System.out.println("Http Open connection. In disconnect");
sendCaptureEndEvent(new ShareStoppedMessage(meetingId, streamId, session));
}
private void sendCaptureEndEvent(ShareStoppedMessage message) {
ClientHttpRequest chr;
try {
//System.out.println(getTimeStamp() + " - Sending End Sharing Event.");
URLConnection conn = openConnection();
chr = new ClientHttpRequest(conn);
chr.setParameter(MEETING_ID, meetingId);
chr.setParameter(STREAM_ID, message.streamId);
@ -210,6 +197,10 @@ public class NetworkHttpStreamSender {
} catch (IOException e) {
e.printStackTrace();
notifyNetworkStreamListener(ExitCode.DESKSHARE_SERVICE_UNAVAILABLE, null);
} catch (ConnectionException e) {
e.printStackTrace();
notifyNetworkStreamListener(ExitCode.DESKSHARE_SERVICE_UNAVAILABLE, null);
}
}
@ -220,7 +211,7 @@ public class NetworkHttpStreamSender {
// Open a connection to the web server and create a request that has
// the room and event type.
// System.out.println(getTimeStamp() + " - Sending Update Sharing Event.");
openConnection();
URLConnection conn = openConnection();
chr = new ClientHttpRequest(conn);
chr.setParameter(MEETING_ID, meetingId);
chr.setParameter(STREAM_ID, message.streamId);

View File

@ -688,7 +688,7 @@ public class FFmpegFrameRecorder extends FrameRecorder {
if (oc != null) {
try {
/* flush all the buffers */
while (video_st != null && ifmt_ctx == null && recordImage(0, 0, 0, 0, 0, AV_PIX_FMT_NONE, (Buffer[])null));
while (video_st != null && ifmt_ctx == null && recordImage(0, 0, 0, 0, 0, AV_PIX_FMT_NONE, 0, (Buffer[])null));
while (audio_st != null && ifmt_ctx == null && recordSamples(0, 0, (Buffer[])null));
if (interleaved && video_st != null && audio_st != null) {
@ -710,11 +710,11 @@ public class FFmpegFrameRecorder extends FrameRecorder {
}
public void record(Frame frame, int pixelFormat) throws Exception {
if (frame == null || (frame.image == null && frame.samples == null)) {
recordImage(0, 0, 0, 0, 0, pixelFormat, (Buffer[])null);
recordImage(0, 0, 0, 0, 0, pixelFormat, frame.timestamp, (Buffer[])null);
} else {
if (frame.image != null) {
frame.keyFrame = recordImage(frame.imageWidth, frame.imageHeight, frame.imageDepth,
frame.imageChannels, frame.imageStride, pixelFormat, frame.image);
frame.imageChannels, frame.imageStride, pixelFormat, frame.timestamp, frame.image);
}
if (frame.samples != null) {
frame.keyFrame = recordSamples(frame.sampleRate, frame.audioChannels, frame.samples);
@ -722,7 +722,8 @@ public class FFmpegFrameRecorder extends FrameRecorder {
}
}
public boolean recordImage(int width, int height, int depth, int channels, int stride, int pixelFormat, Buffer ... image) throws Exception {
public boolean recordImage(int width, int height, int depth, int channels, int stride,
int pixelFormat, long frameTimestamp, Buffer ... image) throws Exception {
if (video_st == null) {
throw new Exception("No video output stream (Is imageWidth > 0 && imageHeight > 0 and has start() been called?)");
}
@ -808,10 +809,15 @@ public class FFmpegFrameRecorder extends FrameRecorder {
/* if zero size, it means the image was buffered */
if (got_video_packet[0] != 0) {
if (video_pkt.pts() != AV_NOPTS_VALUE) {
video_pkt.pts(av_rescale_q(video_pkt.pts(), video_c.time_base(), video_st.time_base()));
// Override timestamp from system screen grabber. Otherwise, we will have skewed recorded file.
// FfmpegFrameRecorder needs to propagate this timestamp into the avpacket sent to the server.
// ralam - Sept. 14, 2016
video_pkt.pts(frameTimestamp);
//video_pkt.pts(av_rescale_q(video_pkt.pts(), video_c.time_base(), video_st.time_base()));
}
if (video_pkt.dts() != AV_NOPTS_VALUE) {
video_pkt.dts(av_rescale_q(video_pkt.dts(), video_c.time_base(), video_st.time_base()));
video_pkt.dts(frameTimestamp);
//video_pkt.dts(av_rescale_q(video_pkt.dts(), video_c.time_base(), video_st.time_base()));
}
video_pkt.stream_index(video_st.index());
} else {

View File

@ -40,14 +40,14 @@ public class CaptionClientMessageSender {
processSendCaptionHistoryReplyMessage(sch);
}
break;
case UpdateCaptionOwnerMessage.UPDATE_CAPTION_OWNER:
case UpdateCaptionOwnerMessage.UPDATE_CAPTION_OWNER:
UpdateCaptionOwnerMessage uco = UpdateCaptionOwnerMessage.fromJson(message);
if (uco != null) {
processUpdateCaptionOwnerMessage(uco);
}
break;
case EditCaptionHistoryMessage.EDIT_CAPTION_HISTORY:
case EditCaptionHistoryMessage.EDIT_CAPTION_HISTORY:
EditCaptionHistoryMessage ech = EditCaptionHistoryMessage.fromJson(message);
if (ech != null) {
@ -71,6 +71,7 @@ public class CaptionClientMessageSender {
private void processUpdateCaptionOwnerMessage(UpdateCaptionOwnerMessage msg) {
Map<String, Object> message = new HashMap<String, Object>();
message.put(Constants.LOCALE, msg.locale);
message.put(Constants.LOCALE_CODE, msg.localeCode);
message.put(Constants.OWNER_ID, msg.ownerID);
BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingID, "updateCaptionOwner", message);
@ -82,6 +83,7 @@ public class CaptionClientMessageSender {
message.put(Constants.START_INDEX, msg.startIndex);
message.put(Constants.END_INDEX, msg.endIndex);
message.put(Constants.LOCALE, msg.locale);
message.put(Constants.LOCALE_CODE, msg.localeCode);
message.put(Constants.TEXT, msg.text);
BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingID, "editCaptionHistory", message);

View File

@ -298,14 +298,14 @@ public class MessagePublisher {
SendCaptionHistoryRequestMessage msg = new SendCaptionHistoryRequestMessage(meetingID, requesterID);
sender.send(MessagingConstants.TO_CAPTION_CHANNEL, msg.toJson());
}
public void updateCaptionOwner(String meetingID, String locale, String ownerID) {
UpdateCaptionOwnerMessage msg = new UpdateCaptionOwnerMessage(meetingID, locale, ownerID);
sender.send(MessagingConstants.TO_CAPTION_CHANNEL, msg.toJson());
}
public void editCaptionHistory(String meetingID, String userID, Integer startIndex, Integer endIndex, String locale, String text) {
EditCaptionHistoryMessage msg = new EditCaptionHistoryMessage(meetingID, userID, startIndex, endIndex, locale, text);
public void updateCaptionOwner(String meetingID, String locale, String localeCode, String ownerID) {
UpdateCaptionOwnerMessage msg = new UpdateCaptionOwnerMessage(meetingID, locale, localeCode, ownerID);
sender.send(MessagingConstants.TO_CAPTION_CHANNEL, msg.toJson());
}
public void editCaptionHistory(String meetingID, String userID, Integer startIndex, Integer endIndex, String locale, String localeCode, String text) {
EditCaptionHistoryMessage msg = new EditCaptionHistoryMessage(meetingID, userID, startIndex, endIndex, locale, localeCode, text);
sender.send(MessagingConstants.TO_CAPTION_CHANNEL, msg.toJson());
}
}

View File

@ -26,7 +26,7 @@ import org.bigbluebutton.red5.pubsub.MessagePublisher;
import org.red5.logging.Red5LoggerFactory;
import org.red5.server.api.Red5;
import org.slf4j.Logger;
public class CaptionService {
private static Logger log = Red5LoggerFactory.getLogger( CaptionService.class, "bigbluebutton" );
@ -46,26 +46,42 @@ public class CaptionService {
red5InGW.sendCaptionHistory(meetingID, requesterID);
}
public void sendUpdateCaptionOwner(Map<String, Object> msg) {
String locale = msg.get("locale").toString();
Boolean claim = (Boolean) msg.get("claim");
String meetingID = Red5.getConnectionLocal().getScope().getName();
public void sendUpdateCaptionOwner(Map<String, Object> msg) {
String locale = msg.get("locale").toString();
String localeCode = msg.get("localeCode").toString();
Boolean claim = (Boolean) msg.get("claim");
String meetingID = Red5.getConnectionLocal().getScope().getName();
String ownerID = (claim ? getBbbSession().getInternalUserID() : "");
red5InGW.updateCaptionOwner(meetingID, locale, ownerID);
}
red5InGW.updateCaptionOwner(meetingID, locale, localeCode, ownerID);
}
public void editCaptionHistory(Map<String, Object> msg) {
int startIndex = (Integer) msg.get("startIndex");
int endIndex = (Integer) msg.get("endIndex");
String locale = msg.get("locale").toString();
String localeCode = msg.get("localeCode").toString();
String text = msg.get("text").toString();
String meetingID = Red5.getConnectionLocal().getScope().getName();
String userID = getBbbSession().getInternalUserID();
red5InGW.editCaptionHistory(meetingID, userID, startIndex, endIndex, locale, text);
Integer startIndex;
if (msg.get("startIndex") instanceof Double) {
Double tempStartIndex = (Double) msg.get("startIndex");
startIndex = tempStartIndex.intValue();
} else {
startIndex = (Integer) msg.get("startIndex");
}
Integer endIndex;
if (msg.get("endIndex") instanceof Double) {
Double tempEndIndex = (Double) msg.get("endIndex");
endIndex = tempEndIndex.intValue();
} else {
endIndex = (Integer) msg.get("endIndex");
}
red5InGW.editCaptionHistory(meetingID, userID, startIndex, endIndex, locale, localeCode, text);
}
}

View File

@ -41,9 +41,23 @@ public class PollingService {
String meetingID = Red5.getConnectionLocal().getScope().getName();
String userId = getBbbSession().getInternalUserID();
String pollId = (String) message.get("pollId");
Integer questionId = (Integer) message.get("answerId");
Integer answerId = (Integer) message.get("answerId");
Integer questionId;
if (message.get("answerId") instanceof Double) {
Double tempQuestionId = (Double) message.get("answerId");
questionId = tempQuestionId.intValue();
} else {
questionId = (Integer) message.get("answerId");
}
Integer answerId;
if (message.get("answerId") instanceof Double) {
Double tempAnswerId = (Double) message.get("answerId");
answerId = tempAnswerId.intValue();
} else {
answerId = (Integer) message.get("answerId");
}
red5GW.votePoll(meetingID, userId, pollId, questionId, answerId);
}

View File

@ -570,6 +570,10 @@ TitleWindow {
imageSource: Embed(source='assets/images/bbb_mac_safari_3.png');
}
.publishHelpMacSafari4 {
imageSource: Embed(source='assets/images/bbb_mac_safari_4.png');
}
.publishHelpMacFirefox1 {
imageSource: Embed(source='assets/images/bbb_mac_firefox_1.png');
}
@ -582,6 +586,10 @@ TitleWindow {
imageSource: Embed(source='assets/images/bbb_mac_firefox_3.png');
}
.publishHelpMacFirefox4 {
imageSource: Embed(source='assets/images/bbb_mac_firefox_4.png');
}
.publishHelpMacChrome1 {
imageSource: Embed(source='assets/images/bbb_mac_chrome_1.png');
}
@ -594,6 +602,10 @@ TitleWindow {
imageSource: Embed(source='assets/images/bbb_mac_chrome_3.png');
}
.publishHelpMacChrome4 {
imageSource: Embed(source='assets/images/bbb_mac_chrome_4.png');
}
.publishHelpLinuxFirefox1 {
imageSource: Embed(source='assets/images/bbb_linux_firefox_1.png');
}
@ -1049,6 +1061,10 @@ EmojiGrid {
horizontalGap: 6;
}
.breakoutRoomUserWindowHeadingStyle {
fontWeight: bold;
}
.breakoutRoomSettingTitleStyle {
fontFamily: Arial;
fontSize: 20;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -313,18 +313,21 @@ bbb.screensharePublish.helpText.PCChrome3 = 3. Accept the certificate
bbb.screensharePublish.helpText.MacSafari1 = 1. Locate 'screenshare.jnlp'
bbb.screensharePublish.helpText.MacSafari2 = 2. Select 'Show In Finder'
bbb.screensharePublish.helpText.MacSafari3 = 3. Right-click and select 'Open'
bbb.screensharePublish.helpText.MacFirefox1 = 1. Locate 'screenshare.jnlp'
bbb.screensharePublish.helpText.MacSafari4 = 4. Select 'Open' (if prompted)
bbb.screensharePublish.helpText.MacFirefox1 = 1. Choose 'Save File' (if asked)
bbb.screensharePublish.helpText.MacFirefox2 = 2. Select 'Show In Finder'
bbb.screensharePublish.helpText.MacFirefox3 = 3. Right-click and select 'Open'
bbb.screensharePublish.helpText.MacFirefox4 = 4. Select 'Open' (if prompted)
bbb.screensharePublish.helpText.MacChrome1 = 1. Locate 'screenshare.jnlp'
bbb.screensharePublish.helpText.MacChrome2 = 2. Select 'Show In Finder'
bbb.screensharePublish.helpText.MacChrome3 = 3. Right-click and select 'Open'
bbb.screensharePublish.helpText.LinuxFirefox1 = Placeholder linuxFirefox1
bbb.screensharePublish.helpText.LinuxFirefox2 = Placeholder linuxFirefox2
bbb.screensharePublish.helpText.LinuxFirefox3 = Placeholder linuxFirefox3
bbb.screensharePublish.helpText.LinuxChrome1 = Placeholder linuxChrome1
bbb.screensharePublish.helpText.LinuxChrome2 = Placeholder linuxChrome2
bbb.screensharePublish.helpText.LinuxChrome3 = Placeholder linuxChrome3
bbb.screensharePublish.helpText.MacChrome4 = 4. Select 'Open' (if prompted)
bbb.screensharePublish.helpText.LinuxFirefox1 = 1. Click 'OK' to run
bbb.screensharePublish.helpText.LinuxFirefox2 = 2. Accept the certificate
bbb.screensharePublish.helpText.LinuxFirefox3 =
bbb.screensharePublish.helpText.LinuxChrome1 = 1. Locate 'screenshare.jnlp'
bbb.screensharePublish.helpText.LinuxChrome2 = 2. Click to open
bbb.screensharePublish.helpText.LinuxChrome3 = 3. Accept the certificate
bbb.screensharePublish.shareTypeLabel.text = Share:
bbb.screensharePublish.shareType.fullScreen = Full screen
bbb.screensharePublish.shareType.region = Region
@ -421,6 +424,7 @@ bbb.logout.rejected = The connection to the server has been rejected
bbb.logout.invalidapp = The red5 app does not exist
bbb.logout.unknown = Your client has lost connection with the server
bbb.logout.usercommand = You have logged out of the conference
bbb.logour.breakoutRoomClose = Your browser window will be closed
bbb.logout.ejectedFromMeeting = A moderator has kicked you out of the meeting.
bbb.logout.refresh.message = If this logout was unexpected click the button below to reconnect.
bbb.logout.refresh.label = Reconnect
@ -645,6 +649,7 @@ bbb.users.settings.lockAll=Lock All Users
bbb.users.settings.lockAllExcept=Lock Users Except Presenter
bbb.users.settings.lockSettings=Lock Viewers ...
bbb.users.settings.breakoutRooms=Breakout Rooms ...
bbb.users.settings.sendBreakoutRoomsInvitations=Send Breakout Rooms Invitations ...
bbb.users.settings.unlockAll=Unlock All Viewers
bbb.users.settings.roomIsLocked=Locked by default
bbb.users.settings.roomIsMuted=Muted by default
@ -666,19 +671,24 @@ bbb.lockSettings.locked=Locked
bbb.lockSettings.lockOnJoin=Lock On Join
bbb.users.breakout.breakoutRooms = Breakout Rooms
bbb.users.breakout.updateBreakoutRooms = Update Breakout Rooms
bbb.users.breakout.remainingTimeBreakout = {0}: <b>{1} remaining</b>
bbb.users.breakout.remainingTimeParent = <b>{1} remaining</b>
bbb.users.breakout.calculatingRemainingTime = Calculating remaining time...
bbb.users.breakout.remainingTimeEnded = Time ended, breakout room will close.
bbb.users.breakout.rooms = Rooms
bbb.users.breakout.roomsCombo.accessibilityName = Number of rooms to create
bbb.users.breakout.room = Room
bbb.users.breakout.randomAssign = Randomly Assign Users
bbb.users.breakout.timeLimit = Time Limit
bbb.users.breakout.durationStepper.accessibilityName = Time limit in minutes
bbb.users.breakout.minutes = Minutes
bbb.users.breakout.record = Record
bbb.users.breakout.recordCheckbox.accessibilityName = Record breakout rooms
bbb.users.breakout.notAssigned = Not Assigned
bbb.users.breakout.dragAndDropToolTip = Tip: You can drag and drop users between rooms
bbb.users.breakout.start = Start
bbb.users.breakout.invite = Invite
bbb.users.breakout.close = Close
bbb.users.breakout.closeAllRooms = Close All Breakout Rooms
bbb.users.breakout.insufficientUsers = Insufficient users. You should place at least one user in one breakout room.

View File

@ -47,7 +47,7 @@
uri="rtmp://HOST/screenshare"
showButton="true"
baseTabIndex="201"
useWebRTCIfAvailable="false"
tryWebRTCFirst="false"
chromeExtensionKey=""
help="http://HOST/client/help/screenshare-help.html"
/>

View File

@ -1,30 +1,55 @@
<h1>Desktop Sharing Help</h1>
<p>This page contains a list of videos that let you quickly get started using BigBlueButton's desktop sharing.</p>
<!DOCTYPE html>
<html>
<head>
<style>
h1,h2 {
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
}
</style>
</head>
<body>
<h1>Launching Screen Sharing</h1>
<p>Desktop sharing requires Java 1.8. If you don't have Java 1.8 installed (or are not sure if you have it installed), first visit <a href="http://java.com/">java.com</a> and install Java.</p>
<p>As the presenter, before you launch screen sharing you need Java installed on your computer (we recommend Java 1.8, though it might work on older versions). If you don't have Java 1.8 installed (or are not sure if you have it installed), visit <a href="http://java.com/">java.com</a> to install Java.</p>
<p>Choose the video below that corresponds to your operating system and browser.<p>
<h2>Tutorial Video</h2>
<p>The video below demonstrates how to launch screen sharing on both Windows and Mac OS X.</p>
<h2>Windows + Internet Explorer</h2>
<iframe width="420" height="315" src="https://www.youtube.com/embed/xTFuEvmEqB0" frameborder="0" allowfullscreen></iframe>
<iframe width="420" height="315" src="https://www.youtube.com/embed/w0qei2-uDpI" frameborder="0" allowfullscreen></iframe>
<p>When you start screen sharing, it will download a file called <b>screenshare (N).jnlp</b>. It might be called screenshare.jnlp, screenshare (1).jnlp, screenshare (2).jnlp, and so on. As shown in the above video, you open downloaded file to launch screen sharing. The steps to open are different depending on your operating system.</p>
<h2>Windows + Firefox</h2>
<h2>Windows</h2>
<p>As decribed in the above video, on Windows, the steps to open <b>screenshare (N).jnlp</b> are:</p>
<iframe width="420" height="315" src="https://www.youtube.com/embed/7ZuunBQbmj8" frameborder="0" allowfullscreen></iframe>
<ol>
<li>Locate where the browser has downloaded screenshare (N).jnlp (the images will guide you)
<li>Click to open
</ol>
<h2>Windows + Chrome</h2>
<h2>Mac OS X</h2>
<p>As shown in the above video, on Mac OS X, the steps to open <b>screenshare (N).jnlp</b> in Chrome are:</p>
<iframe width="420" height="315" src="https://www.youtube.com/embed/bx9Tupfro_I" frameborder="0" allowfullscreen></iframe>
<ol>
<li>Locate where the browser has downloaded screenshare (N).jnlp (the images will guide you)
<li>Open in Finder
<li>Right-click and choose "Open"
</ol>
<h2>Mac OS X + Chrome<h2>
<p>For FireFox, the steps are:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Xezw2moXZQE" frameborder="0" allowfullscreen></iframe>
<ol>
<li>Choose "Save File" (if asked)
<li>Open in Finder
<li>Right-click and choose "Open"
</ol>
<h2>Mac OS X + FireFox</h2>
<h2>Notes</h2>
<p>The extension .jnlp stands for Java Network Launch Protocol. When you open the downloaded <b>screenshare (N).jnlp</b>, your computer launchs Java with, in turn, downloads and launchs the BigBlueButton screen share application. You then control the screen sharing application within the BigBlueButton client.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/FmTJOB4SODc" frameborder="0" allowfullscreen></iframe>
<p>The presenter and only the presenter needs to have Java installed. Students view your desktop within BigBlueButton client. On Windows, screen share supports sharing full screen and region. On Mac OS X, screen schare only supports full screen. In both platforms, full screen will share your home screen.</p>
<p>For more vidoes on using BigBlueButton, see <a href="http://bigbluebutton.org/videos/">http://bigbluebutton.org/videos/</a>.</p>
</body>
</html>

View File

@ -97,7 +97,7 @@
iframe.onload = function() {
iframe.isLoaded = true;
};
iframe.src = 'https://www.webrtc-experiment.com/getSourceId/';
// iframe.src = 'https://www.webrtc-experiment.com/getSourceId/';
iframe.style.display = 'none';
(document.body || document.documentElement).appendChild(iframe);
})();
})();

View File

@ -1,13 +1,13 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
*
* Copyright (c) 2012 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.
@ -16,49 +16,56 @@
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*
*/
package org.bigbluebutton.core
{
package org.bigbluebutton.core {
import flash.system.Capabilities;
import mx.core.FlexGlobals;
import mx.utils.URLUtil;
import org.bigbluebutton.core.managers.ConfigManager2;
import org.bigbluebutton.core.managers.ConnectionManager;
import org.bigbluebutton.core.managers.UserConfigManager;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.core.managers.VideoProfileManager;
import org.bigbluebutton.core.model.Session;
import org.bigbluebutton.core.model.VideoProfile;
import org.bigbluebutton.util.SessionTokenUtil;
import org.bigbluebutton.util.SessionTokenUtil;
public class BBB {
private static var configManager:ConfigManager2 = null;
private static var connectionManager:ConnectionManager = null;
private static var session:Session = null;
private static var userConfigManager:UserConfigManager = null;
private static var videoProfileManager:VideoProfileManager = null;
private static var sessionTokenUtil:SessionTokenUtil = null;
public static function getSessionTokenUtil():SessionTokenUtil {
if (sessionTokenUtil == null) {
sessionTokenUtil = new SessionTokenUtil();
}
return sessionTokenUtil;
}
public static function initUserConfigManager():UserConfigManager {
if (userConfigManager == null) {
userConfigManager = new UserConfigManager();
}
return userConfigManager;
}
public static function getConfigManager():ConfigManager2 {
if (configManager == null) {
configManager = new ConfigManager2();
}
return configManager;
}
public static function loadConfig():void {
configManager.loadConfig();
}
@ -86,7 +93,7 @@ package org.bigbluebutton.core
public static function get defaultVideoProfile():VideoProfile {
return initVideoProfileManager().defaultVideoProfile;
}
public static function get fallbackVideoProfile():VideoProfile {
return initVideoProfileManager().fallbackVideoProfile;
}
@ -96,47 +103,54 @@ package org.bigbluebutton.core
connectionManager = new ConnectionManager();
}
return connectionManager;
}
}
public static function initSession():Session {
if (session == null) {
session = new Session();
}
return session;
}
}
public static function getFlashPlayerVersion():Number {
var versionString:String = Capabilities.version;
var pattern:RegExp = /^(\w*) (\d*),(\d*),(\d*),(\d*)$/;
var result:Object = pattern.exec(versionString);
if (result != null) {
// trace("input: " + result.input);
// trace("platform: " + result[1]);
// trace("majorVersion: " + result[2]);
// trace("minorVersion: " + result[3]);
// trace("buildNumber: " + result[4]);
// trace("internalBuildNumber: " + result[5]);
// trace("input: " + result.input);
// trace("platform: " + result[1]);
// trace("majorVersion: " + result[2]);
// trace("minorVersion: " + result[3]);
// trace("buildNumber: " + result[4]);
// trace("internalBuildNumber: " + result[5]);
return Number(result[2] + "." + result[3]);
} else {
// trace("Unable to match RegExp.");
// trace("Unable to match RegExp.");
return 0;
}
}
}
public static function getLogoutURL():String {
var logoutUrl:String = BBB.initUserConfigManager().getLogoutUrl();
if (logoutUrl == null) {
var pageHost:String = FlexGlobals.topLevelApplication.url.split("/")[0];
var pageURL:String = FlexGlobals.topLevelApplication.url.split("/")[2];
var sessionToken:String = BBB.sessionTokenUtil.getSessionToken();
logoutUrl = pageHost + "//" + pageURL;
if (sessionToken != "") {
logoutUrl = pageHost + "//" + pageURL + "/bigbluebutton/api/signOut?sessionToken=" + sessionToken;
}
}
logoutUrl = getBaseURL();
}
return logoutUrl;
}
public static function getSignoutURL():String {
var sessionToken:String = BBB.sessionTokenUtil.getSessionToken();
var logoutUrl:String = getBaseURL();
if (sessionToken != "") {
logoutUrl += "/bigbluebutton/api/signOut?sessionToken=" + sessionToken;
}
return logoutUrl;
}
public static function getBaseURL():String {
var protocol:String = URLUtil.getProtocol(FlexGlobals.topLevelApplication.url);
var serverName:String = URLUtil.getServerNameWithPort(FlexGlobals.topLevelApplication.url);
return protocol + "://" + serverName;
}
}
}
}

View File

@ -36,16 +36,12 @@ package org.bigbluebutton.core.managers
}
public function setUri(uri:String):void {
connDelegate.setUri(uri);
}
public function get connection():NetConnection {
return connDelegate.connection;
}
public function connect(params:ConferenceParameters):void {
connDelegate.connect(params);
public function connect():void {
connDelegate.connect();
}
public function disconnect(onUserAction:Boolean):void {

View File

@ -18,18 +18,15 @@
*/
package org.bigbluebutton.core.managers
{
import com.asfusion.mate.events.Dispatcher;
import com.asfusion.mate.events.Dispatcher;
import flash.display.DisplayObject;
import flash.events.TimerEvent;
import flash.utils.Dictionary;
import flash.utils.Timer;
import flash.utils.Timer;
import mx.collections.ArrayCollection;
import mx.core.FlexGlobals;
import mx.core.IFlexDisplayObject;
import mx.managers.PopUpManager;
import mx.managers.PopUpManager;
import org.as3commons.logging.api.ILogger;
import org.as3commons.logging.api.getClassLogger;
import org.bigbluebutton.core.UsersUtil;
@ -76,7 +73,6 @@ package org.bigbluebutton.core.managers
}
private function timeout(e:TimerEvent = null):void {
LOGGER.debug("timeout");
_dispatcher.dispatchEvent(new BBBEvent(BBBEvent.CANCEL_RECONNECTION_EVENT));
_dispatcher.dispatchEvent(new LogoutEvent(LogoutEvent.USER_LOGGED_OUT));
}

View File

@ -1,13 +1,13 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
*
* Copyright (c) 2012 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.
@ -16,33 +16,38 @@
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*
*/
package org.bigbluebutton.core.managers
{
package org.bigbluebutton.core.managers {
import org.bigbluebutton.main.model.ConferenceParameters;
public class UserConfigManager
{
public class UserConfigManager {
private var conferenceParameters:ConferenceParameters = null;
public function setConferenceParameters(c:ConferenceParameters):void {
conferenceParameters = c;
}
public function getConfParams():ConferenceParameters {
return conferenceParameters;
}
public function getLogoutUrl():String {
if (conferenceParameters == null) return null;
if (conferenceParameters == null)
return null;
return conferenceParameters.logoutUrl;
}
public function getWelcomeMessage():String {
if (conferenceParameters == null) return null;
return conferenceParameters.welcome;
}
public function getMeetingTitle():String {
if (conferenceParameters)
return conferenceParameters.meetingName;
else
return null;
}
public function getWelcomeMessage():String {
if (conferenceParameters == null)
return null;
return conferenceParameters.welcome;
}
public function getMeetingTitle():String {
if (conferenceParameters)
return conferenceParameters.meetingName;
else
return null;
}
}
}

View File

@ -17,40 +17,44 @@
*
*/
package org.bigbluebutton.main.events {
import flash.events.Event;
public class BreakoutRoomEvent extends Event {
public static const OPEN_BREAKOUT_ROOMS_PANEL:String = "OPEN_BREAKOUT_ROOMS_PANEL";
public static const CREATE_BREAKOUT_ROOMS:String = "CREATE_BREAKOUT_ROOMS";
public static const REQUEST_BREAKOUT_JOIN_URL:String = "REQUEST_BREAKOUT_JOIN_URL";
public static const BREAKOUT_JOIN_URL:String = "BREAKOUT_JOIN_URL";
public static const LISTEN_IN:String = "LISTEN_IN";
public static const END_ALL_BREAKOUT_ROOMS:String = "END_ALL_BREAKOUT_ROOMS";
public static const UPDATE_REMAINING_TIME_PARENT:String = "UPDATE_REMAINING_TIME_PARENT";
public static const UPDATE_REMAINING_TIME_BREAKOUT:String = "UPDATE_REMAINING_TIME_BREAKOUT";
public var meetingId:String;
public var breakoutId:String;
public var rooms:Array;
public var durationInMinutes:int;
public var record:Boolean;
public var joinURL:String;
public var listen:Boolean;
public var joinMode:String;
public var userId:String;
public function BreakoutRoomEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false) {
super(type, bubbles, cancelable);
}

View File

@ -30,7 +30,7 @@ package org.bigbluebutton.main.events
public static const PORT_TEST_UPDATE:String = "PORT_TEST_UPDATE";
public static const TUNNELING_FAILED:String = "RTMTP_ALSO_FAILED";
public var protocol:String;
public var tunnel:Boolean;
public var hostname:String;
public var port:String;
public var app:String;

View File

@ -24,13 +24,7 @@ package org.bigbluebutton.main.events
{
public static const START_USER_SERVICES:String = "START_USER_SERVICES";
public static const USER_SERVICES_STARTED:String = "USER_SERVICES_STARTED";
public var applicationURI:String;
public var hostURI:String;
public var isTunnelling:Boolean = false;
public var user:Object;
public function UserServicesEvent(type:String)
{
super(type, true, false);

View File

@ -46,11 +46,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
</EventHandlers>
<EventHandlers type="{PortTestEvent.PORT_TEST_SUCCESS}" >
<MethodInvoker generator="{ModulesProxy}" method="portTestSuccess" arguments="{event.protocol}" />
<MethodInvoker generator="{ModulesProxy}" method="portTestSuccess" arguments="{event.tunnel}" />
</EventHandlers>
<EventHandlers type="{PortTestEvent.PORT_TEST_FAILED}" >
<MethodInvoker generator="{ModulesProxy}" method="testRTMPT" arguments="{event.protocol}" />
<MethodInvoker generator="{ModulesProxy}" method="testRTMPT" arguments="{event.tunnel}" />
</EventHandlers>
<EventHandlers type="{SuccessfulLoginEvent.USER_LOGGED_IN}" >

View File

@ -1,3 +1,3 @@
/** * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ * * Copyright (c) 2012 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.main.model { import flash.events.NetStatusEvent; import flash.events.TimerEvent; import flash.net.NetConnection; import flash.net.ObjectEncoding; import flash.utils.Timer; import org.as3commons.logging.api.ILogger; import org.as3commons.logging.api.getClassLogger; [Bindable] /** * Test RTMP port. * * @author Thijs Triemstra ( info@collab.nl ) */ public class PortTest { private static const LOGGER:ILogger = getClassLogger(PortTest); /** * Protocol name. */ private var protocol : String; /** * Protocol name (uppercase). */ public var protocolName : String; /** * RTMP hostname. */ private var hostname : String; /** * RTMP port. */ public var port : String; /** * RTMP port. */ public var portName : String = "Default"; /** * RTMP application. */ private var application : String; /** * Base RTMP URI. */ private var baseURI : String; /** * RTMP connection. */ public var nc : NetConnection; /** * Connection status. */ public var status : String; private var _connectionListener:Function; /** * Timer to control timeout of connection test */ private var testTimeout:Number = 0; /** * Timer to control timeout of connection test */ private var connectionTimer:Timer; /** * Set default encoding to AMF0 so FMS also understands. */ NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0; /** * Create new port test and connect to the RTMP server. * * @param protocol * @param hostname * @param port * @param application * @testTimeout timeout of test in milliseconds */ public function PortTest( protocol : String = "", hostname : String = "", port : String = "", application : String = "", testTimeout : Number = 10000 ) { this.protocol = protocol; this.protocolName = protocol.toUpperCase(); this.hostname = hostname; this.application = application; this.testTimeout = testTimeout; if ( port.length > 0 ) protocol : String = "", testTimeout : Number = 10000 protocol : String = "", ) protocol : String = "", { } protocol : String = "", this.protocolName = protocol.toUpperCase(); { hostname : String = "", protocol : String = "", this.protocol = protocol; hostname : String = "", protocol : String = "", this.baseURI = this.protocol + "://" + this.hostname + this.port + "/" + this.application; // } /** * Start connection. */ public function connect() : void { this.nc = new NetConnection(); this.nc.client = this;
/** * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ * * Copyright (c) 2012 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.main.model { import flash.events.NetStatusEvent; import flash.events.TimerEvent; import flash.net.NetConnection; import flash.net.ObjectEncoding; import flash.utils.Timer; import org.as3commons.logging.api.ILogger; import org.as3commons.logging.api.getClassLogger; [Bindable] /** * Test RTMP port. * * @author Thijs Triemstra ( info@collab.nl ) */ public class PortTest { private static const LOGGER:ILogger = getClassLogger(PortTest); /** * Connect using rtmp or rtmpt. */ private var tunnel: Boolean; /** * RTMP hostname. */ private var hostname : String; /** * RTMP port. */ public var port : String; /** * RTMP port. */ public var portName : String = "Default"; /** * RTMP application. */ private var application : String; /** * Base RTMP URI. */ private var baseURI : String; /** * RTMP connection. */ public var nc : NetConnection; /** * Connection status. */ public var status : String; private var _connectionListener:Function; /** * Timer to control timeout of connection test */ private var testTimeout:Number = 0; /** * Timer to control timeout of connection test */ private var connectionTimer:Timer; /** * Set default encoding to AMF0 so FMS also understands. */ NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0; /** * Create new port test and connect to the RTMP server. * * @param protocol * @param hostname * @param port * @param application * @testTimeout timeout of test in milliseconds */ public function PortTest( tunnel : Boolean, hostname : String = "", port : String = "", application : String = "", testTimeout : Number = 10000) { this.tunnel = tunnel; this.hostname = hostname; this.application = application; this.testTimeout = testTimeout; if ( port.length > 0 ) { protocol : String = "", ) protocol : String = "", { hostname : String = "", { this.port = port; } hostname : String = "", protocol : String = "", if (tunnel) { hostname : String = "", this.protocolName = protocol.toUpperCase(); port : String = "", port : String = "", protocol : String = "", port : String = "", hostname : String = "", // } /** * Start connection. */ public function connect() : void { this.nc = new NetConnection(); this.nc.client = this;
this.nc.proxyType = "best";
this.nc.addEventListener( NetStatusEvent.NET_STATUS, netStatus ); // connect to server try { // Create connection with the server. this.nc.connect( this.baseURI, "portTestMeetingId", "portTestDummyUserId" ); status = "Connecting..."; connectionTimer = new Timer(testTimeout, 1); connectionTimer.addEventListener(TimerEvent.TIMER, connectionTimeout); connectionTimer.start(); } catch( e : ArgumentError ) { // Invalid parameters. status = "ERROR: " + e.message; } } /** * Method called when connection timed out */ public function connectionTimeout (e:TimerEvent) : void { status = "FAILED"; _connectionListener(status, protocol, hostname, port, application); close(); } /** * Close connection. */ public function close() : void { //Stop timeout timer when connected/rejected connectionTimer.stop(); // Remove listener. this.nc.removeEventListener( NetStatusEvent.NET_STATUS, netStatus ); // Close the NetConnection. this.nc.close(); } /** * Catch NetStatusEvents. * * @param event */ protected function netStatus( event : NetStatusEvent ) : void { var info : Object = event.info; var statusCode : String = info.code; // if ( statusCode == "NetConnection.Connect.Success" ) { status = "SUCCESS"; _connectionListener(status, protocol, hostname, port, application); } connectionTimer = new Timer(testTimeout, 1); connectionTimer.addEventListener(TimerEvent.TIMER, connectionTimeout); statusCode == "NetConnection.Connect.Closed" ) // Create connection with the server. } _connectionListener(status, protocol, hostname, port, application); } catch( e : ArgumentError ) connectionTimer = new Timer(testTimeout, 1); } 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]); } public function addConnectionSuccessListener(listener:Function):void { _connectionListener = listener; } } }
this.nc.addEventListener( NetStatusEvent.NET_STATUS, netStatus ); // connect to server try { LOGGER.debug("Testing connection to " + this.baseURI); // Create connection with the server. this.nc.connect( this.baseURI, "portTestMeetingId", "portTestDummyUserId" ); status = "Connecting..."; connectionTimer = new Timer(testTimeout, 1); connectionTimer.addEventListener(TimerEvent.TIMER, connectionTimeout); connectionTimer.start(); } catch( e : ArgumentError ) { // Invalid parameters. status = "ERROR: " + e.message; } } /** * Method called when connection timed out */ public function connectionTimeout (e:TimerEvent) : void { LOGGER.debug("Timedout trying to connect to " + this.baseURI); status = "FAILED"; _connectionListener(status, tunnel, hostname, port, application); close(); } /** * Close connection. */ public function close() : void { //Stop timeout timer when connected/rejected connectionTimer.stop(); // Remove listener. this.nc.removeEventListener( NetStatusEvent.NET_STATUS, netStatus ); // Close the NetConnection. this.nc.close(); } /** * Catch NetStatusEvents. * * @param event */ protected function netStatus( event : NetStatusEvent ) : void { var info : Object = event.info; var statusCode : String = info.code; // // Close NetConnection. close(); connectionTimer = new Timer(testTimeout, 1); } status = "Connecting..."; connectionTimer = new Timer(testTimeout, 1); catch( e : ArgumentError ) connectionTimer.addEventListener(TimerEvent.TIMER, connectionTimeout); connectionTimer.addEventListener(TimerEvent.TIMER, connectionTimeout); // Create connection with the server. connectionTimer.addEventListener(TimerEvent.TIMER, connectionTimeout); statusCode == "NetConnection.Connect.Closed" ) { LOGGER.debug("Failed to connect to " + this.baseURI); } connectionTimer.addEventListener(TimerEvent.TIMER, connectionTimeout); } } 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]); } public function addConnectionSuccessListener(listener:Function):void { _connectionListener = listener; } } }

View File

@ -28,31 +28,29 @@ package org.bigbluebutton.main.model {
private static const LOGGER:ILogger = getClassLogger(PortTestProxy);
private var nc:NetConnection;
private var protocol:String;
private var tunnel:Boolean;
private var port:String;
private var hostname:String;
private var application:String;
private var uri:String;
private var modulesDispatcher:ModulesDispatcher;
public function PortTestProxy(modulesDispatcher: ModulesDispatcher) {
this.modulesDispatcher = modulesDispatcher;
}
public function connect(protocol:String = "", hostname:String = "", port:String = "", application:String = "", testTimeout:Number = 10000):void {
var portTest:PortTest = new PortTest(protocol,hostname,port,application, testTimeout);
public function connect(tunnel:Boolean, hostname:String = "", port:String = "", application:String = "", testTimeout:Number = 10000):void {
this.tunnel = tunnel;
var portTest:PortTest = new PortTest(tunnel, hostname, port, application, testTimeout);
portTest.addConnectionSuccessListener(connectionListener);
var red5Url:String = protocol + "://" + hostname + "/" + application;
portTest.connect();
}
private function connectionListener(status:String, protocol:String, hostname:String, port:String, application:String):void {
uri = protocol + "://" + hostname + "/" + application;
private function connectionListener(status:String, tunnel:Boolean, hostname:String, port:String, application:String):void {
if (status == "SUCCESS") {
modulesDispatcher.sendPortTestSuccessEvent(port, hostname, protocol, application);
modulesDispatcher.sendPortTestSuccessEvent(port, hostname, tunnel, application);
} else {
modulesDispatcher.sendPortTestFailedEvent(port, hostname, protocol, application);
modulesDispatcher.sendPortTestFailedEvent(port, hostname, tunnel, application);
}
}
@ -66,14 +64,13 @@ package org.bigbluebutton.main.model {
var statusCode : String = info.code;
if (statusCode == "NetConnection.Connect.Success") {
modulesDispatcher.sendPortTestSuccessEvent(port, hostname, protocol, application);
modulesDispatcher.sendPortTestSuccessEvent(port, hostname, tunnel, application);
} else if (statusCode == "NetConnection.Connect.Rejected" ||
statusCode == "NetConnection.Connect.Failed" ||
statusCode == "NetConnection.Connect.Closed" ) {
LOGGER.error("::netStatusEventHandler - Failed to connect to {0}", [uri]);
modulesDispatcher.sendPortTestFailedEvent(port, hostname, protocol, application);
modulesDispatcher.sendPortTestFailedEvent(port, hostname, tunnel, application);
} else {
LOGGER.error("Failed to connect to {0} due to {1}", [uri, statusCode]);
modulesDispatcher.sendPortTestFailedEvent(port, hostname, tunnel, application);
}
// Close NetConnection.
close();

View File

@ -18,15 +18,19 @@
*/
package org.bigbluebutton.main.model.modules
{
import com.asfusion.mate.events.Dispatcher;
import com.asfusion.mate.events.Dispatcher;
import flash.system.ApplicationDomain;
import flash.utils.Dictionary;
import mx.collections.ArrayCollection;
import flash.utils.Dictionary;
import mx.collections.ArrayCollection;
import org.as3commons.logging.api.ILogger;
import org.as3commons.logging.api.getClassLogger;
import org.bigbluebutton.common.IBigBlueButtonModule;
import org.bigbluebutton.common.Role;
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.core.model.MeetingModel;
import org.bigbluebutton.main.events.AppVersionEvent;
import org.bigbluebutton.main.model.ConferenceParameters;
@ -44,8 +48,6 @@ package org.bigbluebutton.main.model.modules
private var _applicationDomain:ApplicationDomain;
private var conferenceParameters:ConferenceParameters;
private var _protocol:String;
private var modulesDispatcher:ModulesDispatcher;
public function ModuleManager(modulesDispatcher: ModulesDispatcher)
@ -72,8 +74,8 @@ package org.bigbluebutton.main.model.modules
BBB.loadConfig();
}
public function useProtocol(protocol:String):void {
_protocol = protocol;
public function useProtocol(tunnel:Boolean):void {
BBB.initConnectionManager().isTunnelling = tunnel;
}
public function get portTestHost():String {
@ -96,7 +98,11 @@ package org.bigbluebutton.main.model.modules
var m:ModuleDescriptor = getModule(name);
if (m != null) {
var bbb:IBigBlueButtonModule = m.module as IBigBlueButtonModule;
m.loadConfigAttributes(conferenceParameters, _protocol);
var protocol:String = "rtmp";
if (BBB.initConnectionManager().isTunnelling) {
protocol = "rtmpt";
}
m.loadConfigAttributes(conferenceParameters, protocol);
bbb.start(m.attributes);
}
}
@ -155,8 +161,7 @@ package org.bigbluebutton.main.model.modules
}
public function startUserServices():void {
var appURL:String = BBB.getConfigManager().config.application.uri.replace(/rtmp:/gi, _protocol + ":");
modulesDispatcher.sendStartUserServicesEvent(appURL, BBB.getConfigManager().config.application.host, _protocol.toUpperCase() == "RTMPT");
modulesDispatcher.sendStartUserServicesEvent();
}
public function loadAllModules(parameters:ConferenceParameters):void{

View File

@ -18,10 +18,8 @@
*/
package org.bigbluebutton.main.model.modules
{
import com.asfusion.mate.events.Dispatcher;
import flash.events.TimerEvent;
import com.asfusion.mate.events.Dispatcher;
import flash.events.TimerEvent;
import org.as3commons.logging.api.ILogger;
import org.as3commons.logging.api.getClassLogger;
import org.as3commons.logging.util.jsonXify;
@ -71,11 +69,8 @@ package org.bigbluebutton.main.model.modules
dispatcher.dispatchEvent(loginEvent);
}
public function sendStartUserServicesEvent(application:String, host:String, isTunnelling:Boolean):void{
public function sendStartUserServicesEvent():void{
var e:UserServicesEvent = new UserServicesEvent(UserServicesEvent.START_USER_SERVICES);
e.applicationURI = application;
e.hostURI = host;
e.isTunnelling = isTunnelling;
dispatcher.dispatchEvent(e);
}
@ -130,11 +125,11 @@ package org.bigbluebutton.main.model.modules
dispatcher.dispatchEvent(new PortTestEvent(PortTestEvent.TUNNELING_FAILED));
}
public function sendPortTestSuccessEvent(port:String, host:String, protocol:String, app:String):void{
public function sendPortTestSuccessEvent(port:String, host:String, tunnel:Boolean, app:String):void{
var logData:Object = new Object();
logData.port = port;
logData.server = host;
logData.protocol = protocol;
logData.tunnel = tunnel;
logData.app = app;
logData.userId = meetingInfo.userId;
logData.username = meetingInfo.username;
@ -145,17 +140,17 @@ package org.bigbluebutton.main.model.modules
var portEvent:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_SUCCESS);
portEvent.port = port;
portEvent.hostname = host;
portEvent.protocol = protocol;
portEvent.tunnel = tunnel;
portEvent.app = app;
dispatcher.dispatchEvent(portEvent);
}
public function sendPortTestFailedEvent(port:String, host:String, protocol:String, app:String):void{
public function sendPortTestFailedEvent(port:String, host:String, tunnel:Boolean, app:String):void{
var portFailEvent:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_FAILED);
portFailEvent.port = port;
portFailEvent.hostname = host;
portFailEvent.protocol = protocol;
portFailEvent.tunnel = tunnel;
portFailEvent.app = app;
dispatcher.dispatchEvent(portFailEvent);

View File

@ -42,8 +42,9 @@ package org.bigbluebutton.main.model.modules
return _user.username;
}
public function portTestSuccess(protocol:String):void {
modulesManager.useProtocol(protocol);
public function portTestSuccess(tunnel:Boolean):void {
LOGGER.debug("Successfully tested connection to server. isTunnelling=" + tunnel);
modulesManager.useProtocol(tunnel);
modulesManager.startUserServices();
}
@ -72,12 +73,16 @@ package org.bigbluebutton.main.model.modules
}
public function testRTMP():void{
portTestProxy.connect("RTMP", getPortTestHost(), "1935", getPortTestApplication(), getPortTestTimeout());
portTestProxy.connect(false /*"RTMP"*/, getPortTestHost(), "1935", getPortTestApplication(), getPortTestTimeout());
}
public function testRTMPT(protocol:String):void{
if (protocol == "RTMP") portTestProxy.connect("RTMPT", getPortTestHost(), "", getPortTestApplication(), getPortTestTimeout());
else modulesDispatcher.sendTunnelingFailedEvent(getPortTestHost(), getPortTestApplication());
public function testRTMPT(tunnel:Boolean):void{
if (! tunnel) {
// Try to test using rtmpt as rtmp failed.
portTestProxy.connect(true /*"RTMPT"*/, getPortTestHost(), "", getPortTestApplication(), getPortTestTimeout());
} else {
modulesDispatcher.sendTunnelingFailedEvent(getPortTestHost(), getPortTestApplication());
}
}
public function loadAllModules(params:ConferenceParameters):void{

View File

@ -389,6 +389,7 @@ package org.bigbluebutton.main.model.users
n.disableMyMic = user.disableMyMic;
n.disableMyPrivateChat = user.disableMyPrivateChat;
n.disableMyPublicChat = user.disableMyPublicChat;
n.breakoutRooms = user.breakoutRooms.concat(); // concatenate an array with nothing to deliver a new array.
return n;
}

View File

@ -633,6 +633,16 @@ package org.bigbluebutton.main.model.users {
}
}
}
public function getBreakoutRoomInListen() : BreakoutRoom {
for (var i:int = 0; i < breakoutRooms.length; i++) {
var br:BreakoutRoom = BreakoutRoom(breakoutRooms.getItemAt(i));
if (br.listenStatus == BreakoutRoom.SELF) {
return br;
}
}
return null;
}
public function resetBreakoutRooms():void {
for (var i:int = 0; i < breakoutRooms.length; i++) {

View File

@ -18,8 +18,7 @@
*/
package org.bigbluebutton.main.model.users
{
import com.asfusion.mate.events.Dispatcher;
import com.asfusion.mate.events.Dispatcher;
import flash.events.AsyncErrorEvent;
import flash.events.IOErrorEvent;
import flash.events.NetStatusEvent;
@ -30,6 +29,7 @@ package org.bigbluebutton.main.model.users
import flash.utils.Timer;
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.core.services.BandwidthMonitor;
@ -39,7 +39,7 @@ package org.bigbluebutton.main.model.users
import org.bigbluebutton.main.model.ConferenceParameters;
import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
import org.bigbluebutton.main.model.users.events.UsersConnectionEvent;
public class NetConnectionDelegate
{
private static const LOGGER:ILogger = getClassLogger(NetConnectionDelegate);
@ -50,17 +50,8 @@ package org.bigbluebutton.main.model.users
private var _userid:Number = -1;
private var _role:String = "unknown";
private var _applicationURI:String;
private var _conferenceParameters:ConferenceParameters;
// These two are just placeholders. We'll get this from the server later and
// then pass to other modules.
private var _authToken:String = "AUTHORIZED";
private var _room:String;
private var tried_tunneling:Boolean = false;
private var logoutOnUserCommand:Boolean = false;
private var backoff:Number = 2000;
private var dispatcher:Dispatcher;
private var _messageListeners:Array = new Array();
@ -70,24 +61,10 @@ package org.bigbluebutton.main.model.users
private var _validateTokenTimer:Timer = null;
public function NetConnectionDelegate():void
{
public function NetConnectionDelegate():void {
dispatcher = new Dispatcher();
_netConnection = new NetConnection();
_netConnection.proxyType = "best";
_netConnection.client = this;
_netConnection.addEventListener( NetStatusEvent.NET_STATUS, netStatus );
_netConnection.addEventListener( AsyncErrorEvent.ASYNC_ERROR, netASyncError );
_netConnection.addEventListener( SecurityErrorEvent.SECURITY_ERROR, netSecurityError );
_netConnection.addEventListener( IOErrorEvent.IO_ERROR, netIOError );
}
public function setUri(uri:String):void {
_applicationURI = uri;
}
public function get connection():NetConnection {
return _netConnection;
}
@ -136,9 +113,11 @@ package org.bigbluebutton.main.model.users
}
private function validateToken():void {
var confParams:ConferenceParameters = BBB.initUserConfigManager().getConfParams();
var message:Object = new Object();
message["userId"] = _conferenceParameters.internalUserID;
message["authToken"] = _conferenceParameters.authToken;
message["userId"] = confParams.internalUserID;
message["authToken"] = confParams.authToken;
_validateTokenTimer = new Timer(7000, 1);
_validateTokenTimer.addEventListener(TimerEvent.TIMER, validataTokenTimerHandler);
@ -265,18 +244,39 @@ package org.bigbluebutton.main.model.users
* mode: LIVE/PLAYBACK - Live:when used to collaborate, Playback:when being used to playback a recorded conference.
* room: Need the room number when playing back a recorded conference. When LIVE, the room is taken from the URI.
*/
public function connect(params:ConferenceParameters, tunnel:Boolean = false):void {
_conferenceParameters = params;
public function connect():void {
var confParams:ConferenceParameters = BBB.initUserConfigManager().getConfParams();
tried_tunneling = tunnel;
_netConnection = new NetConnection();
_netConnection.proxyType = "best";
_netConnection.client = this;
_netConnection.addEventListener( NetStatusEvent.NET_STATUS, netStatus );
_netConnection.addEventListener( AsyncErrorEvent.ASYNC_ERROR, netASyncError );
_netConnection.addEventListener( SecurityErrorEvent.SECURITY_ERROR, netSecurityError );
_netConnection.addEventListener( IOErrorEvent.IO_ERROR, netIOError );
try {
var uri:String = _applicationURI + "/" + _conferenceParameters.room;
_netConnection.connect(uri, _conferenceParameters.username, _conferenceParameters.role,
_conferenceParameters.room, _conferenceParameters.voicebridge,
_conferenceParameters.record, _conferenceParameters.externUserID,
_conferenceParameters.internalUserID, _conferenceParameters.muteOnStart, _conferenceParameters.lockSettings);
var appURL:String = BBB.getConfigManager().config.application.uri;
var pattern:RegExp = /(?P<protocol>.+):\/\/(?P<server>.+)\/(?P<app>.+)/;
var result:Array = pattern.exec(appURL);
var protocol:String = "rtmp";
var uri:String = appURL + "/" + confParams.room;
if (BBB.initConnectionManager().isTunnelling) {
uri = "rtmpt://" + result.server + "/" + result.app + "/" + confParams.room;
} else {
uri = "rtmp://" + result.server + ":1935/" + result.app + "/" + confParams.room;
}
LOGGER.debug("BBB Apps URI=" + uri);
_netConnection.connect(uri, confParams.username, confParams.role,
confParams.room, confParams.voicebridge,
confParams.record, confParams.externUserID,
confParams.internalUserID, confParams.muteOnStart, confParams.lockSettings);
} catch(e:ArgumentError) {
// Invalid parameters.
switch (e.errorID) {
@ -304,17 +304,6 @@ package org.bigbluebutton.main.model.users
handleResult( event );
}
private var _bwMon:BandwidthMonitor = new BandwidthMonitor();
private function startMonitoringBandwidth():void {
LOGGER.info("Start monitoring bandwidth.");
var pattern:RegExp = /(?P<protocol>.+):\/\/(?P<server>.+)\/(?P<app>.+)/;
var result:Array = pattern.exec(_applicationURI);
_bwMon.serverURL = result.server;
_bwMon.serverApplication = "video";
_bwMon.start();
}
public function handleResult(event:Object):void {
var info : Object = event.info;
var statusCode : String = info.code;
@ -326,29 +315,18 @@ package org.bigbluebutton.main.model.users
case "NetConnection.Connect.Success":
numNetworkChangeCount = 0;
JSLog.debug("Successfully connected to BBB App.", logData);
validateToken();
break;
case "NetConnection.Connect.Failed":
if (tried_tunneling) {
LOGGER.error(":Connection to viewers application failed...even when tunneling");
sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_FAILED);
} else {
disconnect(false);
LOGGER.error(":Connection to viewers application failed...try tunneling");
var rtmptRetryTimer:Timer = new Timer(1000, 1);
rtmptRetryTimer.addEventListener("timer", rtmptRetryTimerHandler);
rtmptRetryTimer.start();
}
sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_FAILED);
break;
case "NetConnection.Connect.Closed":
logData.message = "NetConnection.Connect.Closed on bbb-apps";
LOGGER.info(JSON.stringify(logData));
sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_CLOSED);
break;
case "NetConnection.Connect.InvalidApp":
@ -362,7 +340,8 @@ package org.bigbluebutton.main.model.users
break;
case "NetConnection.Connect.Rejected":
LOGGER.debug(":Connection to the server rejected. Uri: {0}. Check if the red5 specified in the uri exists and is running", [_applicationURI]);
var appURL:String = BBB.getConfigManager().config.application.uri
LOGGER.debug(":Connection to the server rejected. Uri: {0}. Check if the red5 specified in the uri exists and is running", [appURL]);
sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_REJECTED);
break;
@ -381,11 +360,6 @@ package org.bigbluebutton.main.model.users
break;
}
}
private function rtmptRetryTimerHandler(event:TimerEvent):void {
LOGGER.debug("rtmptRetryTimerHandler: {0}", [event]);
connect(_conferenceParameters, true);
}
protected function netSecurityError(event: SecurityErrorEvent):void {
LOGGER.error("Security error - {0}", [event.text]);
@ -402,44 +376,50 @@ package org.bigbluebutton.main.model.users
sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON);
}
private function sendConnectionFailedEvent(reason:String):void{
var logData:Object = new Object();
private function sendConnectionFailedEvent(reason:String):void{
var logData:Object = new Object();
if (this.logoutOnUserCommand) {
logData.reason = "User requested.";
logData.user = UsersUtil.getUserData();
JSLog.debug("User logged out from BBB App.", logData);
sendUserLoggedOutEvent();
} else if (reason == ConnectionFailedEvent.CONNECTION_CLOSED && !UsersUtil.isUserEjected()) {
// do not try to reconnect if the connection failed is different than CONNECTION_CLOSED
logData.reason = reason;
logData.user = UsersUtil.getUserData();
JSLog.warn("User disconnected from BBB App.", logData);
if (this.logoutOnUserCommand) {
logData.reason = "User requested.";
logData.user = UsersUtil.getUserData();
logData.message = "User logged out from BBB App.";
LOGGER.info(JSON.stringify(logData));
sendUserLoggedOutEvent();
} else if (reason == ConnectionFailedEvent.CONNECTION_CLOSED && !UsersUtil.isUserEjected()) {
// do not try to reconnect if the connection failed is different than CONNECTION_CLOSED
logData.reason = reason;
logData.user = UsersUtil.getUserData();
logData.message = "User disconnected from BBB App.";
LOGGER.info(JSON.stringify(logData));
if (reconnecting) {
var attemptFailedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_CONNECTION_ATTEMPT_FAILED_EVENT);
attemptFailedEvent.payload.type = ReconnectionManager.BIGBLUEBUTTON_CONNECTION;
dispatcher.dispatchEvent(attemptFailedEvent);
} else {
reconnecting = true;
authenticated = false;
if (reconnecting) {
var attemptFailedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_CONNECTION_ATTEMPT_FAILED_EVENT);
attemptFailedEvent.payload.type = ReconnectionManager.BIGBLUEBUTTON_CONNECTION;
dispatcher.dispatchEvent(attemptFailedEvent);
} else {
reconnecting = true;
authenticated = false;
var disconnectedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_DISCONNECTED_EVENT);
disconnectedEvent.payload.type = ReconnectionManager.BIGBLUEBUTTON_CONNECTION;
disconnectedEvent.payload.callback = connect;
disconnectedEvent.payload.callbackParameters = new Array(_conferenceParameters, tried_tunneling);
dispatcher.dispatchEvent(disconnectedEvent);
var disconnectedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_DISCONNECTED_EVENT);
disconnectedEvent.payload.type = ReconnectionManager.BIGBLUEBUTTON_CONNECTION;
disconnectedEvent.payload.callback = connect;
disconnectedEvent.payload.callbackParameters = new Array();
dispatcher.dispatchEvent(disconnectedEvent);
}
} else {
if (UsersUtil.isUserEjected()) {
logData.user = UsersUtil.getUserData();
logData.message = "User has been ejected from meeting.";
LOGGER.info(JSON.stringify(logData));
reason = ConnectionFailedEvent.USER_EJECTED_FROM_MEETING;
}
LOGGER.debug("Connection failed event - " + reason);
var e:ConnectionFailedEvent = new ConnectionFailedEvent(reason);
dispatcher.dispatchEvent(e);
}
}
} else {
if (UsersUtil.isUserEjected()) {
LOGGER.debug("User has been ejected from meeting.");
reason = ConnectionFailedEvent.USER_EJECTED_FROM_MEETING;
}
LOGGER.debug("Connection failed event - " + reason);
var e:ConnectionFailedEvent = new ConnectionFailedEvent(reason);
dispatcher.dispatchEvent(e);
}
}
private function sendUserLoggedOutEvent():void{
var e:ConnectionFailedEvent = new ConnectionFailedEvent(ConnectionFailedEvent.USER_LOGGED_OUT);

View File

@ -18,11 +18,9 @@
*/
package org.bigbluebutton.main.model.users
{
import com.asfusion.mate.events.Dispatcher;
import com.asfusion.mate.events.Dispatcher;
import flash.external.ExternalInterface;
import flash.net.NetConnection;
import flash.net.NetConnection;
import mx.collections.ArrayCollection;
import org.as3commons.logging.api.ILogger;
@ -67,14 +65,10 @@ package org.bigbluebutton.main.model.users
dispatcher = new Dispatcher();
}
public function startService(e:UserServicesEvent):void {
applicationURI = e.applicationURI;
hostURI = e.hostURI;
BBB.initConnectionManager().isTunnelling = e.isTunnelling;
public function startService(e:UserServicesEvent):void {
joinService = new JoinService();
joinService.addJoinResultListener(joinListener);
joinService.load(e.hostURI);
joinService.load(BBB.getConfigManager().config.application.host);
}
private function joinListener(success:Boolean, result:Object):void {
@ -110,7 +104,7 @@ package org.bigbluebutton.main.model.users
_conferenceParameters.username = result.username;
_conferenceParameters.role = result.role;
_conferenceParameters.room = result.room;
_conferenceParameters.authToken = result.authToken;
_conferenceParameters.authToken = result.authToken;
_conferenceParameters.webvoiceconf = result.webvoiceconf;
_conferenceParameters.voicebridge = result.voicebridge;
_conferenceParameters.welcome = result.welcome;
@ -148,8 +142,7 @@ package org.bigbluebutton.main.model.users
private function connect():void{
_connectionManager = BBB.initConnectionManager();
_connectionManager.setUri(applicationURI);
_connectionManager.connect(_conferenceParameters);
_connectionManager.connect();
}
public function logoutUser():void {
@ -210,7 +203,7 @@ package org.bigbluebutton.main.model.users
}
public function requestBreakoutJoinUrl(e:BreakoutRoomEvent):void{
sender.requestBreakoutJoinUrl(_conferenceParameters.meetingID, e.breakoutId, _conferenceParameters.userid);
sender.requestBreakoutJoinUrl(_conferenceParameters.meetingID, e.breakoutId, e.userId);
}
public function listenInOnBreakout(e:BreakoutRoomEvent):void {

View File

@ -26,7 +26,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
x="168" y="86" layout="vertical" width="400" height="110" horizontalAlign="center">
<mx:Script>
<![CDATA[
import mx.core.FlexGlobals;
import flash.net.navigateToURL;
import mx.managers.PopUpManager;
import org.as3commons.logging.api.ILogger;
@ -35,52 +36,57 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
import org.bigbluebutton.util.i18n.ResourceUtil;
private static const LOGGER:ILogger = getClassLogger(LoggedOutWindow);
[Bindable] private var message:String = "You have logged out of the conference";
private static const LOGGER:ILogger = getClassLogger(LoggedOutWindow);
[Bindable]
private var message:String;
private var urlLoader:URLLoader;
private function init():void {
addEventListener(Event.CLOSE, onUserLoggedOutWindowClose);
}
private function redirect():void {
private function callSignOut():void {
var logoutURL:String = BBB.getSignoutURL();
var request:URLRequest = new URLRequest(logoutURL);
LOGGER.debug("Log out url: " + logoutURL);
request.method = URLRequestMethod.GET;
urlLoader = new URLLoader();
// If the redirect value is set to false handleComplete will be triggered
urlLoader.addEventListener(Event.COMPLETE, handleComplete);
urlLoader.addEventListener(IOErrorEvent.IO_ERROR, handleRedirectError);
urlLoader.load(request);
}
private function exitApplication():void {
if (!UserManager.getInstance().getConference().isBreakout) {
var logoutURL:String = BBB.getLogoutURL();
var request:URLRequest = new URLRequest(logoutURL);
LOGGER.debug("Log out url: " + logoutURL);
request.method = URLRequestMethod.GET;
urlLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, handleComplete);
urlLoader.addEventListener(IOErrorEvent.IO_ERROR, handleRedirectError);
urlLoader.load(request);
navigateToURL(new URLRequest(BBB.getLogoutURL()), "_self");
} else {
ExternalInterface.call("window.close");
}
}
private function handleComplete(e:Event):void {
LOGGER.debug("Client URL=[{0}]", [FlexGlobals.topLevelApplication.url]);
var logoutURL:String = BBB.getLogoutURL();
var request:URLRequest = new URLRequest(logoutURL);
LOGGER.debug("Logging out to: {0}", [logoutURL]);
navigateToURL(request, '_self');
PopUpManager.removePopUp(this);
PopUpManager.removePopUp(this);
exitApplication();
}
private function handleRedirectError(e:IOErrorEvent):void {
LOGGER.error("Log out redirection returned with error.");
PopUpManager.removePopUp(this);
exitApplication();
}
private function onUserLoggedOutWindowClose(e:Event):void {
LOGGER.debug("Closing UserLoggedOutWindow");
PopUpManager.removePopUp(this);
}
private function onUserLoggedOutWindowClose(e:Event):void {
PopUpManager.removePopUp(this);
}
public function setReason(reason:String):void{
switch(reason){
public function setReason(reason:String):void {
LOGGER.debug("Received ConnectionFailedEvent with reason: " + reason);
switch (reason) {
case ConnectionFailedEvent.APP_SHUTDOWN:
message = ResourceUtil.getInstance().getString('bbb.logout.appshutdown');
break;
@ -102,19 +108,21 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
case ConnectionFailedEvent.UNKNOWN_REASON:
message = ResourceUtil.getInstance().getString('bbb.logout.unknown');
break;
case ConnectionFailedEvent.USER_EJECTED_FROM_MEETING:
message = ResourceUtil.getInstance().getString('bbb.logout.ejectedFromMeeting');
break;
case ConnectionFailedEvent.USER_EJECTED_FROM_MEETING:
message = ResourceUtil.getInstance().getString('bbb.logout.ejectedFromMeeting');
break;
case ConnectionFailedEvent.USER_LOGGED_OUT:
message = ResourceUtil.getInstance().getString('bbb.logout.usercommand');
redirect(); // we know that the disconnect was requested so automatically redirect
break;
}
if (message && UserManager.getInstance().getConference().isBreakout) {
message += "\n" + ResourceUtil.getInstance().getString('bbb.logour.breakoutRoomClose');
}
}
]]>
</mx:Script>
<mx:VBox width="100%" height="100%" horizontalAlign="center">
<mx:Text text="{message}"/>
<mx:Button id="okBtn" label="{ResourceUtil.getInstance().getString('bbb.logout.button.label')}" click="redirect()"/>
<mx:Text text="{message}" textAlign="center"/>
<mx:Button id="okBtn" label="{ResourceUtil.getInstance().getString('bbb.logout.button.label')}" click="callSignOut()"/>
</mx:VBox>
</mx:TitleWindow>

View File

@ -624,9 +624,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
ls.y = point1.y - (ls.height/2);
}
private function openBreakoutRoomsWindow(e:Event = null):void {
private function openBreakoutRoomsWindow(e:BreakoutRoomEvent):void {
var popUp:IFlexDisplayObject = PopUpManager.createPopUp(mdiCanvas, BreakoutRoomSettings, true);
PopUpManager.centerPopUp(popUp);
BreakoutRoomSettings(popUp).initCreateBreakoutRooms(e.joinMode);
}
private function onFooterLinkClicked(e:TextEvent):void{

View File

@ -94,6 +94,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
messages.push(obj);
showNotification();
LOGGER.warn("ClientNotification:" + e.title + " " + e.message);
}
private function showNotification():void {

View File

@ -99,13 +99,17 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private function yesButtonClicked():void {
userClosed = true;
LOGGER.debug("Echo test passed.");
var logData:Object = new Object();
logData.reason = "User requested.";
logData.user = UsersUtil.getUserData();
logData.message = "WebRtc Echo test passed.";
JSLog.info("WebRtc Echo test passed.", logData);
LOGGER.info(JSON.stringify(logData));
setCurrentState("connecting");
lblConnectMessage.text = lblConnectMessageMock.text = ResourceUtil.getInstance().getString('bbb.micSettings.webrtc.endingecho');
@ -115,7 +119,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private function noButtonClicked():void {
userClosed = true;
LOGGER.warn("Echo test failed.");
var logData:Object = new Object();
logData.reason = "User requested.";
logData.user = UsersUtil.getUserData();
logData.message = "WebRtc Echo test failed.";
LOGGER.info(JSON.stringify(logData));
var dispatcher:Dispatcher = new Dispatcher();
dispatcher.dispatchEvent(new WebRTCEchoTestEvent(WebRTCEchoTestEvent.WEBRTC_ECHO_TEST_NO_AUDIO));
@ -123,7 +133,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
private function handleWebRTCEchoTestStartedEvent(e:WebRTCEchoTestStartedEvent):void {
webRTCEchoTestStarted();
webRTCEchoTestStarted();
}
private function webRTCEchoTestStarted():void {
@ -183,7 +193,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
var logData:Object = new Object();
logData.reason = "User requested.";
logData.user = UsersUtil.getUserData();
JSLog.info("WebRtc call started.", logData);
logData.message = "WebRtc call started.";
LOGGER.info(JSON.stringify(logData));
onCancelClicked();
}

View File

@ -26,6 +26,7 @@ package org.bigbluebutton.modules.caption.events {
public var startIndex:int = -1;
public var endIndex:int = -1;
public var locale:String = "";
public var localeCode:String = "";
public var text:String = "";
public function ReceiveEditCaptionHistoryEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) {

View File

@ -24,6 +24,7 @@ package org.bigbluebutton.modules.caption.events {
public static const RECEIVE_UPDATE_CAPTION_OWNER_EVENT:String = "RECEIVE_UPDATE_CAPTION_OWNER_EVENT";
public var locale:String = "";
public var localeCode:String = "";
public var ownerID:String = "";
public function ReceiveUpdateCaptionOwnerEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) {

View File

@ -26,6 +26,7 @@ package org.bigbluebutton.modules.caption.events {
public var startIndex:int = -1;
public var endIndex:int = -1;
public var locale:String = "";
public var localeCode:String = "";
public var text:String = "";
public function SendEditCaptionHistoryEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) {

View File

@ -24,6 +24,7 @@ package org.bigbluebutton.modules.caption.events {
public static const SEND_UPDATE_CAPTION_OWNER_EVENT:String = "SEND_UPDATE_CAPTION_OWNER_EVENT";
public var locale:String = "";
public var localeCode:String = "";
public var claim:Boolean = false;
public function SendUpdateCaptionOwnerEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) {

View File

@ -56,11 +56,11 @@ package org.bigbluebutton.modules.caption.managers {
}
public function receiveUpdateCaptionOwner(event:ReceiveUpdateCaptionOwnerEvent):void {
_transcripts.updateCaptionOwner(event.locale, event.ownerID);
_transcripts.updateCaptionOwner(event.locale, event.localeCode, event.ownerID);
}
public function receiveEditCaptionHistory(event:ReceiveEditCaptionHistoryEvent):void {
_transcripts.editCaptionHistory(event.locale, event.startIndex, event.endIndex, event.text);
_transcripts.editCaptionHistory(event.locale, event.localeCode, event.startIndex, event.endIndex, event.text);
}
public function openWindow():void {

View File

@ -31,8 +31,12 @@ package org.bigbluebutton.modules.caption.model {
[Bindable]
public var locale:String;
public function Transcript(l:String) {
[Bindable]
public var localeCode:String;
public function Transcript(l:String, c:String) {
locale = l;
localeCode = c;
transcript = "";
ownerID = "";
}

View File

@ -49,29 +49,29 @@ package org.bigbluebutton.modules.caption.model {
var localeClassName:String = flash.utils.getQualifiedClassName(locale);
var localeClass:Class = flash.utils.getDefinitionByName(localeClassName) as Class;
var t:Transcript = findLocale((locale as localeClass).toString());
var t:Transcript = findLocale((locale as localeClass).toString(), history[locale][2]);
t.ownerID = history[locale][0];
t.editHistory(0,0,history[locale][1]);
}
_historyInited = true;
}
public function updateCaptionOwner(locale:String, ownerID:String):void {
findLocale(locale).ownerID = ownerID;
public function updateCaptionOwner(locale:String, code:String, ownerID:String):void {
findLocale(locale, code).ownerID = ownerID;
}
public function editCaptionHistory(locale:String, startIndex:int, endIndex:int, text:String):void {
public function editCaptionHistory(locale:String, code:String, startIndex:int, endIndex:int, text:String):void {
if (_historyInited) { // ignore updates until after history has been loaded
findLocale(locale).editHistory(startIndex, endIndex, text);
findLocale(locale, code).editHistory(startIndex, endIndex, text);
}
}
public function findLocale(locale:String):Transcript {
public function findLocale(locale:String, code:String):Transcript {
for each (var t:Transcript in transcriptCollection) {
if (t.locale == locale) return t;
}
var newTranscript:Transcript = new Transcript(locale);
var newTranscript:Transcript = new Transcript(locale, code);
transcriptCollection.addItem(newTranscript);
return newTranscript;
}

View File

@ -36,6 +36,7 @@ package org.bigbluebutton.modules.caption.services {
public function sendUpdateCaptionOwner(e:SendUpdateCaptionOwnerEvent):void {
var msg:Object = new Object();
msg.locale = e.locale;
msg.localeCode = e.localeCode;
msg.claim = e.claim;
sender.sendUpdateCaptionOwner(msg);
@ -47,6 +48,7 @@ package org.bigbluebutton.modules.caption.services {
msg.startIndex = e.startIndex;
msg.endIndex = e.endIndex;
msg.locale = e.locale;
msg.localeCode = e.localeCode;
msg.text = e.text;
sender.sendEditCaptionHistory(msg);

View File

@ -65,19 +65,21 @@ package org.bigbluebutton.modules.caption.services {
var event:ReceiveUpdateCaptionOwnerEvent = new ReceiveUpdateCaptionOwnerEvent(ReceiveUpdateCaptionOwnerEvent.RECEIVE_UPDATE_CAPTION_OWNER_EVENT);
event.locale = message.locale;
event.localeCode = message.localeCode;
event.ownerID = message.owner_id;
var dispatcher:Dispatcher = new Dispatcher();
dispatcher.dispatchEvent(event);
}
private function editCaptionHistory(message:Object):void {
//LOGGER.debug("editCaptionHistory {start_index:" + message.start_index+",end_index:"+message.end_index+",locale:"+message.locale+",text:'"+message.text+"'}");
//LOGGER.debug("editCaptionHistory {start_index:" + message.start_index+",end_index:"+message.end_index+",locale:"+message.locale+",locale_code"+message.locale_code+",text:'"+message.text+"'}");
//var map:Object = JSON.parse(message);
var event:ReceiveEditCaptionHistoryEvent = new ReceiveEditCaptionHistoryEvent(ReceiveEditCaptionHistoryEvent.RECEIVE_EDIT_CAPTION_HISTORY);
event.startIndex = int(message.start_index);
event.endIndex = int(message.end_index);
event.locale = message.locale;
event.localeCode = message.locale_code;
event.text = message.text;
var dispatcher:Dispatcher = new Dispatcher();
dispatcher.dispatchEvent(event);

View File

@ -40,6 +40,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import mx.binding.utils.ChangeWatcher;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.controls.Button;
import mx.events.FlexEvent;
import mx.managers.PopUpManager;
@ -105,8 +106,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
if (UserManager.getInstance().getConference().amIModerator()) {
transcriptsCollection = new ArrayCollection();
for each (var l:String in ResourceUtil.getInstance().localeNames) {
transcriptsCollection.addItem({locale: l});
var names:Array = ResourceUtil.getInstance().localeNames;
var codes:Array = ResourceUtil.getInstance().localeCodes;
for (var i:int=0; i<names.length; i++) {
transcriptsCollection.addItem({locale: names[i], localeCode: codes[i]});
}
} else {
transcriptsCollection = t.transcriptCollection;
@ -122,7 +127,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private function optionChange(type:int, val:Object):void {
switch (type) {
case OptionENUM.LOCALE:
onLocaleChange(String(val));
onLocaleChange(val);
break;
case OptionENUM.SIZE:
textTab.setFontSize(int(val));
@ -139,8 +144,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
}
private function onLocaleChange(locale:String):void {
currentTranscript = transcriptsObject.findLocale(locale);
private function onLocaleChange(item:Object):void {
currentTranscript = transcriptsObject.findLocale(item.locale, item.localeCode);
optionsTab.setCurrentTranscript(currentTranscript);
textTab.setCurrentTranscript(currentTranscript);
@ -157,6 +162,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
if (!captionTabs.contains(textTab)) {
addTextTab();
}
var tab:Button = captionTabs.getTabAt(0);
if (tab != null) {
tab.setStyle("fillColors", new Array(0xFFAE00, 0xD3800A));
}
}
private function onTranscriptOwnerIDChange(o:Object):void {
@ -190,6 +200,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
captionTabs.addChildAt(textTab, 0);
}
private function onTabChange():void {
var tab:Button = captionTabs.getTabAt(captionTabs.selectedIndex);
tab.setStyle("fillColors", new Array(0xFFFFFF, 0xCCCCCC));
}
private function localeChanged(e:Event):void{
resourcesChanged();
}
@ -224,6 +239,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mx:Box width="100%" height="100%" horizontalAlign="left">
<containers:SuperTabNavigator id="captionTabs"
width="100%" height="100%" minTabWidth="20"
dragEnabled="false" popUpButtonPolicy="off" />
dragEnabled="false" popUpButtonPolicy="off"
change="onTabChange()"/>
</mx:Box>
</CustomMdiWindow>

Some files were not shown because too many files have changed in this diff Show More