Commit 4573b1aa authored by Dele Olajide's avatar Dele Olajide Committed by dele

Jitsi Videobridge - Implemented conference audio recording, not working yet

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13854 b35dd754-fafc-0310-a699-88a17e54d16e
parent c08c876c
package com.rayo.core.verb;
import org.dom4j.Element;
public class ColibriCommand extends AbstractVerbCommand {
private String videobridge;
private String localRTPPort;
private String localRTCPPort;
private String remoteRTPPort;
private String remoteRTCPPort;
private String codec;
public ColibriCommand(String videobridge, String localRTPPort, String localRTCPPort, String remoteRTPPort, String remoteRTCPPort, String codec)
{
this.videobridge = videobridge;
this.localRTPPort = localRTPPort;
this.localRTCPPort = localRTCPPort;
this.remoteRTPPort = remoteRTPPort;
this.remoteRTCPPort = remoteRTCPPort;
this.codec = codec;
}
public String getVideobridge()
{
return this.videobridge;
}
public String getLocalRTPPort()
{
return this.localRTPPort;
}
public String getLocalRTCPPort()
{
return this.localRTCPPort;
}
public String getRemoteRTPPort()
{
return this.remoteRTPPort;
}
public String getRemoteRTCPPort()
{
return this.remoteRTCPPort;
}
public String getCodec()
{
return this.codec;
}
}
...@@ -45,24 +45,13 @@ public class ColibriProvider extends BaseProvider { ...@@ -45,24 +45,13 @@ public class ColibriProvider extends BaseProvider {
private Object buildColibriCommand(Element element) throws URISyntaxException private Object buildColibriCommand(Element element) throws URISyntaxException
{ {
String action = element.attributeValue("action"); String action = element.attributeValue("action");
String videobridge = element.attributeValue("videobridge");
String localRTPPort = element.attributeValue("localrtpport");
String localRTCPPort = element.attributeValue("localrtcpport");
String remoteRTPPort = element.attributeValue("remotertpport");
String remoteRTCPPort = element.attributeValue("remotertcpport");
String codec = element.attributeValue("codec");
Object command = null; Object command = null;
if ("register".equals(action)) if ("register".equals(action)) {
{
command = new RegisterCommand(); command = new RegisterCommand();
} else if ("unregister".equals(action)) { } else if ("unregister".equals(action)) {
command = new UnRegisterCommand(); command = new UnRegisterCommand();
} else if ("bridge".equals(action)) {
command = new ColibriCommand(videobridge, localRTPPort, localRTCPPort, remoteRTPPort, remoteRTCPPort, codec);
} }
return command; return command;
......
/*
* Jitsi Videobridge, OpenSource video conferencing.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jitsi.videobridge;
import javax.media.*;
import javax.media.protocol.*;
import org.jitsi.impl.neomedia.device.*;
import org.jitsi.service.neomedia.*;
/**
* Implements a <tt>MediaDevice</tt> which provides silence in the form of audio
* media and does not play back any (audio) media (because Jitsi Videobridge is
* a server-side technology).
*
* @author Lyubomir Marinov
*/
public class AudioSilenceMediaDevice
extends AudioMediaDeviceImpl
{
/**
* {@inheritDoc}
*
* Overrides the super implementation to initialize a <tt>CaptureDevice</tt>
* without asking FMJ to initialize one for a <tt>CaptureDeviceInfo</tt>.
*/
@Override
protected CaptureDevice createCaptureDevice()
{
return new AudioSilenceCaptureDevice();
}
/**
* {@inheritDoc}
*
* Overrides the super implementation to disable the very playback because
* Jitsi Videobridge is a server-side technology.
*/
@Override
protected Processor createPlayer(DataSource dataSource)
{
return null;
}
/**
* {@inheritDoc}
*
* Overrides the super implementation to initialize a
* <tt>MediaDeviceSession</tt> which disables the very playback because
* Jitsi Videobridge is a server-side technology.
*/
@Override
public MediaDeviceSession createSession()
{
return
new AudioMediaDeviceSession(this)
{
/**
* {@inheritDoc}
*
* Overrides the super implementation to disable the
* very playback because Jitsi Videobridge is a
* server-side technology.
*/
@Override
protected Player createPlayer(DataSource dataSource)
{
return null;
}
};
}
/**
* {@inheritDoc}
*
* Overrides the super implementation to always return
* {@link MediaDirection#SENDRECV} because this instance stands for a relay
* and because the super bases the <tt>MediaDirection</tt> on the
* <tt>CaptureDeviceInfo</tt> which this instance does not have.
*/
@Override
public MediaDirection getDirection()
{
return MediaDirection.SENDRECV;
}
}
...@@ -14,6 +14,9 @@ import java.util.jar.*; ...@@ -14,6 +14,9 @@ import java.util.jar.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import javax.media.*;
import javax.media.protocol.*;
import org.jitsi.service.neomedia.*; import org.jitsi.service.neomedia.*;
import org.jitsi.util.*; import org.jitsi.util.*;
import org.jitsi.videobridge.*; import org.jitsi.videobridge.*;
...@@ -53,11 +56,14 @@ import org.dom4j.*; ...@@ -53,11 +56,14 @@ import org.dom4j.*;
import org.jitsi.videobridge.*; import org.jitsi.videobridge.*;
import org.jitsi.impl.neomedia.*; import org.jitsi.impl.neomedia.*;
import org.jitsi.impl.neomedia.format.*; import org.jitsi.impl.neomedia.format.*;
import org.jitsi.impl.neomedia.device.*;
import org.jitsi.service.neomedia.*; import org.jitsi.service.neomedia.*;
import org.jitsi.service.neomedia.device.*; import org.jitsi.service.neomedia.device.*;
import org.jitsi.service.neomedia.event.*; import org.jitsi.service.neomedia.event.*;
import org.jitsi.service.neomedia.format.*; import org.jitsi.service.neomedia.format.*;
import org.jitsi.service.libjitsi.*; import org.jitsi.service.libjitsi.*;
import org.jitsi.util.*;
/** /**
* Implements <tt>org.jivesoftware.openfire.container.Plugin</tt> to integrate * Implements <tt>org.jivesoftware.openfire.container.Plugin</tt> to integrate
...@@ -274,7 +280,7 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -274,7 +280,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
try try
{ {
String binaryPath = String binaryPath =
(new URL(ComponentImpl.class.getProtectionDomain() (new URL(Videobridge.class.getProtectionDomain()
.getCodeSource().getLocation(), ".")).openConnection() .getCodeSource().getLocation(), ".")).openConnection()
.getPermission().getName(); .getPermission().getName();
...@@ -559,12 +565,7 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -559,12 +565,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
Object object = colibriProvider.fromXML(element); Object object = colibriProvider.fromXML(element);
if (object instanceof ColibriCommand) { if (object instanceof RegisterCommand) {
ColibriCommand command = (ColibriCommand) object;
reply = handleColibriCommand(command, iq);
} else if (object instanceof RegisterCommand) {
registry.put(fromId, from); registry.put(fromId, from);
reply = IQ.createResultIQ(iq); reply = IQ.createResultIQ(iq);
...@@ -592,43 +593,6 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -592,43 +593,6 @@ public class PluginImpl implements Plugin, PropertyEventListener
{ {
return new IQHandlerInfo("colibri", RAYO_COLIBRI); return new IQHandlerInfo("colibri", RAYO_COLIBRI);
} }
/**
*
*
*/
private IQ handleColibriCommand(ColibriCommand command, IQ iq)
{
Log.info("ColibriIQHandler handleColibriCommand " + command);
IQ reply = IQ.createResultIQ(iq);
String vBridge = command.getVideobridge();
if (vBridge != null)
{
String focusAgentName = "jitsi.videobridge." + vBridge;
JID user = iq.getFrom();
Log.info("ColibriIQHandler handleColibriCommand bridge " + focusAgentName);
if (sessions.containsKey(focusAgentName))
{
FocusAgent focusAgent = sessions.get(focusAgentName);
if (focusAgent.isUser(user))
{
reply = focusAgent.handleColibriCommand(command, iq);
} else {
reply.setError(PacketError.Condition.item_not_found);
}
} else {
reply.setError(PacketError.Condition.not_allowed);
}
}
return reply;
}
/** /**
* *
* *
...@@ -852,6 +816,7 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -852,6 +816,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
private LocalClientSession session; private LocalClientSession session;
private String domainName = XMPPServer.getInstance().getServerInfo().getXMPPDomain(); private String domainName = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
private MediaStream mediaStream; private MediaStream mediaStream;
private DataSink mediaSink;
public ConcurrentHashMap<String, Participant> users = new ConcurrentHashMap<String, Participant>(); public ConcurrentHashMap<String, Participant> users = new ConcurrentHashMap<String, Participant>();
public ConcurrentHashMap<String, Participant> ids = new ConcurrentHashMap<String, Participant>(); public ConcurrentHashMap<String, Participant> ids = new ConcurrentHashMap<String, Participant>();
...@@ -1096,9 +1061,11 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -1096,9 +1061,11 @@ public class PluginImpl implements Plugin, PropertyEventListener
Log.info("removeColibriChannel " + count); Log.info("removeColibriChannel " + count);
} }
/** /**
*
* *
* *
*/ */
/*
public IQ handleColibriCommand(ColibriCommand command, IQ iq) public IQ handleColibriCommand(ColibriCommand command, IQ iq)
{ {
String focusJid = XMPPServer.getInstance().createJID(focusName, focusName).toString(); String focusJid = XMPPServer.getInstance().createJID(focusName, focusName).toString();
...@@ -1157,6 +1124,7 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -1157,6 +1124,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
} }
return reply; return reply;
} }
*/
/** /**
* *
* *
...@@ -1179,6 +1147,15 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -1179,6 +1147,15 @@ public class PluginImpl implements Plugin, PropertyEventListener
mediaStream.stop(); mediaStream.stop();
mediaStream = null; mediaStream = null;
} }
if (mediaSink != null)
{
try {
mediaSink.stop();
} catch (Exception e) {}
mediaSink = null;
}
} }
/** /**
* *
...@@ -1251,7 +1228,12 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -1251,7 +1228,12 @@ public class PluginImpl implements Plugin, PropertyEventListener
if (iq.getType() == IQ.Type.result) if (iq.getType() == IQ.Type.result)
{ {
Element conference = iq.getChildElement().createCopy(); Element conference = iq.getChildElement().createCopy();
focusId = conference.attributeValue("id");
if (focusId == null)
{
focusId = conference.attributeValue("id");
}
String id = packet.getID(); String id = packet.getID();
if (ids.containsKey(id)) if (ids.containsKey(id))
...@@ -1283,7 +1265,7 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -1283,7 +1265,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
Element root = iq.getChildElement(); Element root = iq.getChildElement();
Element conference = null; Element conference = null;
if (user.toString().equals("jitsi-videobridge." + domainName)) // SSRC notification from videobridge, ignore if (user.toString().equals("jitsi-videobridge." + domainName)) // SSRC notification from videobridge, brodcast, create recorder
{ {
conference = root.createCopy(); // rayo from participant conference = root.createCopy(); // rayo from participant
...@@ -1292,6 +1274,30 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -1292,6 +1274,30 @@ public class PluginImpl implements Plugin, PropertyEventListener
if (channels.containsKey(channelId)) if (channels.containsKey(channelId))
broadcastSSRC(channels.get(channelId)); broadcastSSRC(channels.get(channelId));
if (mediaSink == null /*&& count > 1*/) // recording not working, causing exception
{
try {
/*
String focusJid = XMPPServer.getInstance().createJID(focusName, focusName).toString();
Content content = getVideoBridge().getConference(focusId, focusJid).getOrCreateContent("audio");
AudioMixerMediaDevice mediaDevice = (AudioMixerMediaDevice) content.getMixer();
MediaDeviceSession deviceSession = mediaDevice.createSession();
deviceSession.setContentDescriptor(new ContentDescriptor(FileTypeDescriptor.MPEG_AUDIO));
deviceSession.setMute(false);
deviceSession.start(MediaDirection.SENDRECV);
DataSource outputDataSource = deviceSession.getCaptureDevice();
mediaSink = Manager.createDataSink(outputDataSource, new MediaLocator("file:recording-" + focusName + ".mp3"));
mediaSink.open();
mediaSink.start();
*/
} catch (Exception e) {
Log.error("Error creating recording file", e);
}
}
} else { } else {
conference = root.element("conference").createCopy(); // rayo from participant conference = root.element("conference").createCopy(); // rayo from participant
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment