/** * Sets the values of the properties of a specific <tt>ColibriConferenceIQ</tt> to the values of * the respective properties of this instance. Thus, the specified <tt>iq</tt> may be thought of * as a description of this instance. * * <p><b>Note</b>: The copying of the values is deep i.e. the <tt>Contents</tt>s of this instance * are described in the specified <tt>iq</tt>. * * @param iq the <tt>ColibriConferenceIQ</tt> to set the values of the properties of this instance * on */ public void describeDeep(ColibriConferenceIQ iq) { describeShallow(iq); if (isRecording()) { ColibriConferenceIQ.Recording recordingIQ = new ColibriConferenceIQ.Recording(State.ON.toString()); recordingIQ.setDirectory(getRecordingDirectory()); iq.setRecording(recordingIQ); } for (Content content : getContents()) { ColibriConferenceIQ.Content contentIQ = iq.getOrCreateContent(content.getName()); for (Channel channel : content.getChannels()) { if (channel instanceof SctpConnection) { ColibriConferenceIQ.SctpConnection sctpConnectionIQ = new ColibriConferenceIQ.SctpConnection(); channel.describe(sctpConnectionIQ); contentIQ.addSctpConnection(sctpConnectionIQ); } else { ColibriConferenceIQ.Channel channelIQ = new ColibriConferenceIQ.Channel(); channel.describe(channelIQ); contentIQ.addChannel(channelIQ); } } } }
/** * Processes channels allocation response from the JVB and stores info about new channels in * {@link #conferenceState}. * * @param allocateResponse the Colibri IQ that describes JVB response to allocate request. */ public void processChannelAllocResp(ColibriConferenceIQ allocateResponse) { String conferenceResponseID = allocateResponse.getID(); String colibriID = conferenceState.getID(); if (colibriID == null) conferenceState.setID(conferenceResponseID); else if (!colibriID.equals(conferenceResponseID)) throw new IllegalStateException("conference.id"); /* * XXX We must remember the JID of the Jitsi Videobridge because * (1) we do not want to re-discover it in every method * invocation on this Call instance and (2) we want to use one * and the same for all CallPeers within this Call instance. */ conferenceState.setFrom(allocateResponse.getFrom()); for (ColibriConferenceIQ.Content contentResponse : allocateResponse.getContents()) { String contentName = contentResponse.getName(); ColibriConferenceIQ.Content content = conferenceState.getOrCreateContent(contentName); // FIXME: we do not check if allocated channel does not clash // with any existing one for (ColibriConferenceIQ.Channel channelResponse : contentResponse.getChannels()) { content.addChannel(channelResponse); } for (ColibriConferenceIQ.SctpConnection sctpConnResponse : contentResponse.getSctpConnections()) { content.addSctpConnection(sctpConnResponse); } } for (ColibriConferenceIQ.ChannelBundle bundle : allocateResponse.getChannelBundles()) { conferenceState.addChannelBundle(bundle); } }
/** * Utility method for extracting info about channels allocated from JVB response. FIXME: this * might not work as expected when channels for multiple peers with single query were allocated. * * @param conferenceResponse JVB response to allocate channels request. * @param peerContents list of peer media contents that has to be matched with allocated channels. * @return the Colibri IQ that describes allocated channels. */ public static ColibriConferenceIQ getResponseContents( ColibriConferenceIQ conferenceResponse, List<ContentPacketExtension> peerContents) { ColibriConferenceIQ conferenceResult = new ColibriConferenceIQ(); conferenceResult.setFrom(conferenceResponse.getFrom()); conferenceResult.setID(conferenceResponse.getID()); // FIXME: we support single bundle for all channels String bundleId = null; for (ContentPacketExtension content : peerContents) { MediaType mediaType = JingleUtils.getMediaType(content); ColibriConferenceIQ.Content contentResponse = conferenceResponse.getContent(mediaType.toString()); if (contentResponse != null) { String contentName = contentResponse.getName(); ColibriConferenceIQ.Content contentResult = new ColibriConferenceIQ.Content(contentName); conferenceResult.addContent(contentResult); for (ColibriConferenceIQ.Channel channelResponse : contentResponse.getChannels()) { contentResult.addChannel(channelResponse); bundleId = readChannelBundle(channelResponse, bundleId); } for (ColibriConferenceIQ.SctpConnection sctpConnResponse : contentResponse.getSctpConnections()) { contentResult.addSctpConnection(sctpConnResponse); bundleId = readChannelBundle(sctpConnResponse, bundleId); } } } // Copy only peer's bundle(JVB returns all bundles) if (bundleId != null) { for (ColibriConferenceIQ.ChannelBundle bundle : conferenceResponse.getChannelBundles()) { if (bundleId.equals(bundle.getId())) { conferenceResult.addChannelBundle(bundle); break; } } } return conferenceResult; }
/** * Adds the channel-bundles of this <tt>Conference</tt> as * <tt>ColibriConferenceIQ.ChannelBundle</tt> instances in <tt>iq</tt>. * * @param iq the <tt>ColibriConferenceIQ</tt> in which to describe. */ void describeChannelBundles(ColibriConferenceIQ iq) { synchronized (transportManagers) { for (Map.Entry<String, IceUdpTransportManager> entry : transportManagers.entrySet()) { ColibriConferenceIQ.ChannelBundle responseBundleIQ = new ColibriConferenceIQ.ChannelBundle(entry.getKey()); entry.getValue().describe(responseBundleIQ); iq.addChannelBundle(responseBundleIQ); } } }
/** * Notifies this instance that a specific <tt>ColibriConferenceIQ</tt> has been received. * * @param conferenceIQ the <tt>ColibriConferenceIQ</tt> which has been received */ private void processColibriConferenceIQ(ColibriConferenceIQ conferenceIQ) { /* * The application is not a Jitsi Videobridge server, it is a client. * Consequently, the specified ColibriConferenceIQ is sent to it in * relation to the part of the application's functionality which makes * requests to a Jitsi Videobridge server i.e. CallJabberImpl. * * Additionally, the method processColibriConferenceIQ is presently tasked * with processing ColibriConferenceIQ requests only. They are SET IQs * sent by the Jitsi Videobridge server to notify the application about * updates in the states of (colibri) conferences organized by the * application. */ if (IQ.Type.SET.equals(conferenceIQ.getType()) && conferenceIQ.getID() != null) { OperationSetBasicTelephony<?> basicTelephony = protocolProvider.getOperationSet(OperationSetBasicTelephony.class); if (basicTelephony != null) { Iterator<? extends Call> i = basicTelephony.getActiveCalls(); while (i.hasNext()) { Call call = i.next(); if (call instanceof CallJabberImpl) { CallJabberImpl callJabberImpl = (CallJabberImpl) call; MediaAwareCallConference conference = callJabberImpl.getConference(); if ((conference != null) && conference.isJitsiVideobridge()) { /* * TODO We may want to disallow rogue CallJabberImpl * instances which may throw an exception to prevent * the conferenceIQ from reaching the CallJabberImpl * instance which it was meant for. */ if (callJabberImpl.processColibriConferenceIQ(conferenceIQ)) break; } } } } } }
/** * Sets the values of the properties of a specific <tt>ColibriConferenceIQ</tt> to the values of * the respective properties of this instance. Thus, the specified <tt>iq</tt> may be thought of * as a description of this instance. * * <p><b>Note</b>: The copying of the values is shallow i.e. the <tt>Content</tt>s of this * instance are not described in the specified <tt>iq</tt>. * * @param iq the <tt>ColibriConferenceIQ</tt> to set the values of the properties of this instance * on */ public void describeShallow(ColibriConferenceIQ iq) { iq.setID(getID()); iq.setName(getName()); }
private void handleColibriIq(ColibriConferenceIQ colibriIQ) { ColibriConferenceIQ.Recording recording = colibriIQ.getRecording(); String from = colibriIQ.getFrom(); JitsiMeetConference conference = getConferenceForMucJid(colibriIQ.getFrom()); if (conference == null) { logger.debug("Room not found for JID: " + from); return; } JitsiMeetRecording recordingHandler = conference.getRecording(); if (recordingHandler == null) { logger.error("JitsiMeetRecording is null for iq: " + colibriIQ.toXML()); // Internal server error smackXmpp .getXmppConnection() .sendPacket( IQ.createErrorResponse( colibriIQ, new XMPPError(XMPPError.Condition.interna_server_error))); return; } State recordingState = recordingHandler.modifyRecordingState( colibriIQ.getFrom(), recording.getToken(), recording.getState(), recording.getDirectory(), colibriIQ.getTo()); ColibriConferenceIQ response = new ColibriConferenceIQ(); response.setType(IQ.Type.RESULT); response.setPacketID(colibriIQ.getPacketID()); response.setTo(colibriIQ.getFrom()); response.setFrom(colibriIQ.getTo()); response.setName(colibriIQ.getName()); response.setRecording(new ColibriConferenceIQ.Recording(recordingState)); smackXmpp.getXmppConnection().sendPacket(response); }