/*
* (C) Copyright 2014 Kurento (http://kurento.org/)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library 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.
*
*/
package com.kurento.demo.cebit;
import static java.lang.reflect.Modifier.TRANSIENT;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.kurento.demo.common.WebRTCParticipant;
import com.kurento.kmf.content.ContentCommand;
import com.kurento.kmf.content.ContentCommandResult;
import com.kurento.kmf.content.ContentEvent;
import com.kurento.kmf.content.WebRtcContentHandler;
import com.kurento.kmf.content.WebRtcContentService;
import com.kurento.kmf.content.WebRtcContentSession;
import com.kurento.kmf.media.MediaPipeline;
import com.kurento.kmf.media.WebRtcEndpoint;
/**
* WebRtc Handler for OneToMany rooms.
*
* @author Miguel París Díaz (mparisdiaz@gmail.com)
* @author Ivan Gracia (izanmail@gmail.com)
* @author Boni Garcia (bgarcia@gsyc.es)
* @since 4.0.1
*/
@WebRtcContentService(path = "/selectable/*")
public class SelectableRoomHandler extends WebRtcContentHandler {
/* Commands */
public static final String COMMAND_GET_PARTICIPANTS = "getParticipants";
public static final String COMMAND_SELECT = "selectParticipant";
public static final String COMMAND_CONNECT = "connectParticipant";
/* Events */
public static final String EVENT_ON_JOINED = "onJoined";
public static final String EVENT_ON_UNJOINED = "onUnjoined";
/* Global variables */
private MediaPipeline mp;
private Map<String, WebRTCParticipant> participants;
private static final Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(TRANSIENT).create();
@Override
public void onContentRequest(WebRtcContentSession session) throws Exception {
if (mp == null) {
synchronized (this) {
if (mp == null) {
mp = session.getMediaPipelineFactory().create();
participants = new ConcurrentHashMap<String, WebRTCParticipant>();
}
}
}
String name = session.getContentId();
if (name == null || name.isEmpty()) {
name = "<no name>";
}
if (existName(name)) {
session.terminate(403, "User " + name + " is already in the room. "
+ "Please select another name and try again.");
} else {
WebRtcEndpoint endpoint = mp.newWebRtcEndpoint().build();
WebRTCParticipant participant = new WebRTCParticipant(
session.getSessionId(), name, endpoint, session);
participant.endpoint.connect(participant.endpoint);
session.start(participant.endpoint);
session.setAttribute("participant", participant);
participants.put(participant.getId(), participant);
notifyJoined(participant);
}
}
@Override
public ContentCommandResult onContentCommand(WebRtcContentSession session,
ContentCommand command) throws Exception {
String cmdType = command.getType();
String cmdData = command.getData();
getLogger().info("onContentCommand: ({}, {})", cmdType, cmdData);
if (COMMAND_GET_PARTICIPANTS.equalsIgnoreCase(cmdType)) {
String json = gson.toJson(participants.values());
return new ContentCommandResult(json);
} else if (COMMAND_SELECT.equalsIgnoreCase(cmdType)) {
return new ContentCommandResult(Boolean.toString(selectParticipant(
session, cmdData)));
} else if (COMMAND_CONNECT.equalsIgnoreCase(cmdType)) {
Type listType = new TypeToken<List<String>>() {
}.getType();
List<String> idList = gson.fromJson(cmdData, listType);
if (idList.size() != 2) {
return new ContentCommandResult(Boolean.FALSE.toString());
}
return new ContentCommandResult(
Boolean.toString(connectParticipant(idList.get(0),
idList.get(1))));
}
return super.onContentCommand(session, command);
}
@Override
public synchronized void onSessionTerminated(WebRtcContentSession session,
int code, String reason) throws Exception {
WebRTCParticipant participant = (WebRTCParticipant) session
.getAttribute("participant");
participants.remove(participant.getId());
notifyUnjoined(participant);
if (participants.isEmpty()) {
getLogger().info("Clearing room");
mp = null;
participants.clear();
}
super.onSessionTerminated(session, code, reason);
}
private boolean selectParticipant(WebRtcContentSession session,
String partId) {
WebRTCParticipant partSelected = participants.get(partId);
if (partSelected == null) {
getLogger().error("Participant {} does not exist", partId);
return false;
}
partSelected.endpoint.connect(((WebRTCParticipant) session
.getAttribute("participant")).endpoint);
return true;
}
private boolean connectParticipant(String origId, String destId) {
WebRTCParticipant orig = participants.get(origId);
if (orig == null) {
getLogger().error("Participant {} does not exist", origId);
return false;
}
WebRTCParticipant dest = participants.get(destId);
if (dest == null) {
getLogger().error("Participant {} does not exist", destId);
return false;
}
orig.endpoint.connect(dest.endpoint);
return true;
}
private boolean existName(final String name) {
for (WebRTCParticipant p : participants.values()) {
if (p.getName().equalsIgnoreCase(name)) {
return true;
}
}
return false;
}
private void notifyJoined(WebRTCParticipant participant) {
String json = gson.toJson(participant);
getLogger().info("Participant joined: {}", json);
for (WebRTCParticipant p : participants.values()) {
p.session.publishEvent(new ContentEvent(EVENT_ON_JOINED, json));
}
}
private void notifyUnjoined(WebRTCParticipant participant) {
String json = gson.toJson(participant);
getLogger().info("Participant unjoined: {}", json);
for (WebRTCParticipant p : participants.values()) {
p.session.publishEvent(new ContentEvent(EVENT_ON_UNJOINED, json));
}
}
}