1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2025-09-12 02:29:38 +02:00

Normalize newlines to '\n'

Change all \r\n into unix style newlines. Add missing newlines at the
end of a file and activate the newline checkstyle module, that enforces
'\n' as newline and a newline at the end of every file.
This commit is contained in:
Florian Schmaus 2014-02-17 23:58:40 +01:00
parent 1e57f1c659
commit d069e1be64
364 changed files with 50349 additions and 50346 deletions

View file

@ -64,4 +64,4 @@ import org.jivesoftware.smackx.packet.JingleError;
public JingleError getError() {
return error;
}
}
}

View file

@ -595,4 +595,4 @@ public class JingleManager implements JingleSessionListener {
}
return null;
}
}
}

View file

@ -1,31 +1,31 @@
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
import org.jivesoftware.smackx.jingle.JingleSession;
/**
* Inteface used to dispatch a event when a Jingle session is created.
*
* @author Thiago Camargo
*/
public interface CreatedJingleSessionListener {
public void sessionCreated(JingleSession jingleSession);
}
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
import org.jivesoftware.smackx.jingle.JingleSession;
/**
* Inteface used to dispatch a event when a Jingle session is created.
*
* @author Thiago Camargo
*/
public interface CreatedJingleSessionListener {
public void sessionCreated(JingleSession jingleSession);
}

View file

@ -1,48 +1,48 @@
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
/**
* Interface for listening to jmf info events.
* @author Thiago Camargo
*/
public interface JingleMediaInfoListener extends JingleListener {
/**
* The other end is busy.
*/
public void mediaInfoBusy();
/**
* We are on hold.
*/
public void mediaInfoHold();
/**
* The jmf is muted.
*/
public void mediaInfoMute();
/**
* We are queued.
*/
public void mediaInfoQueued();
/**
* We are ringing.
*/
public void mediaInfoRinging();
}
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
/**
* Interface for listening to jmf info events.
* @author Thiago Camargo
*/
public interface JingleMediaInfoListener extends JingleListener {
/**
* The other end is busy.
*/
public void mediaInfoBusy();
/**
* We are on hold.
*/
public void mediaInfoHold();
/**
* The jmf is muted.
*/
public void mediaInfoMute();
/**
* We are queued.
*/
public void mediaInfoQueued();
/**
* We are ringing.
*/
public void mediaInfoRinging();
}

View file

@ -1,40 +1,40 @@
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
import org.jivesoftware.smackx.jingle.media.PayloadType;
/**
* Interface for listening to jmf events.
* @author Thiago Camargo
*/
public interface JingleMediaListener extends JingleListener {
/**
* Notification that the jmf has been negotiated and established.
*
* @param pt The payload type agreed.
*/
public void mediaEstablished(PayloadType pt);
/**
* Notification that a payload type must be cancelled
*
* @param cand The payload type that must be closed
*/
public void mediaClosed(PayloadType cand);
}
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
import org.jivesoftware.smackx.jingle.media.PayloadType;
/**
* Interface for listening to jmf events.
* @author Thiago Camargo
*/
public interface JingleMediaListener extends JingleListener {
/**
* Notification that the jmf has been negotiated and established.
*
* @param pt The payload type agreed.
*/
public void mediaEstablished(PayloadType pt);
/**
* Notification that a payload type must be cancelled
*
* @param cand The payload type that must be closed
*/
public void mediaClosed(PayloadType cand);
}

View file

@ -1,82 +1,82 @@
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* Interface for listening for session events.
* @author Thiago Camargo
*/
public interface JingleSessionListener extends JingleListener {
/**
* Notification that the session has been established. Arguments specify
* the payload type and transport to use.
*
* @param pt the Payload tyep to use
* @param remoteCandidate the remote candidate to use for connecting to the remote
* service.
* @param localCandidate the local candidate where we must listen for connections
* @param jingleSession Session that called the method
*/
public void sessionEstablished(PayloadType pt, TransportCandidate remoteCandidate,
TransportCandidate localCandidate, JingleSession jingleSession);
/**
* Notification that the session was declined.
*
* @param reason the reason (if any).
* @param jingleSession Session that called the method
*/
public void sessionDeclined(String reason, JingleSession jingleSession);
/**
* Notification that the session was redirected.
*
* @param redirection
* @param jingleSession session that called the method
*/
public void sessionRedirected(String redirection, JingleSession jingleSession);
/**
* Notification that the session was closed normally.
*
* @param reason the reason (if any).
* @param jingleSession Session that called the method
*/
public void sessionClosed(String reason, JingleSession jingleSession);
/**
* Notification that the session was closed due to an exception.
*
* @param e the exception.
* @param jingleSession session that called the method
*/
public void sessionClosedOnError(XMPPException e, JingleSession jingleSession);
/**
* Notification that the Media has arrived for this session.
*
* @param jingleSession session that called the method
* @param participant description of the participant
*/
public void sessionMediaReceived(JingleSession jingleSession, String participant);
}
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* Interface for listening for session events.
* @author Thiago Camargo
*/
public interface JingleSessionListener extends JingleListener {
/**
* Notification that the session has been established. Arguments specify
* the payload type and transport to use.
*
* @param pt the Payload tyep to use
* @param remoteCandidate the remote candidate to use for connecting to the remote
* service.
* @param localCandidate the local candidate where we must listen for connections
* @param jingleSession Session that called the method
*/
public void sessionEstablished(PayloadType pt, TransportCandidate remoteCandidate,
TransportCandidate localCandidate, JingleSession jingleSession);
/**
* Notification that the session was declined.
*
* @param reason the reason (if any).
* @param jingleSession Session that called the method
*/
public void sessionDeclined(String reason, JingleSession jingleSession);
/**
* Notification that the session was redirected.
*
* @param redirection
* @param jingleSession session that called the method
*/
public void sessionRedirected(String redirection, JingleSession jingleSession);
/**
* Notification that the session was closed normally.
*
* @param reason the reason (if any).
* @param jingleSession Session that called the method
*/
public void sessionClosed(String reason, JingleSession jingleSession);
/**
* Notification that the session was closed due to an exception.
*
* @param e the exception.
* @param jingleSession session that called the method
*/
public void sessionClosedOnError(XMPPException e, JingleSession jingleSession);
/**
* Notification that the Media has arrived for this session.
*
* @param jingleSession session that called the method
* @param participant description of the participant
*/
public void sessionMediaReceived(JingleSession jingleSession, String participant);
}

View file

@ -1,33 +1,33 @@
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
import org.jivesoftware.smackx.jingle.JingleSessionRequest;
/**
* Interface to listener Jingle session requests.
*
* @author Alvaro Saurin
*/
public interface JingleSessionRequestListener extends JingleListener {
/**
* A request to start a session has been recieved from another user.
*
* @param request The request from the other user.
*/
public void sessionRequested(JingleSessionRequest request);
}
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
import org.jivesoftware.smackx.jingle.JingleSessionRequest;
/**
* Interface to listener Jingle session requests.
*
* @author Alvaro Saurin
*/
public interface JingleSessionRequestListener extends JingleListener {
/**
* A request to start a session has been recieved from another user.
*
* @param request The request from the other user.
*/
public void sessionRequested(JingleSessionRequest request);
}

View file

@ -1,55 +1,55 @@
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* Interface for listening to transport events.
*
* @author Thiago Camargo
*/
public interface JingleTransportListener extends JingleListener {
/**
* Notification that the transport has been established.
*
* @param local The transport candidate that has been used for listening
* in the local machine
* @param remote The transport candidate that has been used for
* transmitting to the remote machine
*/
public void transportEstablished(TransportCandidate local,
TransportCandidate remote);
/**
* Notification that a transport must be cancelled.
*
* @param cand The transport candidate that must be cancelled. A value
* of "null" means all the transports for this session.
*/
public void transportClosed(TransportCandidate cand);
/**
* Notification that the transport was closed due to an exception.
*
* @param e the exception.
*/
public void transportClosedOnError(XMPPException e);
}
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.listeners;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* Interface for listening to transport events.
*
* @author Thiago Camargo
*/
public interface JingleTransportListener extends JingleListener {
/**
* Notification that the transport has been established.
*
* @param local The transport candidate that has been used for listening
* in the local machine
* @param remote The transport candidate that has been used for
* transmitting to the remote machine
*/
public void transportEstablished(TransportCandidate local,
TransportCandidate remote);
/**
* Notification that a transport must be cancelled.
*
* @param cand The transport candidate that must be cancelled. A value
* of "null" means all the transports for this session.
*/
public void transportClosed(TransportCandidate cand);
/**
* Notification that the transport was closed due to an exception.
*
* @param e the exception.
*/
public void transportClosedOnError(XMPPException e);
}

View file

@ -1,85 +1,85 @@
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.media;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
import java.util.List;
/**
* This class provides necessary Jingle Session jmf methods and behavior.
* <p/>
* The goal of this class is to provide a flexible way to make JingleManager control jmf streaming APIs without implement them.
* For instance you can implement a file transfer using java sockets or a VOIP Media Manager using JMF.
* You can implement many JingleMediaManager according to you necessity.
*
* @author Thiago Camargo
*/
public abstract class JingleMediaManager {
public static final String MEDIA_NAME = "JingleMediaManager";
// Each media manager must keep track of the transport manager that it uses.
private JingleTransportManager transportManager;
public JingleMediaManager(JingleTransportManager transportManager) {
this.transportManager = transportManager;
}
/**
* Return The transport manager that goes with this media manager.
*/
public JingleTransportManager getTransportManager() {
return transportManager;
}
/**
* Return all supported Payloads for this Manager
*
* @return The Payload List
*/
public abstract List<PayloadType> getPayloads();
/**
* Returns the Preferred PayloadType of the Media Manager
*
* @return The PayloadType
*/
public PayloadType getPreferredPayloadType() {
return getPayloads().size() > 0 ? getPayloads().get(0) : null;
}
/**
* Create a Media Session Implementation
*
* @param payloadType
* @param remote
* @param local
* @return
*/
public abstract JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote,
final TransportCandidate local, JingleSession jingleSession);
// This is to set the attributes of the <content> element of the Jingle packet.
public String getName() {
return MEDIA_NAME;
}
}
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.media;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
import java.util.List;
/**
* This class provides necessary Jingle Session jmf methods and behavior.
* <p/>
* The goal of this class is to provide a flexible way to make JingleManager control jmf streaming APIs without implement them.
* For instance you can implement a file transfer using java sockets or a VOIP Media Manager using JMF.
* You can implement many JingleMediaManager according to you necessity.
*
* @author Thiago Camargo
*/
public abstract class JingleMediaManager {
public static final String MEDIA_NAME = "JingleMediaManager";
// Each media manager must keep track of the transport manager that it uses.
private JingleTransportManager transportManager;
public JingleMediaManager(JingleTransportManager transportManager) {
this.transportManager = transportManager;
}
/**
* Return The transport manager that goes with this media manager.
*/
public JingleTransportManager getTransportManager() {
return transportManager;
}
/**
* Return all supported Payloads for this Manager
*
* @return The Payload List
*/
public abstract List<PayloadType> getPayloads();
/**
* Returns the Preferred PayloadType of the Media Manager
*
* @return The PayloadType
*/
public PayloadType getPreferredPayloadType() {
return getPayloads().size() > 0 ? getPayloads().get(0) : null;
}
/**
* Create a Media Session Implementation
*
* @param payloadType
* @param remote
* @param local
* @return
*/
public abstract JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote,
final TransportCandidate local, JingleSession jingleSession);
// This is to set the attributes of the <content> element of the Jingle packet.
public String getName() {
return MEDIA_NAME;
}
}

View file

@ -1,188 +1,188 @@
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.media;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
import java.util.ArrayList;
import java.util.List;
/**
* Public Abstract Class provides a clear interface between Media Session and Jingle API.
* <p/>
* When a Jingle Session is fully stablished, we will have a Payload Type and two transport candidates defined for it.
* Smack Jingle API don't implement Media Transmit and Receive methods.
* But provides an interface to let the user implements it using another API. For instance: JMF.
* <p/>
* <i>The Class that implements this one, must have the support to transmit and receive the jmf.</i>
* <i>This interface let the user choose his own jmf API.</i>
*
* @author Thiago Camargo
*/
public abstract class JingleMediaSession {
// Payload Type of the Session
private PayloadType payloadType;
// Local Transport details
private TransportCandidate local;
// Remote Transport details
private TransportCandidate remote;
// Media Locator
private String mediaLocator;
// Media Received Listener
private List<MediaReceivedListener> mediaReceivedListeners = new ArrayList<MediaReceivedListener>();
// Jingle Session
private JingleSession jingleSession;
/**
* Creates a new JingleMediaSession Instance to handle Media methods.
*
* @param payloadType Payload Type of the transmittion
* @param remote Remote accepted Transport Candidate
* @param local Local accepted Transport Candidate
* @param mediaLocator Media Locator of the capture device
*/
public JingleMediaSession(PayloadType payloadType, TransportCandidate remote,
TransportCandidate local, String mediaLocator, JingleSession jingleSession) {
this.local = local;
this.remote = remote;
this.payloadType = payloadType;
this.mediaLocator = mediaLocator;
this.jingleSession = jingleSession;
}
/**
* Returns the PayloadType of the Media Session
*
* @return
*/
public PayloadType getPayloadType() {
return payloadType;
}
/**
* Returns the Media Session local Candidate
*
* @return
*/
public TransportCandidate getLocal() {
return local;
}
/**
* Returns the Media Session remote Candidate
*
* @return
*/
public TransportCandidate getRemote() {
return remote;
}
/**
* Return the media locator or null if not defined
*
* @return media locator
*/
public String getMediaLocator() {
return mediaLocator;
}
/**
* Set the media locator
*
* @param mediaLocator media locator or null to use default
*/
public void setMediaLocator(String mediaLocator) {
this.mediaLocator = mediaLocator;
}
/**
* Adds a Media Received Listener
*
* @param mediaReceivedListener
*/
public void addMediaReceivedListener(MediaReceivedListener mediaReceivedListener) {
mediaReceivedListeners.add(mediaReceivedListener);
}
/**
* Removes a Media Received Listener
*
* @param mediaReceivedListener
*/
public void removeMediaReceivedListener(MediaReceivedListener mediaReceivedListener) {
mediaReceivedListeners.remove(mediaReceivedListener);
}
/**
* Removes all Media Received Listeners
*/
public void removeAllMediaReceivedListener() {
mediaReceivedListeners.clear();
}
/**
* Initialize the RTP Channel preparing to transmit and receive.
*/
public abstract void initialize();
/**
* Starts a RTP / UDP / TCP Transmission to the remote Candidate
*/
public abstract void startTrasmit();
/**
* Starts a RTP / UDP / TCP Receiver from the remote Candidate to local Candidate
*/
public abstract void startReceive();
/**
* Set transmit activity. If the active is true, the instance should trasmit.
* If it is set to false, the instance should pause transmit.
*
* @param active
*/
public abstract void setTrasmit(boolean active);
/**
* Stops a RTP / UDP / TCP Transmission to the remote Candidate
*/
public abstract void stopTrasmit();
/**
* Stops a RTP / UDP / TCP Receiver from the remote Candidate to local Candidate
*/
public abstract void stopReceive();
/**
* Called when new Media is received.
*/
public void mediaReceived(String participant) {
for (MediaReceivedListener mediaReceivedListener : mediaReceivedListeners) {
mediaReceivedListener.mediaReceived(participant);
}
}
/**
* Gets associated JingleSession
* @return associated JingleSession
*/
public JingleSession getJingleSession() {
return jingleSession;
}
}
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.media;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
import java.util.ArrayList;
import java.util.List;
/**
* Public Abstract Class provides a clear interface between Media Session and Jingle API.
* <p/>
* When a Jingle Session is fully stablished, we will have a Payload Type and two transport candidates defined for it.
* Smack Jingle API don't implement Media Transmit and Receive methods.
* But provides an interface to let the user implements it using another API. For instance: JMF.
* <p/>
* <i>The Class that implements this one, must have the support to transmit and receive the jmf.</i>
* <i>This interface let the user choose his own jmf API.</i>
*
* @author Thiago Camargo
*/
public abstract class JingleMediaSession {
// Payload Type of the Session
private PayloadType payloadType;
// Local Transport details
private TransportCandidate local;
// Remote Transport details
private TransportCandidate remote;
// Media Locator
private String mediaLocator;
// Media Received Listener
private List<MediaReceivedListener> mediaReceivedListeners = new ArrayList<MediaReceivedListener>();
// Jingle Session
private JingleSession jingleSession;
/**
* Creates a new JingleMediaSession Instance to handle Media methods.
*
* @param payloadType Payload Type of the transmittion
* @param remote Remote accepted Transport Candidate
* @param local Local accepted Transport Candidate
* @param mediaLocator Media Locator of the capture device
*/
public JingleMediaSession(PayloadType payloadType, TransportCandidate remote,
TransportCandidate local, String mediaLocator, JingleSession jingleSession) {
this.local = local;
this.remote = remote;
this.payloadType = payloadType;
this.mediaLocator = mediaLocator;
this.jingleSession = jingleSession;
}
/**
* Returns the PayloadType of the Media Session
*
* @return
*/
public PayloadType getPayloadType() {
return payloadType;
}
/**
* Returns the Media Session local Candidate
*
* @return
*/
public TransportCandidate getLocal() {
return local;
}
/**
* Returns the Media Session remote Candidate
*
* @return
*/
public TransportCandidate getRemote() {
return remote;
}
/**
* Return the media locator or null if not defined
*
* @return media locator
*/
public String getMediaLocator() {
return mediaLocator;
}
/**
* Set the media locator
*
* @param mediaLocator media locator or null to use default
*/
public void setMediaLocator(String mediaLocator) {
this.mediaLocator = mediaLocator;
}
/**
* Adds a Media Received Listener
*
* @param mediaReceivedListener
*/
public void addMediaReceivedListener(MediaReceivedListener mediaReceivedListener) {
mediaReceivedListeners.add(mediaReceivedListener);
}
/**
* Removes a Media Received Listener
*
* @param mediaReceivedListener
*/
public void removeMediaReceivedListener(MediaReceivedListener mediaReceivedListener) {
mediaReceivedListeners.remove(mediaReceivedListener);
}
/**
* Removes all Media Received Listeners
*/
public void removeAllMediaReceivedListener() {
mediaReceivedListeners.clear();
}
/**
* Initialize the RTP Channel preparing to transmit and receive.
*/
public abstract void initialize();
/**
* Starts a RTP / UDP / TCP Transmission to the remote Candidate
*/
public abstract void startTrasmit();
/**
* Starts a RTP / UDP / TCP Receiver from the remote Candidate to local Candidate
*/
public abstract void startReceive();
/**
* Set transmit activity. If the active is true, the instance should trasmit.
* If it is set to false, the instance should pause transmit.
*
* @param active
*/
public abstract void setTrasmit(boolean active);
/**
* Stops a RTP / UDP / TCP Transmission to the remote Candidate
*/
public abstract void stopTrasmit();
/**
* Stops a RTP / UDP / TCP Receiver from the remote Candidate to local Candidate
*/
public abstract void stopReceive();
/**
* Called when new Media is received.
*/
public void mediaReceived(String participant) {
for (MediaReceivedListener mediaReceivedListener : mediaReceivedListeners) {
mediaReceivedListener.mediaReceived(participant);
}
}
/**
* Gets associated JingleSession
* @return associated JingleSession
*/
public JingleSession getJingleSession() {
return jingleSession;
}
}

View file

@ -362,4 +362,4 @@ public class PayloadType {
return true;
}
}
}
}

View file

@ -12,287 +12,287 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.Toolkit;
import java.util.Vector;
import javax.media.Format;
import javax.media.PlugInManager;
import javax.media.Renderer;
import javax.media.format.AudioFormat;
import org.jivesoftware.smackx.jingle.SmackLogger;
import com.sun.media.ExclusiveUse;
import com.sun.media.util.Registry;
public class JMFInit extends Frame implements Runnable {
private static final long serialVersionUID = 6476412003260641680L;
private static final SmackLogger LOGGER = SmackLogger.getLogger(JMFInit.class);
private String tempDir = "/tmp";
private boolean done = false;
private String userHome;
private boolean visible = false;
public JMFInit(String[] args, boolean visible) {
super("Initializing JMF...");
this.visible = visible;
Registry.set("secure.allowCaptureFromApplets", true);
Registry.set("secure.allowSaveFileFromApplets", true);
updateTemp(args);
try {
Registry.commit();
}
catch (Exception e) {
message("Failed to commit to JMFRegistry!");
}
Thread detectThread = new Thread(this);
detectThread.run();
/*
* int slept = 0; while (!done && slept < 60 * 1000 * 2) { try {
* Thread.currentThread().sleep(500); } catch (InterruptedException ie) { }
* slept += 500; }
*
* if (!done) { console.error("Detection is taking too long!
* Aborting!"); message("Detection is taking too long! Aborting!"); }
*
* try { Thread.currentThread().sleep(2000); } catch
* (InterruptedException ie) { }
*/
}
public void run() {
detectDirectAudio();
detectS8DirectAudio();
detectCaptureDevices();
done = true;
}
private void updateTemp(String[] args) {
if (args != null && args.length > 0) {
tempDir = args[0];
message("Setting cache directory to " + tempDir);
Registry r = new Registry();
try {
r.set("secure.cacheDir", tempDir);
r.commit();
message("Updated registry");
}
catch (Exception e) {
message("Couldn't update registry!");
}
}
}
private void detectCaptureDevices() {
// check if JavaSound capture is available
message("Looking for Audio capturer");
Class<?> dsauto;
try {
dsauto = Class.forName("DirectSoundAuto");
dsauto.newInstance();
message("Finished detecting DirectSound capturer");
}
catch (ThreadDeath td) {
throw td;
}
catch (Throwable t) {
//Do nothing
}
Class<?> jsauto;
try {
jsauto = Class.forName("JavaSoundAuto");
jsauto.newInstance();
message("Finished detecting javasound capturer");
}
catch (ThreadDeath td) {
throw td;
}
catch (Throwable t) {
message("JavaSound capturer detection failed!");
}
/*
// Check if VFWAuto or SunVideoAuto is available
message("Looking for video capture devices");
Class auto = null;
Class autoPlus = null;
try {
auto = Class.forName("VFWAuto");
}
catch (Exception e) {
}
if (auto == null) {
try {
auto = Class.forName("SunVideoAuto");
}
catch (Exception ee) {
}
try {
autoPlus = Class.forName("SunVideoPlusAuto");
}
catch (Exception ee) {
}
}
if (auto == null) {
try {
auto = Class.forName("V4LAuto");
}
catch (Exception ee) {
}
}
try {
Object instance = auto.newInstance();
if (autoPlus != null) {
Object instancePlus = autoPlus.newInstance();
}
message("Finished detecting video capture devices");
}
catch (ThreadDeath td) {
throw td;
}
catch (Throwable t) {
message("Capture device detection failed!");
}
*/
}
private void detectDirectAudio() {
Class<?> cls;
int plType = PlugInManager.RENDERER;
String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
try {
// Check if this is the Windows Performance Pack - hack
cls = Class.forName("VFWAuto");
// Check if DS capture is supported, otherwise fail DS renderer
// since NT doesn't have capture
cls = Class.forName("com.sun.media.protocol.dsound.DSound");
// Find the renderer class and instantiate it.
cls = Class.forName(dar);
Renderer rend = (Renderer) cls.newInstance();
try {
// Set the format and open the device
AudioFormat af = new AudioFormat(AudioFormat.LINEAR, 44100, 16,
2);
rend.setInputFormat(af);
rend.open();
Format[] inputFormats = rend.getSupportedInputFormats();
// Register the device
PlugInManager.addPlugIn(dar, inputFormats, new Format[0],
plType);
// Move it to the top of the list
Vector<String> rendList = PlugInManager.getPlugInList(null, null,
plType);
int listSize = rendList.size();
if (rendList.elementAt(listSize - 1).equals(dar)) {
rendList.removeElementAt(listSize - 1);
rendList.insertElementAt(dar, 0);
PlugInManager.setPlugInList(rendList, plType);
PlugInManager.commit();
// Log.debug("registered");
}
rend.close();
}
catch (Throwable t) {
// Log.debug("Error " + t);
}
}
catch (Throwable tt) {
//Do nothing
}
}
private void detectS8DirectAudio() {
Class<?> cls;
int plType = PlugInManager.RENDERER;
String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
try {
// Check if this is the solaris Performance Pack - hack
cls = Class.forName("SunVideoAuto");
// Find the renderer class and instantiate it.
cls = Class.forName(dar);
Renderer rend = (Renderer) cls.newInstance();
if (rend instanceof ExclusiveUse
&& !((ExclusiveUse) rend).isExclusive()) {
// sol8+, DAR supports mixing
Vector<String> rendList = PlugInManager.getPlugInList(null, null,
plType);
int listSize = rendList.size();
boolean found = false;
String rname = null;
for (int i = 0; i < listSize; i++) {
rname = (String) (rendList.elementAt(i));
if (rname.equals(dar)) { // DAR is in the registry
found = true;
rendList.removeElementAt(i);
break;
}
}
if (found) {
rendList.insertElementAt(dar, 0);
PlugInManager.setPlugInList(rendList, plType);
PlugInManager.commit();
}
}
}
catch (Throwable tt) {
//Do nothing
}
}
private void message(String mesg) {
LOGGER.debug(mesg);
}
private void createGUI() {
TextArea textBox = new TextArea(5, 50);
add("Center", textBox);
textBox.setEditable(false);
addNotify();
pack();
int scrWidth = (int) Toolkit.getDefaultToolkit().getScreenSize()
.getWidth();
int scrHeight = (int) Toolkit.getDefaultToolkit().getScreenSize()
.getHeight();
setLocation((scrWidth - getWidth()) / 2, (scrHeight - getHeight()) / 2);
setVisible(visible);
}
public static void start(boolean visible) {
new JMFInit(null, visible);
}
}
package org.jivesoftware.smackx.jingle.mediaimpl;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.Toolkit;
import java.util.Vector;
import javax.media.Format;
import javax.media.PlugInManager;
import javax.media.Renderer;
import javax.media.format.AudioFormat;
import org.jivesoftware.smackx.jingle.SmackLogger;
import com.sun.media.ExclusiveUse;
import com.sun.media.util.Registry;
public class JMFInit extends Frame implements Runnable {
private static final long serialVersionUID = 6476412003260641680L;
private static final SmackLogger LOGGER = SmackLogger.getLogger(JMFInit.class);
private String tempDir = "/tmp";
private boolean done = false;
private String userHome;
private boolean visible = false;
public JMFInit(String[] args, boolean visible) {
super("Initializing JMF...");
this.visible = visible;
Registry.set("secure.allowCaptureFromApplets", true);
Registry.set("secure.allowSaveFileFromApplets", true);
updateTemp(args);
try {
Registry.commit();
}
catch (Exception e) {
message("Failed to commit to JMFRegistry!");
}
Thread detectThread = new Thread(this);
detectThread.run();
/*
* int slept = 0; while (!done && slept < 60 * 1000 * 2) { try {
* Thread.currentThread().sleep(500); } catch (InterruptedException ie) { }
* slept += 500; }
*
* if (!done) { console.error("Detection is taking too long!
* Aborting!"); message("Detection is taking too long! Aborting!"); }
*
* try { Thread.currentThread().sleep(2000); } catch
* (InterruptedException ie) { }
*/
}
public void run() {
detectDirectAudio();
detectS8DirectAudio();
detectCaptureDevices();
done = true;
}
private void updateTemp(String[] args) {
if (args != null && args.length > 0) {
tempDir = args[0];
message("Setting cache directory to " + tempDir);
Registry r = new Registry();
try {
r.set("secure.cacheDir", tempDir);
r.commit();
message("Updated registry");
}
catch (Exception e) {
message("Couldn't update registry!");
}
}
}
private void detectCaptureDevices() {
// check if JavaSound capture is available
message("Looking for Audio capturer");
Class<?> dsauto;
try {
dsauto = Class.forName("DirectSoundAuto");
dsauto.newInstance();
message("Finished detecting DirectSound capturer");
}
catch (ThreadDeath td) {
throw td;
}
catch (Throwable t) {
//Do nothing
}
Class<?> jsauto;
try {
jsauto = Class.forName("JavaSoundAuto");
jsauto.newInstance();
message("Finished detecting javasound capturer");
}
catch (ThreadDeath td) {
throw td;
}
catch (Throwable t) {
message("JavaSound capturer detection failed!");
}
/*
// Check if VFWAuto or SunVideoAuto is available
message("Looking for video capture devices");
Class auto = null;
Class autoPlus = null;
try {
auto = Class.forName("VFWAuto");
}
catch (Exception e) {
}
if (auto == null) {
try {
auto = Class.forName("SunVideoAuto");
}
catch (Exception ee) {
}
try {
autoPlus = Class.forName("SunVideoPlusAuto");
}
catch (Exception ee) {
}
}
if (auto == null) {
try {
auto = Class.forName("V4LAuto");
}
catch (Exception ee) {
}
}
try {
Object instance = auto.newInstance();
if (autoPlus != null) {
Object instancePlus = autoPlus.newInstance();
}
message("Finished detecting video capture devices");
}
catch (ThreadDeath td) {
throw td;
}
catch (Throwable t) {
message("Capture device detection failed!");
}
*/
}
private void detectDirectAudio() {
Class<?> cls;
int plType = PlugInManager.RENDERER;
String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
try {
// Check if this is the Windows Performance Pack - hack
cls = Class.forName("VFWAuto");
// Check if DS capture is supported, otherwise fail DS renderer
// since NT doesn't have capture
cls = Class.forName("com.sun.media.protocol.dsound.DSound");
// Find the renderer class and instantiate it.
cls = Class.forName(dar);
Renderer rend = (Renderer) cls.newInstance();
try {
// Set the format and open the device
AudioFormat af = new AudioFormat(AudioFormat.LINEAR, 44100, 16,
2);
rend.setInputFormat(af);
rend.open();
Format[] inputFormats = rend.getSupportedInputFormats();
// Register the device
PlugInManager.addPlugIn(dar, inputFormats, new Format[0],
plType);
// Move it to the top of the list
Vector<String> rendList = PlugInManager.getPlugInList(null, null,
plType);
int listSize = rendList.size();
if (rendList.elementAt(listSize - 1).equals(dar)) {
rendList.removeElementAt(listSize - 1);
rendList.insertElementAt(dar, 0);
PlugInManager.setPlugInList(rendList, plType);
PlugInManager.commit();
// Log.debug("registered");
}
rend.close();
}
catch (Throwable t) {
// Log.debug("Error " + t);
}
}
catch (Throwable tt) {
//Do nothing
}
}
private void detectS8DirectAudio() {
Class<?> cls;
int plType = PlugInManager.RENDERER;
String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
try {
// Check if this is the solaris Performance Pack - hack
cls = Class.forName("SunVideoAuto");
// Find the renderer class and instantiate it.
cls = Class.forName(dar);
Renderer rend = (Renderer) cls.newInstance();
if (rend instanceof ExclusiveUse
&& !((ExclusiveUse) rend).isExclusive()) {
// sol8+, DAR supports mixing
Vector<String> rendList = PlugInManager.getPlugInList(null, null,
plType);
int listSize = rendList.size();
boolean found = false;
String rname = null;
for (int i = 0; i < listSize; i++) {
rname = (String) (rendList.elementAt(i));
if (rname.equals(dar)) { // DAR is in the registry
found = true;
rendList.removeElementAt(i);
break;
}
}
if (found) {
rendList.insertElementAt(dar, 0);
PlugInManager.setPlugInList(rendList, plType);
PlugInManager.commit();
}
}
}
catch (Throwable tt) {
//Do nothing
}
}
private void message(String mesg) {
LOGGER.debug(mesg);
}
private void createGUI() {
TextArea textBox = new TextArea(5, 50);
add("Center", textBox);
textBox.setEditable(false);
addNotify();
pack();
int scrWidth = (int) Toolkit.getDefaultToolkit().getScreenSize()
.getWidth();
int scrHeight = (int) Toolkit.getDefaultToolkit().getScreenSize()
.getHeight();
setLocation((scrWidth - getWidth()) / 2, (scrHeight - getHeight()) / 2);
setVisible(visible);
}
public static void start(boolean visible) {
new JMFInit(null, visible);
}
}

View file

@ -1,176 +1,176 @@
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.demo;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleManager;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.JingleSessionRequest;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionRequestListener;
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
import org.jivesoftware.smackx.jingle.mediaimpl.jspeex.SpeexMediaManager;
import org.jivesoftware.smackx.jingle.mediaimpl.sshare.ScreenShareMediaManager;
import org.jivesoftware.smackx.jingle.nat.ICETransportManager;
import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
/**
* Jingle Demo Application. It register in a XMPP Server and let users place calls using a full JID and auto-receive calls.
* Parameters: Server User Pass.
*/
public class Demo extends JFrame {
private static final long serialVersionUID = -6584021277434403855L;
private JingleTransportManager transportManager = null;
private Connection xmppConnection = null;
private String server = null;
private String user = null;
private String pass = null;
private JingleManager jm = null;
private JingleSession incoming = null;
private JingleSession outgoing = null;
private JTextField jid;
public Demo(String server, String user, String pass) {
this.server = server;
this.user = user;
this.pass = pass;
if (user.equals("jeffw")) {
jid = new JTextField("eowyn" + "@" + server + "/Smack");
} else {
jid = new JTextField("jeffw" + "@" + server + "/Smack");
}
xmppConnection = new XMPPConnection(server);
try {
xmppConnection.connect();
xmppConnection.login(user, pass);
initialize();
}
catch (XMPPException e) {
e.printStackTrace();
}
}
public void initialize() {
ICETransportManager icetm0 = new ICETransportManager(xmppConnection, "10.47.47.53", 3478);
List<JingleMediaManager> mediaManagers = new ArrayList<JingleMediaManager>();
//mediaManagers.add(new JmfMediaManager(icetm0));
mediaManagers.add(new SpeexMediaManager(icetm0));
mediaManagers.add(new ScreenShareMediaManager(icetm0));
jm = new JingleManager(xmppConnection, mediaManagers);
jm.addCreationListener(icetm0);
jm.addJingleSessionRequestListener(new JingleSessionRequestListener() {
public void sessionRequested(JingleSessionRequest request) {
// if (incoming != null)
// return;
try {
// Accept the call
incoming = request.accept();
// Start the call
incoming.startIncoming();
}
catch (XMPPException e) {
e.printStackTrace();
}
}
});
createGUI();
}
public void createGUI() {
JPanel jPanel = new JPanel();
jPanel.add(jid);
jPanel.add(new JButton(new AbstractAction("Call") {
private static final long serialVersionUID = 4308448034795312815L;
public void actionPerformed(ActionEvent e) {
if (outgoing != null) return;
try {
outgoing = jm.createOutgoingJingleSession(jid.getText());
outgoing.startOutgoing();
}
catch (XMPPException e1) {
e1.printStackTrace();
}
}
}));
jPanel.add(new JButton(new AbstractAction("Hangup") {
private static final long serialVersionUID = -4508007389146723587L;
public void actionPerformed(ActionEvent e) {
if (outgoing != null)
try {
outgoing.terminate();
}
catch (XMPPException e1) {
e1.printStackTrace();
}
finally {
outgoing = null;
}
if (incoming != null)
try {
incoming.terminate();
}
catch (XMPPException e1) {
e1.printStackTrace();
}
finally {
incoming = null;
}
}
}));
this.add(jPanel);
}
public static void main(String args[]) {
Demo demo = null;
if (args.length > 2) {
demo = new Demo(args[0], args[1], args[2]);
demo.pack();
demo.setVisible(true);
demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
}
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.demo;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleManager;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.JingleSessionRequest;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionRequestListener;
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
import org.jivesoftware.smackx.jingle.mediaimpl.jspeex.SpeexMediaManager;
import org.jivesoftware.smackx.jingle.mediaimpl.sshare.ScreenShareMediaManager;
import org.jivesoftware.smackx.jingle.nat.ICETransportManager;
import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
/**
* Jingle Demo Application. It register in a XMPP Server and let users place calls using a full JID and auto-receive calls.
* Parameters: Server User Pass.
*/
public class Demo extends JFrame {
private static final long serialVersionUID = -6584021277434403855L;
private JingleTransportManager transportManager = null;
private Connection xmppConnection = null;
private String server = null;
private String user = null;
private String pass = null;
private JingleManager jm = null;
private JingleSession incoming = null;
private JingleSession outgoing = null;
private JTextField jid;
public Demo(String server, String user, String pass) {
this.server = server;
this.user = user;
this.pass = pass;
if (user.equals("jeffw")) {
jid = new JTextField("eowyn" + "@" + server + "/Smack");
} else {
jid = new JTextField("jeffw" + "@" + server + "/Smack");
}
xmppConnection = new XMPPConnection(server);
try {
xmppConnection.connect();
xmppConnection.login(user, pass);
initialize();
}
catch (XMPPException e) {
e.printStackTrace();
}
}
public void initialize() {
ICETransportManager icetm0 = new ICETransportManager(xmppConnection, "10.47.47.53", 3478);
List<JingleMediaManager> mediaManagers = new ArrayList<JingleMediaManager>();
//mediaManagers.add(new JmfMediaManager(icetm0));
mediaManagers.add(new SpeexMediaManager(icetm0));
mediaManagers.add(new ScreenShareMediaManager(icetm0));
jm = new JingleManager(xmppConnection, mediaManagers);
jm.addCreationListener(icetm0);
jm.addJingleSessionRequestListener(new JingleSessionRequestListener() {
public void sessionRequested(JingleSessionRequest request) {
// if (incoming != null)
// return;
try {
// Accept the call
incoming = request.accept();
// Start the call
incoming.startIncoming();
}
catch (XMPPException e) {
e.printStackTrace();
}
}
});
createGUI();
}
public void createGUI() {
JPanel jPanel = new JPanel();
jPanel.add(jid);
jPanel.add(new JButton(new AbstractAction("Call") {
private static final long serialVersionUID = 4308448034795312815L;
public void actionPerformed(ActionEvent e) {
if (outgoing != null) return;
try {
outgoing = jm.createOutgoingJingleSession(jid.getText());
outgoing.startOutgoing();
}
catch (XMPPException e1) {
e1.printStackTrace();
}
}
}));
jPanel.add(new JButton(new AbstractAction("Hangup") {
private static final long serialVersionUID = -4508007389146723587L;
public void actionPerformed(ActionEvent e) {
if (outgoing != null)
try {
outgoing.terminate();
}
catch (XMPPException e1) {
e1.printStackTrace();
}
finally {
outgoing = null;
}
if (incoming != null)
try {
incoming.terminate();
}
catch (XMPPException e1) {
e1.printStackTrace();
}
finally {
incoming = null;
}
}
}));
this.add(jPanel);
}
public static void main(String args[]) {
Demo demo = null;
if (args.length > 2) {
demo = new Demo(args[0], args[1], args[2]);
demo.pack();
demo.setVisible(true);
demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
}

View file

@ -1,52 +1,52 @@
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import javax.media.format.AudioFormat;
/**
* Audio Format Utils.
*
* @author Thiago Camargo
*/
public class AudioFormatUtils {
/**
* Return a JMF AudioFormat for a given Jingle Payload type.
* Return null if the payload is not supported by this jmf API.
*
* @param payloadtype payloadtype
* @return correspondent audioType
*/
public static AudioFormat getAudioFormat(PayloadType payloadtype) {
switch (payloadtype.getId()) {
case 0:
return new AudioFormat(AudioFormat.ULAW_RTP);
case 3:
return new AudioFormat(AudioFormat.GSM_RTP);
case 4:
return new AudioFormat(AudioFormat.G723_RTP);
default:
return null;
}
}
}
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import javax.media.format.AudioFormat;
/**
* Audio Format Utils.
*
* @author Thiago Camargo
*/
public class AudioFormatUtils {
/**
* Return a JMF AudioFormat for a given Jingle Payload type.
* Return null if the payload is not supported by this jmf API.
*
* @param payloadtype payloadtype
* @return correspondent audioType
*/
public static AudioFormat getAudioFormat(PayloadType payloadtype) {
switch (payloadtype.getId()) {
case 0:
return new AudioFormat(AudioFormat.ULAW_RTP);
case 3:
return new AudioFormat(AudioFormat.GSM_RTP);
case 4:
return new AudioFormat(AudioFormat.G723_RTP);
default:
return null;
}
}
}

View file

@ -1,162 +1,162 @@
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
import java.io.IOException;
import java.net.ServerSocket;
import javax.media.MediaLocator;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* This Class implements a complete JingleMediaSession.
* It sould be used to transmit and receive audio captured from the Mic.
* This Class should be automaticly controlled by JingleSession.
* But you could also use in any VOIP application.
* For better NAT Traversal support this implementation don't support only receive or only transmit.
* To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
*
* @author Thiago Camargo
*/
public class AudioMediaSession extends JingleMediaSession {
private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class);
private AudioChannel audioChannel;
/**
* Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates
*
* @param payloadType Payload of the jmf
* @param remote the remote information. The candidate that the jmf will be sent to.
* @param local the local information. The candidate that will receive the jmf
* @param locator media locator
*/
public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
final TransportCandidate local, String locator, JingleSession jingleSession) {
super(payloadType, remote, local, locator==null?"dsound://":locator,jingleSession);
initialize();
}
/**
* Initialize the Audio Channel to make it able to send and receive audio
*/
public void initialize() {
String ip;
String localIp;
int localPort;
int remotePort;
if (this.getLocal().getSymmetric() != null) {
ip = this.getLocal().getIp();
localIp = this.getLocal().getLocalIp();
localPort = getFreePort();
remotePort = this.getLocal().getSymmetric().getPort();
LOGGER.debug(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort);
}
else {
ip = this.getRemote().getIp();
localIp = this.getLocal().getLocalIp();
localPort = this.getLocal().getPort();
remotePort = this.getRemote().getPort();
}
audioChannel = new AudioChannel(new MediaLocator(this.getMediaLocator()), localIp, ip, localPort, remotePort, AudioFormatUtils.getAudioFormat(this.getPayloadType()),this);
}
/**
* Starts transmission and for NAT Traversal reasons start receiving also.
*/
public void startTrasmit() {
audioChannel.start();
}
/**
* Set transmit activity. If the active is true, the instance should trasmit.
* If it is set to false, the instance should pause transmit.
*
* @param active active state
*/
public void setTrasmit(boolean active) {
audioChannel.setTrasmit(active);
}
/**
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
*/
public void startReceive() {
// Do nothing
}
/**
* Stops transmission and for NAT Traversal reasons stop receiving also.
*/
public void stopTrasmit() {
if (audioChannel != null)
audioChannel.stop();
}
/**
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
*/
public void stopReceive() {
// Do nothing
}
/**
* Obtain a free port we can use.
*
* @return A free port number.
*/
protected int getFreePort() {
ServerSocket ss;
int freePort = 0;
for (int i = 0; i < 10; i++) {
freePort = (int) (10000 + Math.round(Math.random() * 10000));
freePort = freePort % 2 == 0 ? freePort : freePort + 1;
try {
ss = new ServerSocket(freePort);
freePort = ss.getLocalPort();
ss.close();
return freePort;
}
catch (IOException e) {
e.printStackTrace();
}
}
try {
ss = new ServerSocket(0);
freePort = ss.getLocalPort();
ss.close();
}
catch (IOException e) {
e.printStackTrace();
}
return freePort;
}
}
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
import java.io.IOException;
import java.net.ServerSocket;
import javax.media.MediaLocator;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* This Class implements a complete JingleMediaSession.
* It sould be used to transmit and receive audio captured from the Mic.
* This Class should be automaticly controlled by JingleSession.
* But you could also use in any VOIP application.
* For better NAT Traversal support this implementation don't support only receive or only transmit.
* To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
*
* @author Thiago Camargo
*/
public class AudioMediaSession extends JingleMediaSession {
private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class);
private AudioChannel audioChannel;
/**
* Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates
*
* @param payloadType Payload of the jmf
* @param remote the remote information. The candidate that the jmf will be sent to.
* @param local the local information. The candidate that will receive the jmf
* @param locator media locator
*/
public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
final TransportCandidate local, String locator, JingleSession jingleSession) {
super(payloadType, remote, local, locator==null?"dsound://":locator,jingleSession);
initialize();
}
/**
* Initialize the Audio Channel to make it able to send and receive audio
*/
public void initialize() {
String ip;
String localIp;
int localPort;
int remotePort;
if (this.getLocal().getSymmetric() != null) {
ip = this.getLocal().getIp();
localIp = this.getLocal().getLocalIp();
localPort = getFreePort();
remotePort = this.getLocal().getSymmetric().getPort();
LOGGER.debug(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort);
}
else {
ip = this.getRemote().getIp();
localIp = this.getLocal().getLocalIp();
localPort = this.getLocal().getPort();
remotePort = this.getRemote().getPort();
}
audioChannel = new AudioChannel(new MediaLocator(this.getMediaLocator()), localIp, ip, localPort, remotePort, AudioFormatUtils.getAudioFormat(this.getPayloadType()),this);
}
/**
* Starts transmission and for NAT Traversal reasons start receiving also.
*/
public void startTrasmit() {
audioChannel.start();
}
/**
* Set transmit activity. If the active is true, the instance should trasmit.
* If it is set to false, the instance should pause transmit.
*
* @param active active state
*/
public void setTrasmit(boolean active) {
audioChannel.setTrasmit(active);
}
/**
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
*/
public void startReceive() {
// Do nothing
}
/**
* Stops transmission and for NAT Traversal reasons stop receiving also.
*/
public void stopTrasmit() {
if (audioChannel != null)
audioChannel.stop();
}
/**
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
*/
public void stopReceive() {
// Do nothing
}
/**
* Obtain a free port we can use.
*
* @return A free port number.
*/
protected int getFreePort() {
ServerSocket ss;
int freePort = 0;
for (int i = 0; i < 10; i++) {
freePort = (int) (10000 + Math.round(Math.random() * 10000));
freePort = freePort % 2 == 0 ? freePort : freePort + 1;
try {
ss = new ServerSocket(freePort);
freePort = ss.getLocalPort();
ss.close();
return freePort;
}
catch (IOException e) {
e.printStackTrace();
}
}
try {
ss = new ServerSocket(0);
freePort = ss.getLocalPort();
ss.close();
}
catch (IOException e) {
e.printStackTrace();
}
return freePort;
}
}

View file

@ -1,168 +1,168 @@
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
import javax.media.ControllerErrorEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.Player;
import javax.media.RealizeCompleteEvent;
import javax.media.protocol.DataSource;
import javax.media.rtp.Participant;
import javax.media.rtp.RTPControl;
import javax.media.rtp.ReceiveStream;
import javax.media.rtp.ReceiveStreamListener;
import javax.media.rtp.SessionListener;
import javax.media.rtp.event.ByeEvent;
import javax.media.rtp.event.NewParticipantEvent;
import javax.media.rtp.event.NewReceiveStreamEvent;
import javax.media.rtp.event.ReceiveStreamEvent;
import javax.media.rtp.event.RemotePayloadChangeEvent;
import javax.media.rtp.event.SessionEvent;
import javax.media.rtp.event.StreamMappedEvent;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
/**
* This class implements receive methods and listeners to be used in AudioChannel
*
* @author Thiago Camargo
*/
public class AudioReceiver implements ReceiveStreamListener, SessionListener,
ControllerListener {
private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioReceiver.class);
boolean dataReceived = false;
Object dataSync;
JingleMediaSession jingleMediaSession;
public AudioReceiver(final Object dataSync, final JingleMediaSession jingleMediaSession) {
this.dataSync = dataSync;
this.jingleMediaSession = jingleMediaSession;
}
/**
* JingleSessionListener.
*/
public synchronized void update(SessionEvent evt) {
if (evt instanceof NewParticipantEvent) {
Participant p = ((NewParticipantEvent) evt).getParticipant();
LOGGER.error(" - A new participant had just joined: " + p.getCNAME());
}
}
/**
* ReceiveStreamListener
*/
public synchronized void update(ReceiveStreamEvent evt) {
Participant participant = evt.getParticipant(); // could be null.
ReceiveStream stream = evt.getReceiveStream(); // could be null.
if (evt instanceof RemotePayloadChangeEvent) {
LOGGER.error(" - Received an RTP PayloadChangeEvent.");
LOGGER.error("Sorry, cannot handle payload change.");
}
else if (evt instanceof NewReceiveStreamEvent) {
try {
stream = evt.getReceiveStream();
DataSource ds = stream.getDataSource();
// Find out the formats.
RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl");
if (ctl != null) {
LOGGER.error(" - Recevied new RTP stream: " + ctl.getFormat());
}
else
LOGGER.error(" - Recevied new RTP stream");
if (participant == null)
LOGGER.error(" The sender of this stream had yet to be identified.");
else {
LOGGER.error(" The stream comes from: " + participant.getCNAME());
}
// create a player by passing datasource to the Media Manager
Player p = javax.media.Manager.createPlayer(ds);
if (p == null)
return;
p.addControllerListener(this);
p.realize();
jingleMediaSession.mediaReceived(participant != null ? participant.getCNAME() : "");
// Notify intialize() that a new stream had arrived.
synchronized (dataSync) {
dataReceived = true;
dataSync.notifyAll();
}
}
catch (Exception e) {
LOGGER.error("NewReceiveStreamEvent exception " + e.getMessage());
return;
}
}
else if (evt instanceof StreamMappedEvent) {
if (stream != null && stream.getDataSource() != null) {
DataSource ds = stream.getDataSource();
// Find out the formats.
RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl");
LOGGER.error(" - The previously unidentified stream ");
if (ctl != null)
LOGGER.error(" " + ctl.getFormat());
LOGGER.error(" had now been identified as sent by: " + participant.getCNAME());
}
}
else if (evt instanceof ByeEvent) {
LOGGER.error(" - Got \"bye\" from: " + participant.getCNAME());
}
}
/**
* ControllerListener for the Players.
*/
public synchronized void controllerUpdate(ControllerEvent ce) {
Player p = (Player) ce.getSourceController();
if (p == null)
return;
// Get this when the internal players are realized.
if (ce instanceof RealizeCompleteEvent) {
p.start();
}
if (ce instanceof ControllerErrorEvent) {
p.removeControllerListener(this);
LOGGER.error("Receiver internal error: " + ce);
}
}
}
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
import javax.media.ControllerErrorEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.Player;
import javax.media.RealizeCompleteEvent;
import javax.media.protocol.DataSource;
import javax.media.rtp.Participant;
import javax.media.rtp.RTPControl;
import javax.media.rtp.ReceiveStream;
import javax.media.rtp.ReceiveStreamListener;
import javax.media.rtp.SessionListener;
import javax.media.rtp.event.ByeEvent;
import javax.media.rtp.event.NewParticipantEvent;
import javax.media.rtp.event.NewReceiveStreamEvent;
import javax.media.rtp.event.ReceiveStreamEvent;
import javax.media.rtp.event.RemotePayloadChangeEvent;
import javax.media.rtp.event.SessionEvent;
import javax.media.rtp.event.StreamMappedEvent;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
/**
* This class implements receive methods and listeners to be used in AudioChannel
*
* @author Thiago Camargo
*/
public class AudioReceiver implements ReceiveStreamListener, SessionListener,
ControllerListener {
private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioReceiver.class);
boolean dataReceived = false;
Object dataSync;
JingleMediaSession jingleMediaSession;
public AudioReceiver(final Object dataSync, final JingleMediaSession jingleMediaSession) {
this.dataSync = dataSync;
this.jingleMediaSession = jingleMediaSession;
}
/**
* JingleSessionListener.
*/
public synchronized void update(SessionEvent evt) {
if (evt instanceof NewParticipantEvent) {
Participant p = ((NewParticipantEvent) evt).getParticipant();
LOGGER.error(" - A new participant had just joined: " + p.getCNAME());
}
}
/**
* ReceiveStreamListener
*/
public synchronized void update(ReceiveStreamEvent evt) {
Participant participant = evt.getParticipant(); // could be null.
ReceiveStream stream = evt.getReceiveStream(); // could be null.
if (evt instanceof RemotePayloadChangeEvent) {
LOGGER.error(" - Received an RTP PayloadChangeEvent.");
LOGGER.error("Sorry, cannot handle payload change.");
}
else if (evt instanceof NewReceiveStreamEvent) {
try {
stream = evt.getReceiveStream();
DataSource ds = stream.getDataSource();
// Find out the formats.
RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl");
if (ctl != null) {
LOGGER.error(" - Recevied new RTP stream: " + ctl.getFormat());
}
else
LOGGER.error(" - Recevied new RTP stream");
if (participant == null)
LOGGER.error(" The sender of this stream had yet to be identified.");
else {
LOGGER.error(" The stream comes from: " + participant.getCNAME());
}
// create a player by passing datasource to the Media Manager
Player p = javax.media.Manager.createPlayer(ds);
if (p == null)
return;
p.addControllerListener(this);
p.realize();
jingleMediaSession.mediaReceived(participant != null ? participant.getCNAME() : "");
// Notify intialize() that a new stream had arrived.
synchronized (dataSync) {
dataReceived = true;
dataSync.notifyAll();
}
}
catch (Exception e) {
LOGGER.error("NewReceiveStreamEvent exception " + e.getMessage());
return;
}
}
else if (evt instanceof StreamMappedEvent) {
if (stream != null && stream.getDataSource() != null) {
DataSource ds = stream.getDataSource();
// Find out the formats.
RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl");
LOGGER.error(" - The previously unidentified stream ");
if (ctl != null)
LOGGER.error(" " + ctl.getFormat());
LOGGER.error(" had now been identified as sent by: " + participant.getCNAME());
}
}
else if (evt instanceof ByeEvent) {
LOGGER.error(" - Got \"bye\" from: " + participant.getCNAME());
}
}
/**
* ControllerListener for the Players.
*/
public synchronized void controllerUpdate(ControllerEvent ce) {
Player p = (Player) ce.getSourceController();
if (p == null)
return;
// Get this when the internal players are realized.
if (ce instanceof RealizeCompleteEvent) {
p.start();
}
if (ce instanceof ControllerErrorEvent) {
p.removeControllerListener(this);
LOGGER.error("Receiver internal error: " + ce);
}
}
}

View file

@ -1,167 +1,167 @@
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit;
import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* Implements a jingleMediaManager using JMF based API.
* It supports GSM and G723 codecs.
* <i>This API only currently works on windows and Mac.</i>
*
* @author Thiago Camargo
*/
public class JmfMediaManager extends JingleMediaManager {
private static final SmackLogger LOGGER = SmackLogger.getLogger(JmfMediaManager.class);
public static final String MEDIA_NAME = "JMF";
private List<PayloadType> payloads = new ArrayList<PayloadType>();
private String mediaLocator = null;
/**
* Creates a Media Manager instance
*/
public JmfMediaManager(JingleTransportManager transportManager) {
super(transportManager);
setupPayloads();
}
/**
* Creates a Media Manager instance
*
* @param mediaLocator Media Locator
*/
public JmfMediaManager(String mediaLocator, JingleTransportManager transportManager) {
super(transportManager);
this.mediaLocator = mediaLocator;
setupPayloads();
}
/**
* Returns a new jingleMediaSession
*
* @param payloadType payloadType
* @param remote remote Candidate
* @param local local Candidate
* @return JingleMediaSession
*/
public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
return new AudioMediaSession(payloadType, remote, local, mediaLocator, jingleSession);
}
/**
* Setup API supported Payloads
*/
private void setupPayloads() {
payloads.add(new PayloadType.Audio(3, "gsm"));
payloads.add(new PayloadType.Audio(4, "g723"));
payloads.add(new PayloadType.Audio(0, "PCMU", 16000));
}
/**
* Return all supported Payloads for this Manager
*
* @return The Payload List
*/
public List<PayloadType> getPayloads() {
return payloads;
}
/**
* Return the media locator or null if not defined
*
* @return media locator
*/
public String getMediaLocator() {
return mediaLocator;
}
/**
* Set the media locator
*
* @param mediaLocator media locator or null to use default
*/
public void setMediaLocator(String mediaLocator) {
this.mediaLocator = mediaLocator;
}
/**
* Runs JMFInit the first time the application is started so that capture
* devices are properly detected and initialized by JMF.
*/
public static void setupJMF() {
// .jmf is the place where we store the jmf.properties file used
// by JMF. if the directory does not exist or it does not contain
// a jmf.properties file. or if the jmf.properties file has 0 length
// then this is the first time we're running and should continue to
// with JMFInit
String homeDir = System.getProperty("user.home");
File jmfDir = new File(homeDir, ".jmf");
String classpath = System.getProperty("java.class.path");
classpath += System.getProperty("path.separator")
+ jmfDir.getAbsolutePath();
System.setProperty("java.class.path", classpath);
if (!jmfDir.exists())
jmfDir.mkdir();
File jmfProperties = new File(jmfDir, "jmf.properties");
if (!jmfProperties.exists()) {
try {
jmfProperties.createNewFile();
}
catch (IOException ex) {
LOGGER.debug("Failed to create jmf.properties");
ex.printStackTrace();
}
}
// if we're running on linux checkout that libjmutil.so is where it
// should be and put it there.
runLinuxPreInstall();
//if (jmfProperties.length() == 0) {
new JMFInit(null, false);
//}
}
private static void runLinuxPreInstall() {
// @TODO Implement Linux Pre-Install
}
public String getName() {
return MEDIA_NAME;
}
}
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit;
import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* Implements a jingleMediaManager using JMF based API.
* It supports GSM and G723 codecs.
* <i>This API only currently works on windows and Mac.</i>
*
* @author Thiago Camargo
*/
public class JmfMediaManager extends JingleMediaManager {
private static final SmackLogger LOGGER = SmackLogger.getLogger(JmfMediaManager.class);
public static final String MEDIA_NAME = "JMF";
private List<PayloadType> payloads = new ArrayList<PayloadType>();
private String mediaLocator = null;
/**
* Creates a Media Manager instance
*/
public JmfMediaManager(JingleTransportManager transportManager) {
super(transportManager);
setupPayloads();
}
/**
* Creates a Media Manager instance
*
* @param mediaLocator Media Locator
*/
public JmfMediaManager(String mediaLocator, JingleTransportManager transportManager) {
super(transportManager);
this.mediaLocator = mediaLocator;
setupPayloads();
}
/**
* Returns a new jingleMediaSession
*
* @param payloadType payloadType
* @param remote remote Candidate
* @param local local Candidate
* @return JingleMediaSession
*/
public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
return new AudioMediaSession(payloadType, remote, local, mediaLocator, jingleSession);
}
/**
* Setup API supported Payloads
*/
private void setupPayloads() {
payloads.add(new PayloadType.Audio(3, "gsm"));
payloads.add(new PayloadType.Audio(4, "g723"));
payloads.add(new PayloadType.Audio(0, "PCMU", 16000));
}
/**
* Return all supported Payloads for this Manager
*
* @return The Payload List
*/
public List<PayloadType> getPayloads() {
return payloads;
}
/**
* Return the media locator or null if not defined
*
* @return media locator
*/
public String getMediaLocator() {
return mediaLocator;
}
/**
* Set the media locator
*
* @param mediaLocator media locator or null to use default
*/
public void setMediaLocator(String mediaLocator) {
this.mediaLocator = mediaLocator;
}
/**
* Runs JMFInit the first time the application is started so that capture
* devices are properly detected and initialized by JMF.
*/
public static void setupJMF() {
// .jmf is the place where we store the jmf.properties file used
// by JMF. if the directory does not exist or it does not contain
// a jmf.properties file. or if the jmf.properties file has 0 length
// then this is the first time we're running and should continue to
// with JMFInit
String homeDir = System.getProperty("user.home");
File jmfDir = new File(homeDir, ".jmf");
String classpath = System.getProperty("java.class.path");
classpath += System.getProperty("path.separator")
+ jmfDir.getAbsolutePath();
System.setProperty("java.class.path", classpath);
if (!jmfDir.exists())
jmfDir.mkdir();
File jmfProperties = new File(jmfDir, "jmf.properties");
if (!jmfProperties.exists()) {
try {
jmfProperties.createNewFile();
}
catch (IOException ex) {
LOGGER.debug("Failed to create jmf.properties");
ex.printStackTrace();
}
}
// if we're running on linux checkout that libjmutil.so is where it
// should be and put it there.
runLinuxPreInstall();
//if (jmfProperties.length() == 0) {
new JMFInit(null, false);
//}
}
private static void runLinuxPreInstall() {
// @TODO Implement Linux Pre-Install
}
public String getName() {
return MEDIA_NAME;
}
}

View file

@ -1,242 +1,242 @@
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jspeex;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.security.GeneralSecurityException;
import javax.media.NoProcessorException;
import javax.media.format.UnsupportedFormatException;
import javax.media.rtp.rtcp.SenderReport;
import javax.media.rtp.rtcp.SourceDescription;
import mil.jfcom.cie.media.session.MediaSession;
import mil.jfcom.cie.media.session.MediaSessionListener;
import mil.jfcom.cie.media.session.StreamPlayer;
import mil.jfcom.cie.media.srtp.packetizer.SpeexFormat;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* This Class implements a complete JingleMediaSession.
* It sould be used to transmit and receive audio captured from the Mic.
* This Class should be automaticly controlled by JingleSession.
* But you could also use in any VOIP application.
* For better NAT Traversal support this implementation don't support only receive or only transmit.
* To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
*
* @author Thiago Camargo
*/
public class AudioMediaSession extends JingleMediaSession implements MediaSessionListener {
private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class);
private MediaSession mediaSession;
/**
* Create a Session using Speex Codec
*
* @param localhost localHost
* @param localPort localPort
* @param remoteHost remoteHost
* @param remotePort remotePort
* @param eventHandler eventHandler
* @param quality quality
* @param secure secure
* @param micOn micOn
* @return MediaSession
* @throws NoProcessorException
* @throws UnsupportedFormatException
* @throws IOException
* @throws GeneralSecurityException
*/
public static MediaSession createSession(String localhost, int localPort, String remoteHost, int remotePort, MediaSessionListener eventHandler, int quality, boolean secure, boolean micOn) throws NoProcessorException, UnsupportedFormatException, IOException, GeneralSecurityException {
SpeexFormat.setFramesPerPacket(1);
/**
* The master key. Hardcoded for now.
*/
byte[] masterKey = new byte[]{(byte) 0xE1, (byte) 0xF9, 0x7A, 0x0D, 0x3E, 0x01, (byte) 0x8B, (byte) 0xE0, (byte) 0xD6, 0x4F, (byte) 0xA3, 0x2C, 0x06, (byte) 0xDE, 0x41, 0x39};
/**
* The master salt. Hardcoded for now.
*/
byte[] masterSalt = new byte[]{0x0E, (byte) 0xC6, 0x75, (byte) 0xAD, 0x49, (byte) 0x8A, (byte) 0xFE, (byte) 0xEB, (byte) 0xB6, (byte) 0x96, 0x0B, 0x3A, (byte) 0xAB, (byte) 0xE6};
DatagramSocket[] localPorts = MediaSession.getLocalPorts(InetAddress.getByName(localhost), localPort);
MediaSession session = MediaSession.createInstance(remoteHost, remotePort, localPorts, quality, secure, masterKey, masterSalt);
session.setListener(eventHandler);
session.setSourceDescription(new SourceDescription[]{new SourceDescription(SourceDescription.SOURCE_DESC_NAME, "Superman", 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_EMAIL, "cdcie.tester@je.jfcom.mil", 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_LOC, InetAddress.getByName(localhost) + " Port " + session.getLocalDataPort(), 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_TOOL, "JFCOM CDCIE Audio Chat", 1, false)});
return session;
}
/**
* Creates a org.jivesoftware.jingleaudio.jspeex.AudioMediaSession with defined payload type, remote and local candidates
*
* @param payloadType Payload of the jmf
* @param remote the remote information. The candidate that the jmf will be sent to.
* @param local the local information. The candidate that will receive the jmf
* @param locator media locator
*/
public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
final TransportCandidate local, String locator, JingleSession jingleSession) {
super(payloadType, remote, local, locator == null ? "dsound://" : locator, jingleSession);
initialize();
}
/**
* Initialize the Audio Channel to make it able to send and receive audio
*/
public void initialize() {
String ip;
String localIp;
int localPort;
int remotePort;
if (this.getLocal().getSymmetric() != null) {
ip = this.getLocal().getIp();
localIp = this.getLocal().getLocalIp();
localPort = getFreePort();
remotePort = this.getLocal().getSymmetric().getPort();
LOGGER.debug(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort);
}
else {
ip = this.getRemote().getIp();
localIp = this.getLocal().getLocalIp();
localPort = this.getLocal().getPort();
remotePort = this.getRemote().getPort();
}
try {
mediaSession = createSession(localIp, localPort, ip, remotePort, this, 2, false, true);
}
catch (NoProcessorException e) {
e.printStackTrace();
}
catch (UnsupportedFormatException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
/**
* Starts transmission and for NAT Traversal reasons start receiving also.
*/
public void startTrasmit() {
try {
LOGGER.debug("start");
mediaSession.start(true);
this.mediaReceived("");
}
catch (IOException e) {
e.printStackTrace();
}
}
/**
* Set transmit activity. If the active is true, the instance should trasmit.
* If it is set to false, the instance should pause transmit.
*
* @param active active state
*/
public void setTrasmit(boolean active) {
// Do nothing
}
/**
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
*/
public void startReceive() {
// Do nothing
}
/**
* Stops transmission and for NAT Traversal reasons stop receiving also.
*/
public void stopTrasmit() {
if (mediaSession != null)
mediaSession.close();
}
/**
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
*/
public void stopReceive() {
// Do nothing
}
public void newStreamIdentified(StreamPlayer streamPlayer) {
}
public void senderReportReceived(SenderReport report) {
}
public void streamClosed(StreamPlayer stream, boolean timeout) {
}
/**
* Obtain a free port we can use.
*
* @return A free port number.
*/
protected int getFreePort() {
ServerSocket ss;
int freePort = 0;
for (int i = 0; i < 10; i++) {
freePort = (int) (10000 + Math.round(Math.random() * 10000));
freePort = freePort % 2 == 0 ? freePort : freePort + 1;
try {
ss = new ServerSocket(freePort);
freePort = ss.getLocalPort();
ss.close();
return freePort;
}
catch (IOException e) {
e.printStackTrace();
}
}
try {
ss = new ServerSocket(0);
freePort = ss.getLocalPort();
ss.close();
}
catch (IOException e) {
e.printStackTrace();
}
return freePort;
}
}
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jspeex;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.security.GeneralSecurityException;
import javax.media.NoProcessorException;
import javax.media.format.UnsupportedFormatException;
import javax.media.rtp.rtcp.SenderReport;
import javax.media.rtp.rtcp.SourceDescription;
import mil.jfcom.cie.media.session.MediaSession;
import mil.jfcom.cie.media.session.MediaSessionListener;
import mil.jfcom.cie.media.session.StreamPlayer;
import mil.jfcom.cie.media.srtp.packetizer.SpeexFormat;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* This Class implements a complete JingleMediaSession.
* It sould be used to transmit and receive audio captured from the Mic.
* This Class should be automaticly controlled by JingleSession.
* But you could also use in any VOIP application.
* For better NAT Traversal support this implementation don't support only receive or only transmit.
* To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
*
* @author Thiago Camargo
*/
public class AudioMediaSession extends JingleMediaSession implements MediaSessionListener {
private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class);
private MediaSession mediaSession;
/**
* Create a Session using Speex Codec
*
* @param localhost localHost
* @param localPort localPort
* @param remoteHost remoteHost
* @param remotePort remotePort
* @param eventHandler eventHandler
* @param quality quality
* @param secure secure
* @param micOn micOn
* @return MediaSession
* @throws NoProcessorException
* @throws UnsupportedFormatException
* @throws IOException
* @throws GeneralSecurityException
*/
public static MediaSession createSession(String localhost, int localPort, String remoteHost, int remotePort, MediaSessionListener eventHandler, int quality, boolean secure, boolean micOn) throws NoProcessorException, UnsupportedFormatException, IOException, GeneralSecurityException {
SpeexFormat.setFramesPerPacket(1);
/**
* The master key. Hardcoded for now.
*/
byte[] masterKey = new byte[]{(byte) 0xE1, (byte) 0xF9, 0x7A, 0x0D, 0x3E, 0x01, (byte) 0x8B, (byte) 0xE0, (byte) 0xD6, 0x4F, (byte) 0xA3, 0x2C, 0x06, (byte) 0xDE, 0x41, 0x39};
/**
* The master salt. Hardcoded for now.
*/
byte[] masterSalt = new byte[]{0x0E, (byte) 0xC6, 0x75, (byte) 0xAD, 0x49, (byte) 0x8A, (byte) 0xFE, (byte) 0xEB, (byte) 0xB6, (byte) 0x96, 0x0B, 0x3A, (byte) 0xAB, (byte) 0xE6};
DatagramSocket[] localPorts = MediaSession.getLocalPorts(InetAddress.getByName(localhost), localPort);
MediaSession session = MediaSession.createInstance(remoteHost, remotePort, localPorts, quality, secure, masterKey, masterSalt);
session.setListener(eventHandler);
session.setSourceDescription(new SourceDescription[]{new SourceDescription(SourceDescription.SOURCE_DESC_NAME, "Superman", 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_EMAIL, "cdcie.tester@je.jfcom.mil", 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_LOC, InetAddress.getByName(localhost) + " Port " + session.getLocalDataPort(), 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_TOOL, "JFCOM CDCIE Audio Chat", 1, false)});
return session;
}
/**
* Creates a org.jivesoftware.jingleaudio.jspeex.AudioMediaSession with defined payload type, remote and local candidates
*
* @param payloadType Payload of the jmf
* @param remote the remote information. The candidate that the jmf will be sent to.
* @param local the local information. The candidate that will receive the jmf
* @param locator media locator
*/
public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
final TransportCandidate local, String locator, JingleSession jingleSession) {
super(payloadType, remote, local, locator == null ? "dsound://" : locator, jingleSession);
initialize();
}
/**
* Initialize the Audio Channel to make it able to send and receive audio
*/
public void initialize() {
String ip;
String localIp;
int localPort;
int remotePort;
if (this.getLocal().getSymmetric() != null) {
ip = this.getLocal().getIp();
localIp = this.getLocal().getLocalIp();
localPort = getFreePort();
remotePort = this.getLocal().getSymmetric().getPort();
LOGGER.debug(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort);
}
else {
ip = this.getRemote().getIp();
localIp = this.getLocal().getLocalIp();
localPort = this.getLocal().getPort();
remotePort = this.getRemote().getPort();
}
try {
mediaSession = createSession(localIp, localPort, ip, remotePort, this, 2, false, true);
}
catch (NoProcessorException e) {
e.printStackTrace();
}
catch (UnsupportedFormatException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
/**
* Starts transmission and for NAT Traversal reasons start receiving also.
*/
public void startTrasmit() {
try {
LOGGER.debug("start");
mediaSession.start(true);
this.mediaReceived("");
}
catch (IOException e) {
e.printStackTrace();
}
}
/**
* Set transmit activity. If the active is true, the instance should trasmit.
* If it is set to false, the instance should pause transmit.
*
* @param active active state
*/
public void setTrasmit(boolean active) {
// Do nothing
}
/**
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
*/
public void startReceive() {
// Do nothing
}
/**
* Stops transmission and for NAT Traversal reasons stop receiving also.
*/
public void stopTrasmit() {
if (mediaSession != null)
mediaSession.close();
}
/**
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
*/
public void stopReceive() {
// Do nothing
}
public void newStreamIdentified(StreamPlayer streamPlayer) {
}
public void senderReportReceived(SenderReport report) {
}
public void streamClosed(StreamPlayer stream, boolean timeout) {
}
/**
* Obtain a free port we can use.
*
* @return A free port number.
*/
protected int getFreePort() {
ServerSocket ss;
int freePort = 0;
for (int i = 0; i < 10; i++) {
freePort = (int) (10000 + Math.round(Math.random() * 10000));
freePort = freePort % 2 == 0 ? freePort : freePort + 1;
try {
ss = new ServerSocket(freePort);
freePort = ss.getLocalPort();
ss.close();
return freePort;
}
catch (IOException e) {
e.printStackTrace();
}
}
try {
ss = new ServerSocket(0);
freePort = ss.getLocalPort();
ss.close();
}
catch (IOException e) {
e.printStackTrace();
}
return freePort;
}
}

View file

@ -1,131 +1,131 @@
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jspeex;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit;
import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* Implements a jingleMediaManager using JMF based API and JSpeex.
* It supports Speex codec.
* <i>This API only currently works on windows.</i>
*
* @author Thiago Camargo
*/
public class SpeexMediaManager extends JingleMediaManager {
private static final SmackLogger LOGGER = SmackLogger.getLogger(SpeexMediaManager.class);
public static final String MEDIA_NAME = "Speex";
private List<PayloadType> payloads = new ArrayList<PayloadType>();
public SpeexMediaManager(JingleTransportManager transportManager) {
super(transportManager);
setupPayloads();
setupJMF();
}
/**
* Returns a new jingleMediaSession
*
* @param payloadType payloadType
* @param remote remote Candidate
* @param local local Candidate
* @return JingleMediaSession
*/
public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
return new AudioMediaSession(payloadType, remote, local, null,null);
}
/**
* Setup API supported Payloads
*/
private void setupPayloads() {
payloads.add(new PayloadType.Audio(15, "speex"));
}
/**
* Return all supported Payloads for this Manager
*
* @return The Payload List
*/
public List<PayloadType> getPayloads() {
return payloads;
}
/**
* Runs JMFInit the first time the application is started so that capture
* devices are properly detected and initialized by JMF.
*/
public static void setupJMF() {
// .jmf is the place where we store the jmf.properties file used
// by JMF. if the directory does not exist or it does not contain
// a jmf.properties file. or if the jmf.properties file has 0 length
// then this is the first time we're running and should continue to
// with JMFInit
String homeDir = System.getProperty("user.home");
File jmfDir = new File(homeDir, ".jmf");
String classpath = System.getProperty("java.class.path");
classpath += System.getProperty("path.separator")
+ jmfDir.getAbsolutePath();
System.setProperty("java.class.path", classpath);
if (!jmfDir.exists())
jmfDir.mkdir();
File jmfProperties = new File(jmfDir, "jmf.properties");
if (!jmfProperties.exists()) {
try {
jmfProperties.createNewFile();
}
catch (IOException ex) {
LOGGER.debug("Failed to create jmf.properties");
ex.printStackTrace();
}
}
// if we're running on linux checkout that libjmutil.so is where it
// should be and put it there.
runLinuxPreInstall();
if (jmfProperties.length() == 0) {
new JMFInit(null, false);
}
}
private static void runLinuxPreInstall() {
// @TODO Implement Linux Pre-Install
}
public String getName() {
return MEDIA_NAME;
}
}
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.jspeex;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit;
import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* Implements a jingleMediaManager using JMF based API and JSpeex.
* It supports Speex codec.
* <i>This API only currently works on windows.</i>
*
* @author Thiago Camargo
*/
public class SpeexMediaManager extends JingleMediaManager {
private static final SmackLogger LOGGER = SmackLogger.getLogger(SpeexMediaManager.class);
public static final String MEDIA_NAME = "Speex";
private List<PayloadType> payloads = new ArrayList<PayloadType>();
public SpeexMediaManager(JingleTransportManager transportManager) {
super(transportManager);
setupPayloads();
setupJMF();
}
/**
* Returns a new jingleMediaSession
*
* @param payloadType payloadType
* @param remote remote Candidate
* @param local local Candidate
* @return JingleMediaSession
*/
public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
return new AudioMediaSession(payloadType, remote, local, null,null);
}
/**
* Setup API supported Payloads
*/
private void setupPayloads() {
payloads.add(new PayloadType.Audio(15, "speex"));
}
/**
* Return all supported Payloads for this Manager
*
* @return The Payload List
*/
public List<PayloadType> getPayloads() {
return payloads;
}
/**
* Runs JMFInit the first time the application is started so that capture
* devices are properly detected and initialized by JMF.
*/
public static void setupJMF() {
// .jmf is the place where we store the jmf.properties file used
// by JMF. if the directory does not exist or it does not contain
// a jmf.properties file. or if the jmf.properties file has 0 length
// then this is the first time we're running and should continue to
// with JMFInit
String homeDir = System.getProperty("user.home");
File jmfDir = new File(homeDir, ".jmf");
String classpath = System.getProperty("java.class.path");
classpath += System.getProperty("path.separator")
+ jmfDir.getAbsolutePath();
System.setProperty("java.class.path", classpath);
if (!jmfDir.exists())
jmfDir.mkdir();
File jmfProperties = new File(jmfDir, "jmf.properties");
if (!jmfProperties.exists()) {
try {
jmfProperties.createNewFile();
}
catch (IOException ex) {
LOGGER.debug("Failed to create jmf.properties");
ex.printStackTrace();
}
}
// if we're running on linux checkout that libjmutil.so is where it
// should be and put it there.
runLinuxPreInstall();
if (jmfProperties.length() == 0) {
new JMFInit(null, false);
}
}
private static void runLinuxPreInstall() {
// @TODO Implement Linux Pre-Install
}
public String getName() {
return MEDIA_NAME;
}
}

View file

@ -12,154 +12,154 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/**
* UDP Image Receiver.
* It uses PNG Tiles into UDP packets.
*
* @author Thiago Rocha Camargo
*/
public class ImageReceiver extends Canvas {
private static final long serialVersionUID = -7000112305305269025L;
private boolean on = true;
private DatagramSocket socket;
private BufferedImage tiles[][];
private static final int tileWidth = ImageTransmitter.tileWidth;
private InetAddress localHost;
private InetAddress remoteHost;
private int localPort;
private int remotePort;
private ImageDecoder decoder;
public ImageReceiver(final InetAddress remoteHost, final int remotePort, final int localPort, int width, int height) {
tiles = new BufferedImage[width][height];
try {
socket = new DatagramSocket(localPort);
localHost = socket.getLocalAddress();
this.remoteHost = remoteHost;
this.remotePort = remotePort;
this.localPort = localPort;
this.decoder = new DefaultDecoder();
new Thread(new Runnable() {
public void run() {
byte buf[] = new byte[1024];
DatagramPacket p = new DatagramPacket(buf, 1024);
try {
while (on) {
socket.receive(p);
int length = p.getLength();
BufferedImage bufferedImage = decoder.decode(new ByteArrayInputStream(p.getData(), 0, length - 2));
if (bufferedImage != null) {
int x = p.getData()[length - 2];
int y = p.getData()[length - 1];
drawTile(x, y, bufferedImage);
}
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
byte buf[] = new byte[1024];
DatagramPacket p = new DatagramPacket(buf, 1024);
try {
while (on) {
p.setAddress(remoteHost);
p.setPort(remotePort);
socket.send(p);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
catch (SocketException e) {
e.printStackTrace();
}
this.setSize(width, height);
}
public InetAddress getLocalHost() {
return localHost;
}
public InetAddress getRemoteHost() {
return remoteHost;
}
public int getLocalPort() {
return localPort;
}
public int getRemotePort() {
return remotePort;
}
public DatagramSocket getDatagramSocket() {
return socket;
}
public void drawTile(int x, int y, BufferedImage bufferedImage) {
tiles[x][y] = bufferedImage;
//repaint(x * tileWidth, y * tileWidth, tileWidth, tileWidth);
this.getGraphics().drawImage(bufferedImage, tileWidth * x, tileWidth * y, this);
}
public void paint(Graphics g) {
for (int i = 0; i < tiles.length; i++) {
for (int j = 0; j < tiles[0].length; j++) {
g.drawImage(tiles[i][j], tileWidth * i, tileWidth * j, this);
}
}
}
public ImageDecoder getDecoder() {
return decoder;
}
public void setDecoder(ImageDecoder decoder) {
this.decoder = decoder;
}
public void stop(){
this.on=false;
socket.close();
}
}
package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/**
* UDP Image Receiver.
* It uses PNG Tiles into UDP packets.
*
* @author Thiago Rocha Camargo
*/
public class ImageReceiver extends Canvas {
private static final long serialVersionUID = -7000112305305269025L;
private boolean on = true;
private DatagramSocket socket;
private BufferedImage tiles[][];
private static final int tileWidth = ImageTransmitter.tileWidth;
private InetAddress localHost;
private InetAddress remoteHost;
private int localPort;
private int remotePort;
private ImageDecoder decoder;
public ImageReceiver(final InetAddress remoteHost, final int remotePort, final int localPort, int width, int height) {
tiles = new BufferedImage[width][height];
try {
socket = new DatagramSocket(localPort);
localHost = socket.getLocalAddress();
this.remoteHost = remoteHost;
this.remotePort = remotePort;
this.localPort = localPort;
this.decoder = new DefaultDecoder();
new Thread(new Runnable() {
public void run() {
byte buf[] = new byte[1024];
DatagramPacket p = new DatagramPacket(buf, 1024);
try {
while (on) {
socket.receive(p);
int length = p.getLength();
BufferedImage bufferedImage = decoder.decode(new ByteArrayInputStream(p.getData(), 0, length - 2));
if (bufferedImage != null) {
int x = p.getData()[length - 2];
int y = p.getData()[length - 1];
drawTile(x, y, bufferedImage);
}
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
byte buf[] = new byte[1024];
DatagramPacket p = new DatagramPacket(buf, 1024);
try {
while (on) {
p.setAddress(remoteHost);
p.setPort(remotePort);
socket.send(p);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
catch (SocketException e) {
e.printStackTrace();
}
this.setSize(width, height);
}
public InetAddress getLocalHost() {
return localHost;
}
public InetAddress getRemoteHost() {
return remoteHost;
}
public int getLocalPort() {
return localPort;
}
public int getRemotePort() {
return remotePort;
}
public DatagramSocket getDatagramSocket() {
return socket;
}
public void drawTile(int x, int y, BufferedImage bufferedImage) {
tiles[x][y] = bufferedImage;
//repaint(x * tileWidth, y * tileWidth, tileWidth, tileWidth);
this.getGraphics().drawImage(bufferedImage, tileWidth * x, tileWidth * y, this);
}
public void paint(Graphics g) {
for (int i = 0; i < tiles.length; i++) {
for (int j = 0; j < tiles[0].length; j++) {
g.drawImage(tiles[i][j], tileWidth * i, tileWidth * j, this);
}
}
}
public ImageDecoder getDecoder() {
return decoder;
}
public void setDecoder(ImageDecoder decoder) {
this.decoder = decoder;
}
public void stop(){
this.on=false;
socket.close();
}
}

View file

@ -12,207 +12,207 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Arrays;
import org.jivesoftware.smackx.jingle.SmackLogger;
/**
* UDP Image Receiver.
* It uses PNG Tiles into UDP packets.
*
* @author Thiago Rocha Camargo
*/
public class ImageTransmitter implements Runnable {
private static final SmackLogger LOGGER = SmackLogger.getLogger(ImageTransmitter.class);
private Robot robot;
private InetAddress localHost;
private InetAddress remoteHost;
private int localPort;
private int remotePort;
public static final int tileWidth = 25;
private boolean on = true;
private boolean transmit = false;
private DatagramSocket socket;
private Rectangle area;
private int tiles[][][];
private int maxI;
private int maxJ;
private ImageEncoder encoder;
public final static int KEYFRAME = 10;
public ImageTransmitter(DatagramSocket socket, InetAddress remoteHost, int remotePort, Rectangle area) {
try {
robot = new Robot();
maxI = (int) Math.ceil(area.getWidth() / tileWidth);
maxJ = (int) Math.ceil(area.getHeight() / tileWidth);
tiles = new int[maxI][maxJ][tileWidth * tileWidth];
this.area = area;
this.socket = socket;
localHost = socket.getLocalAddress();
localPort = socket.getLocalPort();
this.remoteHost = remoteHost;
this.remotePort = remotePort;
this.encoder = new DefaultEncoder();
transmit = true;
}
catch (AWTException e) {
e.printStackTrace();
}
}
public void start() {
byte buf[] = new byte[1024];
final DatagramPacket p = new DatagramPacket(buf, 1024);
int keyframe = 0;
while (on) {
if (transmit) {
BufferedImage capture = robot.createScreenCapture(area);
QuantizeFilter filter = new QuantizeFilter();
capture = filter.filter(capture, null);
long trace = System.currentTimeMillis();
if (++keyframe > KEYFRAME) {
keyframe = 0;
}
LOGGER.debug("KEYFRAME:" + keyframe);
for (int i = 0; i < maxI; i++) {
for (int j = 0; j < maxJ; j++) {
final BufferedImage bufferedImage = capture.getSubimage(i * tileWidth, j * tileWidth, tileWidth, tileWidth);
int pixels[] = new int[tileWidth * tileWidth];
PixelGrabber pg = new PixelGrabber(bufferedImage, 0, 0, tileWidth, tileWidth, pixels, 0, tileWidth);
try {
if (pg.grabPixels()) {
if (keyframe == KEYFRAME || !Arrays.equals(tiles[i][j], pixels)) {
ByteArrayOutputStream baos = encoder.encode(bufferedImage);
if (baos != null) {
try {
Thread.sleep(1);
baos.write(i);
baos.write(j);
byte[] bytesOut = baos.toByteArray();
if (bytesOut.length > 1000)
LOGGER.error("Bytes out > 1000. Equals " + bytesOut.length);
p.setData(bytesOut);
p.setAddress(remoteHost);
p.setPort(remotePort);
try {
socket.send(p);
}
catch (IOException e) {
e.printStackTrace();
}
tiles[i][j] = pixels;
}
catch (Exception e) {
}
}
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
trace = (System.currentTimeMillis() - trace);
LOGGER.debug("Loop Time:" + trace);
if (trace < 500) {
try {
Thread.sleep(500 - trace);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public void run() {
start();
}
/**
* Set Transmit Enabled/Disabled
*
* @param transmit boolean Enabled/Disabled
*/
public void setTransmit(boolean transmit) {
this.transmit = transmit;
}
/**
* Get the encoder used to encode Images Tiles
*
* @return encoder
*/
public ImageEncoder getEncoder() {
return encoder;
}
/**
* Set the encoder used to encode Image Tiles
*
* @param encoder encoder
*/
public void setEncoder(ImageEncoder encoder) {
this.encoder = encoder;
}
/**
* Stops Transmitter
*/
public void stop() {
this.transmit = false;
this.on = false;
socket.close();
}
}
package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Arrays;
import org.jivesoftware.smackx.jingle.SmackLogger;
/**
* UDP Image Receiver.
* It uses PNG Tiles into UDP packets.
*
* @author Thiago Rocha Camargo
*/
public class ImageTransmitter implements Runnable {
private static final SmackLogger LOGGER = SmackLogger.getLogger(ImageTransmitter.class);
private Robot robot;
private InetAddress localHost;
private InetAddress remoteHost;
private int localPort;
private int remotePort;
public static final int tileWidth = 25;
private boolean on = true;
private boolean transmit = false;
private DatagramSocket socket;
private Rectangle area;
private int tiles[][][];
private int maxI;
private int maxJ;
private ImageEncoder encoder;
public final static int KEYFRAME = 10;
public ImageTransmitter(DatagramSocket socket, InetAddress remoteHost, int remotePort, Rectangle area) {
try {
robot = new Robot();
maxI = (int) Math.ceil(area.getWidth() / tileWidth);
maxJ = (int) Math.ceil(area.getHeight() / tileWidth);
tiles = new int[maxI][maxJ][tileWidth * tileWidth];
this.area = area;
this.socket = socket;
localHost = socket.getLocalAddress();
localPort = socket.getLocalPort();
this.remoteHost = remoteHost;
this.remotePort = remotePort;
this.encoder = new DefaultEncoder();
transmit = true;
}
catch (AWTException e) {
e.printStackTrace();
}
}
public void start() {
byte buf[] = new byte[1024];
final DatagramPacket p = new DatagramPacket(buf, 1024);
int keyframe = 0;
while (on) {
if (transmit) {
BufferedImage capture = robot.createScreenCapture(area);
QuantizeFilter filter = new QuantizeFilter();
capture = filter.filter(capture, null);
long trace = System.currentTimeMillis();
if (++keyframe > KEYFRAME) {
keyframe = 0;
}
LOGGER.debug("KEYFRAME:" + keyframe);
for (int i = 0; i < maxI; i++) {
for (int j = 0; j < maxJ; j++) {
final BufferedImage bufferedImage = capture.getSubimage(i * tileWidth, j * tileWidth, tileWidth, tileWidth);
int pixels[] = new int[tileWidth * tileWidth];
PixelGrabber pg = new PixelGrabber(bufferedImage, 0, 0, tileWidth, tileWidth, pixels, 0, tileWidth);
try {
if (pg.grabPixels()) {
if (keyframe == KEYFRAME || !Arrays.equals(tiles[i][j], pixels)) {
ByteArrayOutputStream baos = encoder.encode(bufferedImage);
if (baos != null) {
try {
Thread.sleep(1);
baos.write(i);
baos.write(j);
byte[] bytesOut = baos.toByteArray();
if (bytesOut.length > 1000)
LOGGER.error("Bytes out > 1000. Equals " + bytesOut.length);
p.setData(bytesOut);
p.setAddress(remoteHost);
p.setPort(remotePort);
try {
socket.send(p);
}
catch (IOException e) {
e.printStackTrace();
}
tiles[i][j] = pixels;
}
catch (Exception e) {
}
}
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
trace = (System.currentTimeMillis() - trace);
LOGGER.debug("Loop Time:" + trace);
if (trace < 500) {
try {
Thread.sleep(500 - trace);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public void run() {
start();
}
/**
* Set Transmit Enabled/Disabled
*
* @param transmit boolean Enabled/Disabled
*/
public void setTransmit(boolean transmit) {
this.transmit = transmit;
}
/**
* Get the encoder used to encode Images Tiles
*
* @return encoder
*/
public ImageEncoder getEncoder() {
return encoder;
}
/**
* Set the encoder used to encode Image Tiles
*
* @param encoder encoder
*/
public void setEncoder(ImageEncoder encoder) {
this.encoder = encoder;
}
/**
* Stops Transmitter
*/
public void stop() {
this.transmit = false;
this.on = false;
socket.close();
}
}

View file

@ -1,31 +1,31 @@
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smackx.jingle.JingleSession;
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A Basic Jingle Transport Manager implementation.
*
*/
public class BasicTransportManager extends JingleTransportManager{
protected TransportResolver createResolver(JingleSession session) {
return new BasicResolver();
}
}
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smackx.jingle.JingleSession;
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A Basic Jingle Transport Manager implementation.
*
*/
public class BasicTransportManager extends JingleTransportManager{
protected TransportResolver createResolver(JingleSession session) {
return new BasicResolver();
}
}

View file

@ -1,147 +1,147 @@
/**
*
* Copyright 2003-2005 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.Random;
/**
* Bridged Resolver use a RTPBridge Service to add a relayed candidate.
* A very reliable solution for NAT Traversal.
* <p/>
* The resolver verify is the XMPP Server that the client is connected offer this service.
* If the server supports, a candidate is requested from the service.
* The resolver adds this candidate
*/
public class BridgedResolver extends TransportResolver {
Connection connection;
Random random = new Random();
long sid;
/**
* Constructor.
* A Bridged Resolver need a Connection to connect to a RTP Bridge.
*/
public BridgedResolver(Connection connection) {
super();
this.connection = connection;
}
/**
* Resolve Bridged Candidate.
* <p/>
* The BridgedResolver takes the IP addresse and ports of a jmf proxy service.
*/
public synchronized void resolve(JingleSession session) throws XMPPException {
setResolveInit();
clearCandidates();
sid = Math.abs(random.nextLong());
RTPBridge rtpBridge = RTPBridge.getRTPBridge(connection, String.valueOf(sid));
String localIp = getLocalHost();
TransportCandidate localCandidate = new TransportCandidate.Fixed(
rtpBridge.getIp(), rtpBridge.getPortA());
localCandidate.setLocalIp(localIp);
TransportCandidate remoteCandidate = new TransportCandidate.Fixed(
rtpBridge.getIp(), rtpBridge.getPortB());
remoteCandidate.setLocalIp(localIp);
localCandidate.setSymmetric(remoteCandidate);
remoteCandidate.setSymmetric(localCandidate);
localCandidate.setPassword(rtpBridge.getPass());
remoteCandidate.setPassword(rtpBridge.getPass());
localCandidate.setSessionId(rtpBridge.getSid());
remoteCandidate.setSessionId(rtpBridge.getSid());
localCandidate.setConnection(this.connection);
remoteCandidate.setConnection(this.connection);
addCandidate(localCandidate);
setResolveEnd();
}
public void initialize() throws XMPPException {
clearCandidates();
if (!RTPBridge.serviceAvailable(connection)) {
setInitialized();
throw new XMPPException("No RTP Bridge service available");
}
setInitialized();
}
public void cancel() throws XMPPException {
// Nothing to do here
}
public static String getLocalHost() {
Enumeration<NetworkInterface> ifaces = null;
try {
ifaces = NetworkInterface.getNetworkInterfaces();
}
catch (SocketException e) {
e.printStackTrace();
}
while (ifaces.hasMoreElements()) {
NetworkInterface iface = ifaces.nextElement();
Enumeration<InetAddress> iaddresses = iface.getInetAddresses();
while (iaddresses.hasMoreElements()) {
InetAddress iaddress = iaddresses.nextElement();
if (!iaddress.isLoopbackAddress() && !iaddress.isLinkLocalAddress() && !iaddress.isSiteLocalAddress() && !(iaddress instanceof Inet6Address)) {
return iaddress.getHostAddress();
}
}
}
try {
return InetAddress.getLocalHost().getHostAddress();
}
catch (Exception e) {
e.printStackTrace();
}
return "127.0.0.1";
}
}
/**
*
* Copyright 2003-2005 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.Random;
/**
* Bridged Resolver use a RTPBridge Service to add a relayed candidate.
* A very reliable solution for NAT Traversal.
* <p/>
* The resolver verify is the XMPP Server that the client is connected offer this service.
* If the server supports, a candidate is requested from the service.
* The resolver adds this candidate
*/
public class BridgedResolver extends TransportResolver {
Connection connection;
Random random = new Random();
long sid;
/**
* Constructor.
* A Bridged Resolver need a Connection to connect to a RTP Bridge.
*/
public BridgedResolver(Connection connection) {
super();
this.connection = connection;
}
/**
* Resolve Bridged Candidate.
* <p/>
* The BridgedResolver takes the IP addresse and ports of a jmf proxy service.
*/
public synchronized void resolve(JingleSession session) throws XMPPException {
setResolveInit();
clearCandidates();
sid = Math.abs(random.nextLong());
RTPBridge rtpBridge = RTPBridge.getRTPBridge(connection, String.valueOf(sid));
String localIp = getLocalHost();
TransportCandidate localCandidate = new TransportCandidate.Fixed(
rtpBridge.getIp(), rtpBridge.getPortA());
localCandidate.setLocalIp(localIp);
TransportCandidate remoteCandidate = new TransportCandidate.Fixed(
rtpBridge.getIp(), rtpBridge.getPortB());
remoteCandidate.setLocalIp(localIp);
localCandidate.setSymmetric(remoteCandidate);
remoteCandidate.setSymmetric(localCandidate);
localCandidate.setPassword(rtpBridge.getPass());
remoteCandidate.setPassword(rtpBridge.getPass());
localCandidate.setSessionId(rtpBridge.getSid());
remoteCandidate.setSessionId(rtpBridge.getSid());
localCandidate.setConnection(this.connection);
remoteCandidate.setConnection(this.connection);
addCandidate(localCandidate);
setResolveEnd();
}
public void initialize() throws XMPPException {
clearCandidates();
if (!RTPBridge.serviceAvailable(connection)) {
setInitialized();
throw new XMPPException("No RTP Bridge service available");
}
setInitialized();
}
public void cancel() throws XMPPException {
// Nothing to do here
}
public static String getLocalHost() {
Enumeration<NetworkInterface> ifaces = null;
try {
ifaces = NetworkInterface.getNetworkInterfaces();
}
catch (SocketException e) {
e.printStackTrace();
}
while (ifaces.hasMoreElements()) {
NetworkInterface iface = ifaces.nextElement();
Enumeration<InetAddress> iaddresses = iface.getInetAddresses();
while (iaddresses.hasMoreElements()) {
InetAddress iaddress = iaddresses.nextElement();
if (!iaddress.isLoopbackAddress() && !iaddress.isLinkLocalAddress() && !iaddress.isSiteLocalAddress() && !(iaddress instanceof Inet6Address)) {
return iaddress.getHostAddress();
}
}
}
try {
return InetAddress.getLocalHost().getHostAddress();
}
catch (Exception e) {
e.printStackTrace();
}
return "127.0.0.1";
}
}

View file

@ -1,80 +1,80 @@
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.listeners.CreatedJingleSessionListener;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener;
import org.jivesoftware.smackx.jingle.media.PayloadType;
/**
* A Jingle Transport Manager implementation to be used for NAT Networks.
* This kind of transport needs that the connected XMPP Server provide a Bridge Service. (http://www.jivesoftware.com/protocol/rtpbridge)
* To relay the jmf outside the NAT.
*
* @author Thiago Camargo
*/
public class BridgedTransportManager extends JingleTransportManager implements JingleSessionListener, CreatedJingleSessionListener {
Connection xmppConnection;
public BridgedTransportManager(Connection xmppConnection) {
super();
this.xmppConnection = xmppConnection;
}
/**
* Return the correspondent resolver
*
* @param session correspondent Jingle Session
* @return resolver
*/
protected TransportResolver createResolver(JingleSession session) {
BridgedResolver bridgedResolver = new BridgedResolver(this.xmppConnection);
return bridgedResolver;
}
// Implement a Session Listener to relay candidates after establishment
public void sessionEstablished(PayloadType pt, TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
RTPBridge rtpBridge = RTPBridge.relaySession(lc.getConnection(), lc.getSessionId(), lc.getPassword(), rc, lc);
}
public void sessionDeclined(String reason, JingleSession jingleSession) {
}
public void sessionRedirected(String redirection, JingleSession jingleSession) {
}
public void sessionClosed(String reason, JingleSession jingleSession) {
}
public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
}
public void sessionMediaReceived(JingleSession jingleSession, String participant) {
// Do Nothing
}
// Session Created
public void sessionCreated(JingleSession jingleSession) {
jingleSession.addListener(this);
}
}
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.listeners.CreatedJingleSessionListener;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener;
import org.jivesoftware.smackx.jingle.media.PayloadType;
/**
* A Jingle Transport Manager implementation to be used for NAT Networks.
* This kind of transport needs that the connected XMPP Server provide a Bridge Service. (http://www.jivesoftware.com/protocol/rtpbridge)
* To relay the jmf outside the NAT.
*
* @author Thiago Camargo
*/
public class BridgedTransportManager extends JingleTransportManager implements JingleSessionListener, CreatedJingleSessionListener {
Connection xmppConnection;
public BridgedTransportManager(Connection xmppConnection) {
super();
this.xmppConnection = xmppConnection;
}
/**
* Return the correspondent resolver
*
* @param session correspondent Jingle Session
* @return resolver
*/
protected TransportResolver createResolver(JingleSession session) {
BridgedResolver bridgedResolver = new BridgedResolver(this.xmppConnection);
return bridgedResolver;
}
// Implement a Session Listener to relay candidates after establishment
public void sessionEstablished(PayloadType pt, TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
RTPBridge rtpBridge = RTPBridge.relaySession(lc.getConnection(), lc.getSessionId(), lc.getPassword(), rc, lc);
}
public void sessionDeclined(String reason, JingleSession jingleSession) {
}
public void sessionRedirected(String redirection, JingleSession jingleSession) {
}
public void sessionClosed(String reason, JingleSession jingleSession) {
}
public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
}
public void sessionMediaReceived(JingleSession jingleSession, String participant) {
// Do Nothing
}
// Session Created
public void sessionCreated(JingleSession jingleSession) {
jingleSession.addListener(this);
}
}

View file

@ -34,4 +34,4 @@ public interface DatagramListener {
*/
public boolean datagramReceived(DatagramPacket datagramPacket);
}
}

View file

@ -1,65 +1,65 @@
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.ContentNegotiator;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.listeners.CreatedJingleSessionListener;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener;
import org.jivesoftware.smackx.jingle.media.PayloadType;
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A Fixed Jingle Transport Manager implementation.
*
*/
public class FixedTransportManager extends JingleTransportManager implements JingleSessionListener, CreatedJingleSessionListener {
FixedResolver resolver;
public FixedTransportManager(FixedResolver inResolver) {
resolver = inResolver;
}
protected TransportResolver createResolver(JingleSession session) {
return resolver;
}
public void sessionEstablished(PayloadType pt, TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
}
public void sessionDeclined(String reason, JingleSession jingleSession) {
}
public void sessionRedirected(String redirection, JingleSession jingleSession) {
}
public void sessionClosed(String reason, JingleSession jingleSession) {
}
public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
}
public void sessionMediaReceived(JingleSession jingleSession, String participant) {
// Do Nothing
}
public void sessionCreated(JingleSession jingleSession) {
jingleSession.addListener(this);
}
}
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.ContentNegotiator;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.listeners.CreatedJingleSessionListener;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener;
import org.jivesoftware.smackx.jingle.media.PayloadType;
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A Fixed Jingle Transport Manager implementation.
*
*/
public class FixedTransportManager extends JingleTransportManager implements JingleSessionListener, CreatedJingleSessionListener {
FixedResolver resolver;
public FixedTransportManager(FixedResolver inResolver) {
resolver = inResolver;
}
protected TransportResolver createResolver(JingleSession session) {
return resolver;
}
public void sessionEstablished(PayloadType pt, TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
}
public void sessionDeclined(String reason, JingleSession jingleSession) {
}
public void sessionRedirected(String redirection, JingleSession jingleSession) {
}
public void sessionClosed(String reason, JingleSession jingleSession) {
}
public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
}
public void sessionMediaReceived(JingleSession jingleSession, String participant) {
// Do Nothing
}
public void sessionCreated(JingleSession jingleSession) {
jingleSession.addListener(this);
}
}

View file

@ -142,4 +142,4 @@ public class HttpServer {
}
}
}
}
}

View file

@ -1,278 +1,278 @@
/**
*
* Copyright 2003-2005 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.SmackLogger;
import de.javawi.jstun.test.demo.ice.Candidate;
import de.javawi.jstun.test.demo.ice.ICENegociator;
import de.javawi.jstun.util.UtilityException;
/**
* ICE Resolver for Jingle transport method that results in sending data between two entities using the Interactive Connectivity Establishment (ICE) methodology. (XEP-0176)
* The goal of this resolver is to make possible to establish and manage out-of-band connections between two XMPP entities, even if they are behind Network Address Translators (NATs) or firewalls.
* To use this resolver you must have a STUN Server and be in a non STUN blocked network. Or use a XMPP server with public IP detection Service.
*
* @author Thiago Camargo
*/
public class ICEResolver extends TransportResolver {
private static final SmackLogger LOGGER = SmackLogger.getLogger(ICEResolver.class);
Connection connection;
Random random = new Random();
long sid;
String server;
int port;
static Map<String, ICENegociator> negociatorsMap = new HashMap<String, ICENegociator>();
//ICENegociator iceNegociator = null;
public ICEResolver(Connection connection, String server, int port) {
super();
this.connection = connection;
this.server = server;
this.port = port;
this.setType(Type.ice);
}
public void initialize() throws XMPPException {
if (!isResolving() && !isResolved()) {
LOGGER.debug("Initialized");
// Negotiation with a STUN server for a set of interfaces is quite slow, but the results
// never change over then instance of a JVM. To increase connection performance considerably
// we now cache established/initialized negotiators for each STUN server, so that subsequent uses
// of the STUN server are much, much faster.
if (negociatorsMap.get(server) == null) {
ICENegociator iceNegociator = new ICENegociator(server, port, (short) 1);
negociatorsMap.put(server, iceNegociator);
// gather candidates
iceNegociator.gatherCandidateAddresses();
// priorize candidates
iceNegociator.prioritizeCandidates();
}
}
this.setInitialized();
}
public void cancel() throws XMPPException {
}
/**
* Resolve the IP and obtain a valid transport method.
*/
public synchronized void resolve(JingleSession session) throws XMPPException {
this.setResolveInit();
for (TransportCandidate candidate : this.getCandidatesList()) {
if (candidate instanceof ICECandidate) {
ICECandidate iceCandidate = (ICECandidate) candidate;
iceCandidate.removeCandidateEcho();
}
}
this.clear();
// Create a transport candidate for each ICE negotiator candidate we have.
ICENegociator iceNegociator = negociatorsMap.get(server);
for (Candidate candidate : iceNegociator.getSortedCandidates())
try {
Candidate.CandidateType type = candidate.getCandidateType();
ICECandidate.Type iceType = ICECandidate.Type.local;
if (type.equals(Candidate.CandidateType.ServerReflexive))
iceType = ICECandidate.Type.srflx;
else if (type.equals(Candidate.CandidateType.PeerReflexive))
iceType = ICECandidate.Type.prflx;
else if (type.equals(Candidate.CandidateType.Relayed))
iceType = ICECandidate.Type.relay;
else
iceType = ICECandidate.Type.host;
// JBW/GW - 17JUL08: Figure out the zero-based NIC number for this candidate.
short nicNum = 0;
try {
Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces();
short i = 0;
NetworkInterface nic = NetworkInterface.getByInetAddress(candidate.getAddress().getInetAddress());
while(nics.hasMoreElements()) {
NetworkInterface checkNIC = nics.nextElement();
if (checkNIC.equals(nic)) {
nicNum = i;
break;
}
i++;
}
} catch (SocketException e1) {
e1.printStackTrace();
}
TransportCandidate transportCandidate = new ICECandidate(candidate.getAddress().getInetAddress().getHostAddress(), 1, nicNum, String.valueOf(Math.abs(random.nextLong())), candidate.getPort(), "1", candidate.getPriority(), iceType);
transportCandidate.setLocalIp(candidate.getBase().getAddress().getInetAddress().getHostAddress());
transportCandidate.setPort(getFreePort());
try {
transportCandidate.addCandidateEcho(session);
}
catch (SocketException e) {
e.printStackTrace();
}
this.addCandidate(transportCandidate);
LOGGER.debug("Candidate addr: " + candidate.getAddress().getInetAddress() + "|" + candidate.getBase().getAddress().getInetAddress() + " Priority:" + candidate.getPriority());
}
catch (UtilityException e) {
e.printStackTrace();
}
catch (UnknownHostException e) {
e.printStackTrace();
}
// Get a Relay Candidate from XMPP Server
if (RTPBridge.serviceAvailable(connection)) {
// try {
String localIp;
int network;
// JBW/GW - 17JUL08: ICENegotiator.getPublicCandidate() always returned null in JSTUN 1.7.0, and now the API doesn't exist in JSTUN 1.7.1
// if (iceNegociator.getPublicCandidate() != null) {
// localIp = iceNegociator.getPublicCandidate().getBase().getAddress().getInetAddress().getHostAddress();
// network = iceNegociator.getPublicCandidate().getNetwork();
// }
// else {
{
localIp = BridgedResolver.getLocalHost();
network = 0;
}
sid = Math.abs(random.nextLong());
RTPBridge rtpBridge = RTPBridge.getRTPBridge(connection, String.valueOf(sid));
TransportCandidate localCandidate = new ICECandidate(
rtpBridge.getIp(), 1, network, String.valueOf(Math.abs(random.nextLong())), rtpBridge.getPortA(), "1", 0, ICECandidate.Type.relay);
localCandidate.setLocalIp(localIp);
TransportCandidate remoteCandidate = new ICECandidate(
rtpBridge.getIp(), 1, network, String.valueOf(Math.abs(random.nextLong())), rtpBridge.getPortB(), "1", 0, ICECandidate.Type.relay);
remoteCandidate.setLocalIp(localIp);
localCandidate.setSymmetric(remoteCandidate);
remoteCandidate.setSymmetric(localCandidate);
localCandidate.setPassword(rtpBridge.getPass());
remoteCandidate.setPassword(rtpBridge.getPass());
localCandidate.setSessionId(rtpBridge.getSid());
remoteCandidate.setSessionId(rtpBridge.getSid());
localCandidate.setConnection(this.connection);
remoteCandidate.setConnection(this.connection);
addCandidate(localCandidate);
// }
// catch (UtilityException e) {
// e.printStackTrace();
// }
// catch (UnknownHostException e) {
// e.printStackTrace();
// }
// Get Public Candidate From XMPP Server
// JBW/GW - 17JUL08 - ICENegotiator.getPublicCandidate() always returned null in JSTUN 1.7.0, and now it doesn't exist in JSTUN 1.7.1
// if (iceNegociator.getPublicCandidate() == null) {
if (true) {
String publicIp = RTPBridge.getPublicIP(connection);
if (publicIp != null && !publicIp.equals("")) {
Enumeration<NetworkInterface> ifaces = null;
try {
ifaces = NetworkInterface.getNetworkInterfaces();
}
catch (SocketException e) {
e.printStackTrace();
}
// If detect this address in local machine, don't use it.
boolean found = false;
while (ifaces.hasMoreElements() && !false) {
NetworkInterface iface = ifaces.nextElement();
Enumeration<InetAddress> iaddresses = iface.getInetAddresses();
while (iaddresses.hasMoreElements()) {
InetAddress iaddress = iaddresses.nextElement();
if (iaddress.getHostAddress().indexOf(publicIp) > -1) {
found = true;
break;
}
}
}
if (!found) {
try {
TransportCandidate publicCandidate = new ICECandidate(
publicIp, 1, 0, String.valueOf(Math.abs(random.nextLong())), getFreePort(), "1", 0, ICECandidate.Type.srflx);
publicCandidate.setLocalIp(InetAddress.getLocalHost().getHostAddress());
try {
publicCandidate.addCandidateEcho(session);
}
catch (SocketException e) {
e.printStackTrace();
}
addCandidate(publicCandidate);
}
catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
}
}
this.setResolveEnd();
}
}
/**
*
* Copyright 2003-2005 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.SmackLogger;
import de.javawi.jstun.test.demo.ice.Candidate;
import de.javawi.jstun.test.demo.ice.ICENegociator;
import de.javawi.jstun.util.UtilityException;
/**
* ICE Resolver for Jingle transport method that results in sending data between two entities using the Interactive Connectivity Establishment (ICE) methodology. (XEP-0176)
* The goal of this resolver is to make possible to establish and manage out-of-band connections between two XMPP entities, even if they are behind Network Address Translators (NATs) or firewalls.
* To use this resolver you must have a STUN Server and be in a non STUN blocked network. Or use a XMPP server with public IP detection Service.
*
* @author Thiago Camargo
*/
public class ICEResolver extends TransportResolver {
private static final SmackLogger LOGGER = SmackLogger.getLogger(ICEResolver.class);
Connection connection;
Random random = new Random();
long sid;
String server;
int port;
static Map<String, ICENegociator> negociatorsMap = new HashMap<String, ICENegociator>();
//ICENegociator iceNegociator = null;
public ICEResolver(Connection connection, String server, int port) {
super();
this.connection = connection;
this.server = server;
this.port = port;
this.setType(Type.ice);
}
public void initialize() throws XMPPException {
if (!isResolving() && !isResolved()) {
LOGGER.debug("Initialized");
// Negotiation with a STUN server for a set of interfaces is quite slow, but the results
// never change over then instance of a JVM. To increase connection performance considerably
// we now cache established/initialized negotiators for each STUN server, so that subsequent uses
// of the STUN server are much, much faster.
if (negociatorsMap.get(server) == null) {
ICENegociator iceNegociator = new ICENegociator(server, port, (short) 1);
negociatorsMap.put(server, iceNegociator);
// gather candidates
iceNegociator.gatherCandidateAddresses();
// priorize candidates
iceNegociator.prioritizeCandidates();
}
}
this.setInitialized();
}
public void cancel() throws XMPPException {
}
/**
* Resolve the IP and obtain a valid transport method.
*/
public synchronized void resolve(JingleSession session) throws XMPPException {
this.setResolveInit();
for (TransportCandidate candidate : this.getCandidatesList()) {
if (candidate instanceof ICECandidate) {
ICECandidate iceCandidate = (ICECandidate) candidate;
iceCandidate.removeCandidateEcho();
}
}
this.clear();
// Create a transport candidate for each ICE negotiator candidate we have.
ICENegociator iceNegociator = negociatorsMap.get(server);
for (Candidate candidate : iceNegociator.getSortedCandidates())
try {
Candidate.CandidateType type = candidate.getCandidateType();
ICECandidate.Type iceType = ICECandidate.Type.local;
if (type.equals(Candidate.CandidateType.ServerReflexive))
iceType = ICECandidate.Type.srflx;
else if (type.equals(Candidate.CandidateType.PeerReflexive))
iceType = ICECandidate.Type.prflx;
else if (type.equals(Candidate.CandidateType.Relayed))
iceType = ICECandidate.Type.relay;
else
iceType = ICECandidate.Type.host;
// JBW/GW - 17JUL08: Figure out the zero-based NIC number for this candidate.
short nicNum = 0;
try {
Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces();
short i = 0;
NetworkInterface nic = NetworkInterface.getByInetAddress(candidate.getAddress().getInetAddress());
while(nics.hasMoreElements()) {
NetworkInterface checkNIC = nics.nextElement();
if (checkNIC.equals(nic)) {
nicNum = i;
break;
}
i++;
}
} catch (SocketException e1) {
e1.printStackTrace();
}
TransportCandidate transportCandidate = new ICECandidate(candidate.getAddress().getInetAddress().getHostAddress(), 1, nicNum, String.valueOf(Math.abs(random.nextLong())), candidate.getPort(), "1", candidate.getPriority(), iceType);
transportCandidate.setLocalIp(candidate.getBase().getAddress().getInetAddress().getHostAddress());
transportCandidate.setPort(getFreePort());
try {
transportCandidate.addCandidateEcho(session);
}
catch (SocketException e) {
e.printStackTrace();
}
this.addCandidate(transportCandidate);
LOGGER.debug("Candidate addr: " + candidate.getAddress().getInetAddress() + "|" + candidate.getBase().getAddress().getInetAddress() + " Priority:" + candidate.getPriority());
}
catch (UtilityException e) {
e.printStackTrace();
}
catch (UnknownHostException e) {
e.printStackTrace();
}
// Get a Relay Candidate from XMPP Server
if (RTPBridge.serviceAvailable(connection)) {
// try {
String localIp;
int network;
// JBW/GW - 17JUL08: ICENegotiator.getPublicCandidate() always returned null in JSTUN 1.7.0, and now the API doesn't exist in JSTUN 1.7.1
// if (iceNegociator.getPublicCandidate() != null) {
// localIp = iceNegociator.getPublicCandidate().getBase().getAddress().getInetAddress().getHostAddress();
// network = iceNegociator.getPublicCandidate().getNetwork();
// }
// else {
{
localIp = BridgedResolver.getLocalHost();
network = 0;
}
sid = Math.abs(random.nextLong());
RTPBridge rtpBridge = RTPBridge.getRTPBridge(connection, String.valueOf(sid));
TransportCandidate localCandidate = new ICECandidate(
rtpBridge.getIp(), 1, network, String.valueOf(Math.abs(random.nextLong())), rtpBridge.getPortA(), "1", 0, ICECandidate.Type.relay);
localCandidate.setLocalIp(localIp);
TransportCandidate remoteCandidate = new ICECandidate(
rtpBridge.getIp(), 1, network, String.valueOf(Math.abs(random.nextLong())), rtpBridge.getPortB(), "1", 0, ICECandidate.Type.relay);
remoteCandidate.setLocalIp(localIp);
localCandidate.setSymmetric(remoteCandidate);
remoteCandidate.setSymmetric(localCandidate);
localCandidate.setPassword(rtpBridge.getPass());
remoteCandidate.setPassword(rtpBridge.getPass());
localCandidate.setSessionId(rtpBridge.getSid());
remoteCandidate.setSessionId(rtpBridge.getSid());
localCandidate.setConnection(this.connection);
remoteCandidate.setConnection(this.connection);
addCandidate(localCandidate);
// }
// catch (UtilityException e) {
// e.printStackTrace();
// }
// catch (UnknownHostException e) {
// e.printStackTrace();
// }
// Get Public Candidate From XMPP Server
// JBW/GW - 17JUL08 - ICENegotiator.getPublicCandidate() always returned null in JSTUN 1.7.0, and now it doesn't exist in JSTUN 1.7.1
// if (iceNegociator.getPublicCandidate() == null) {
if (true) {
String publicIp = RTPBridge.getPublicIP(connection);
if (publicIp != null && !publicIp.equals("")) {
Enumeration<NetworkInterface> ifaces = null;
try {
ifaces = NetworkInterface.getNetworkInterfaces();
}
catch (SocketException e) {
e.printStackTrace();
}
// If detect this address in local machine, don't use it.
boolean found = false;
while (ifaces.hasMoreElements() && !false) {
NetworkInterface iface = ifaces.nextElement();
Enumeration<InetAddress> iaddresses = iface.getInetAddresses();
while (iaddresses.hasMoreElements()) {
InetAddress iaddress = iaddresses.nextElement();
if (iaddress.getHostAddress().indexOf(publicIp) > -1) {
found = true;
break;
}
}
}
if (!found) {
try {
TransportCandidate publicCandidate = new ICECandidate(
publicIp, 1, 0, String.valueOf(Math.abs(random.nextLong())), getFreePort(), "1", 0, ICECandidate.Type.srflx);
publicCandidate.setLocalIp(InetAddress.getLocalHost().getHostAddress());
try {
publicCandidate.addCandidateEcho(session);
}
catch (SocketException e) {
e.printStackTrace();
}
addCandidate(publicCandidate);
}
catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
}
}
this.setResolveEnd();
}
}

View file

@ -1,81 +1,81 @@
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.listeners.CreatedJingleSessionListener;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener;
import org.jivesoftware.smackx.jingle.media.PayloadType;
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public class ICETransportManager extends JingleTransportManager implements JingleSessionListener, CreatedJingleSessionListener {
ICEResolver iceResolver = null;
public ICETransportManager(Connection xmppConnection, String server, int port) {
iceResolver = new ICEResolver(xmppConnection, server, port);
try {
iceResolver.initializeAndWait();
}
catch (XMPPException e) {
e.printStackTrace();
}
}
protected TransportResolver createResolver(JingleSession session) {
try {
iceResolver.resolve(session);
}
catch (XMPPException e) {
e.printStackTrace();
}
return iceResolver;
}
// Implement a Session Listener to relay candidates after establishment
public void sessionEstablished(PayloadType pt, TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
if (lc instanceof ICECandidate) {
if (((ICECandidate) lc).getType().equals("relay")) {
RTPBridge rtpBridge = RTPBridge.relaySession(lc.getConnection(), lc.getSessionId(), lc.getPassword(), rc, lc);
}
}
}
public void sessionDeclined(String reason, JingleSession jingleSession) {
}
public void sessionRedirected(String redirection, JingleSession jingleSession) {
}
public void sessionClosed(String reason, JingleSession jingleSession) {
}
public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
}
public void sessionMediaReceived(JingleSession jingleSession, String participant) {
// Do Nothing
}
// Session Created
public void sessionCreated(JingleSession jingleSession) {
jingleSession.addListener(this);
}
}
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.listeners.CreatedJingleSessionListener;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener;
import org.jivesoftware.smackx.jingle.media.PayloadType;
/**
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public class ICETransportManager extends JingleTransportManager implements JingleSessionListener, CreatedJingleSessionListener {
ICEResolver iceResolver = null;
public ICETransportManager(Connection xmppConnection, String server, int port) {
iceResolver = new ICEResolver(xmppConnection, server, port);
try {
iceResolver.initializeAndWait();
}
catch (XMPPException e) {
e.printStackTrace();
}
}
protected TransportResolver createResolver(JingleSession session) {
try {
iceResolver.resolve(session);
}
catch (XMPPException e) {
e.printStackTrace();
}
return iceResolver;
}
// Implement a Session Listener to relay candidates after establishment
public void sessionEstablished(PayloadType pt, TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
if (lc instanceof ICECandidate) {
if (((ICECandidate) lc).getType().equals("relay")) {
RTPBridge rtpBridge = RTPBridge.relaySession(lc.getConnection(), lc.getSessionId(), lc.getPassword(), rc, lc);
}
}
}
public void sessionDeclined(String reason, JingleSession jingleSession) {
}
public void sessionRedirected(String redirection, JingleSession jingleSession) {
}
public void sessionClosed(String reason, JingleSession jingleSession) {
}
public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
}
public void sessionMediaReceived(JingleSession jingleSession, String participant) {
// Do Nothing
}
// Session Created
public void sessionCreated(JingleSession jingleSession) {
jingleSession.addListener(this);
}
}

View file

@ -1,29 +1,29 @@
/**
*
* Copyright 2003-2005 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
/**
* Listener for ECHO Test Results
*
* @author Thiago Camargo
*/
public interface ResultListener {
public void testFinished(TestResult result, TransportCandidate candidate);
}
/**
*
* Copyright 2003-2005 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
/**
* Listener for ECHO Test Results
*
* @author Thiago Camargo
*/
public interface ResultListener {
public void testFinished(TestResult result, TransportCandidate candidate);
}

View file

@ -1,284 +1,284 @@
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.jivesoftware.smackx.packet.DiscoverItems;
import org.xmlpull.v1.XmlPullParser;
/**
* STUN IQ Packet used to request and retrieve a STUN server and port to make p2p connections easier. STUN is usually used by Jingle Media Transmission between two parties that are behind NAT.
* <p/>
* High Level Usage Example:
* <p/>
* STUN stun = STUN.getSTUNServer(connection);
*
* @author Thiago Camargo
*/
public class STUN extends IQ {
private static final SmackLogger LOGGER = SmackLogger.getLogger(STUN.class);
private List<StunServerAddress> servers = new ArrayList<StunServerAddress>();
private String publicIp = null;
/**
* Element name of the packet extension.
*/
public static final String DOMAIN = "stun";
/**
* Element name of the packet extension.
*/
public static final String ELEMENT_NAME = "query";
/**
* Namespace of the packet extension.
*/
public static final String NAMESPACE = "google:jingleinfo";
static {
ProviderManager.getInstance().addIQProvider(ELEMENT_NAME, NAMESPACE, new STUN.Provider());
}
/**
* Creates a STUN IQ
*/
public STUN() {
}
/**
* Get a list of STUN Servers recommended by the Server
*
* @return
*/
public List<StunServerAddress> getServers() {
return servers;
}
/**
* Get Public Ip returned from the XMPP server
*
* @return
*/
public String getPublicIp() {
return publicIp;
}
/**
* Set Public Ip returned from the XMPP server
*
* @param publicIp
*/
private void setPublicIp(String publicIp) {
this.publicIp = publicIp;
}
/**
* Get the Child Element XML of the Packet
*
* @return
*/
public String getChildElementXML() {
StringBuilder str = new StringBuilder();
str.append("<" + ELEMENT_NAME + " xmlns='" + NAMESPACE + "'/>");
return str.toString();
}
/**
* IQProvider for RTP Bridge packets.
* Parse receive RTPBridge packet to a RTPBridge instance
*
* @author Thiago Rocha
*/
public static class Provider implements IQProvider {
public Provider() {
super();
}
public IQ parseIQ(XmlPullParser parser) throws Exception {
boolean done = false;
int eventType;
String elementName;
String namespace;
if (!parser.getNamespace().equals(NAMESPACE))
throw new Exception("Not a STUN packet");
STUN iq = new STUN();
// Start processing sub-elements
while (!done) {
eventType = parser.next();
elementName = parser.getName();
namespace = parser.getNamespace();
if (eventType == XmlPullParser.START_TAG) {
if (elementName.equals("server")) {
String host = null;
String port = null;
for (int i = 0; i < parser.getAttributeCount(); i++) {
if (parser.getAttributeName(i).equals("host"))
host = parser.getAttributeValue(i);
else if (parser.getAttributeName(i).equals("udp"))
port = parser.getAttributeValue(i);
}
if (host != null && port != null)
iq.servers.add(new StunServerAddress(host, port));
}
else if (elementName.equals("publicip")) {
String host = null;
for (int i = 0; i < parser.getAttributeCount(); i++) {
if (parser.getAttributeName(i).equals("ip"))
host = parser.getAttributeValue(i);
}
if (host != null && !host.equals(""))
iq.setPublicIp(host);
}
}
else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals(ELEMENT_NAME)) {
done = true;
}
}
}
return iq;
}
}
/**
* Get a new STUN Server Address and port from the server.
* If a error occurs or the server don't support STUN Service, null is returned.
*
* @param connection
* @return
*/
public static STUN getSTUNServer(Connection connection) {
if (!connection.isConnected()) {
return null;
}
STUN stunPacket = new STUN();
stunPacket.setTo(DOMAIN + "." + connection.getServiceName());
PacketCollector collector = connection
.createPacketCollector(new PacketIDFilter(stunPacket.getPacketID()));
connection.sendPacket(stunPacket);
STUN response = (STUN) collector
.nextResult(SmackConfiguration.getPacketReplyTimeout());
// Cancel the collector.
collector.cancel();
return response;
}
/**
* Check if the server support STUN Service.
*
* @param xmppConnection
* @return
*/
public static boolean serviceAvailable(Connection connection) {
if (!connection.isConnected()) {
return false;
}
LOGGER.debug("Service listing");
ServiceDiscoveryManager disco = ServiceDiscoveryManager
.getInstanceFor(connection);
try {
DiscoverItems items = disco.discoverItems(connection.getServiceName());
Iterator<DiscoverItems.Item> iter = items.getItems();
while (iter.hasNext()) {
DiscoverItems.Item item = iter.next();
DiscoverInfo info = disco.discoverInfo(item.getEntityID());
Iterator<DiscoverInfo.Identity> iter2 = info.getIdentities();
while (iter2.hasNext()) {
DiscoverInfo.Identity identity = iter2.next();
if (identity.getCategory().equals("proxy") && identity.getType().equals("stun"))
if (info.containsFeature(NAMESPACE))
return true;
}
LOGGER.debug(item.getName()+"-"+info.getType());
}
}
catch (XMPPException e) {
e.printStackTrace();
}
return false;
}
/**
* Provides easy abstract to store STUN Server Addresses and Ports
*/
public static class StunServerAddress {
private String server;
private String port;
public StunServerAddress(String server, String port) {
this.server = server;
this.port = port;
}
/**
* Get the Host Address
*
* @return
*/
public String getServer() {
return server;
}
/**
* Get the Server Port
*
* @return
*/
public String getPort() {
return port;
}
}
}
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.jingle.SmackLogger;
import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.jivesoftware.smackx.packet.DiscoverItems;
import org.xmlpull.v1.XmlPullParser;
/**
* STUN IQ Packet used to request and retrieve a STUN server and port to make p2p connections easier. STUN is usually used by Jingle Media Transmission between two parties that are behind NAT.
* <p/>
* High Level Usage Example:
* <p/>
* STUN stun = STUN.getSTUNServer(connection);
*
* @author Thiago Camargo
*/
public class STUN extends IQ {
private static final SmackLogger LOGGER = SmackLogger.getLogger(STUN.class);
private List<StunServerAddress> servers = new ArrayList<StunServerAddress>();
private String publicIp = null;
/**
* Element name of the packet extension.
*/
public static final String DOMAIN = "stun";
/**
* Element name of the packet extension.
*/
public static final String ELEMENT_NAME = "query";
/**
* Namespace of the packet extension.
*/
public static final String NAMESPACE = "google:jingleinfo";
static {
ProviderManager.getInstance().addIQProvider(ELEMENT_NAME, NAMESPACE, new STUN.Provider());
}
/**
* Creates a STUN IQ
*/
public STUN() {
}
/**
* Get a list of STUN Servers recommended by the Server
*
* @return
*/
public List<StunServerAddress> getServers() {
return servers;
}
/**
* Get Public Ip returned from the XMPP server
*
* @return
*/
public String getPublicIp() {
return publicIp;
}
/**
* Set Public Ip returned from the XMPP server
*
* @param publicIp
*/
private void setPublicIp(String publicIp) {
this.publicIp = publicIp;
}
/**
* Get the Child Element XML of the Packet
*
* @return
*/
public String getChildElementXML() {
StringBuilder str = new StringBuilder();
str.append("<" + ELEMENT_NAME + " xmlns='" + NAMESPACE + "'/>");
return str.toString();
}
/**
* IQProvider for RTP Bridge packets.
* Parse receive RTPBridge packet to a RTPBridge instance
*
* @author Thiago Rocha
*/
public static class Provider implements IQProvider {
public Provider() {
super();
}
public IQ parseIQ(XmlPullParser parser) throws Exception {
boolean done = false;
int eventType;
String elementName;
String namespace;
if (!parser.getNamespace().equals(NAMESPACE))
throw new Exception("Not a STUN packet");
STUN iq = new STUN();
// Start processing sub-elements
while (!done) {
eventType = parser.next();
elementName = parser.getName();
namespace = parser.getNamespace();
if (eventType == XmlPullParser.START_TAG) {
if (elementName.equals("server")) {
String host = null;
String port = null;
for (int i = 0; i < parser.getAttributeCount(); i++) {
if (parser.getAttributeName(i).equals("host"))
host = parser.getAttributeValue(i);
else if (parser.getAttributeName(i).equals("udp"))
port = parser.getAttributeValue(i);
}
if (host != null && port != null)
iq.servers.add(new StunServerAddress(host, port));
}
else if (elementName.equals("publicip")) {
String host = null;
for (int i = 0; i < parser.getAttributeCount(); i++) {
if (parser.getAttributeName(i).equals("ip"))
host = parser.getAttributeValue(i);
}
if (host != null && !host.equals(""))
iq.setPublicIp(host);
}
}
else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals(ELEMENT_NAME)) {
done = true;
}
}
}
return iq;
}
}
/**
* Get a new STUN Server Address and port from the server.
* If a error occurs or the server don't support STUN Service, null is returned.
*
* @param connection
* @return
*/
public static STUN getSTUNServer(Connection connection) {
if (!connection.isConnected()) {
return null;
}
STUN stunPacket = new STUN();
stunPacket.setTo(DOMAIN + "." + connection.getServiceName());
PacketCollector collector = connection
.createPacketCollector(new PacketIDFilter(stunPacket.getPacketID()));
connection.sendPacket(stunPacket);
STUN response = (STUN) collector
.nextResult(SmackConfiguration.getPacketReplyTimeout());
// Cancel the collector.
collector.cancel();
return response;
}
/**
* Check if the server support STUN Service.
*
* @param xmppConnection
* @return
*/
public static boolean serviceAvailable(Connection connection) {
if (!connection.isConnected()) {
return false;
}
LOGGER.debug("Service listing");
ServiceDiscoveryManager disco = ServiceDiscoveryManager
.getInstanceFor(connection);
try {
DiscoverItems items = disco.discoverItems(connection.getServiceName());
Iterator<DiscoverItems.Item> iter = items.getItems();
while (iter.hasNext()) {
DiscoverItems.Item item = iter.next();
DiscoverInfo info = disco.discoverInfo(item.getEntityID());
Iterator<DiscoverInfo.Identity> iter2 = info.getIdentities();
while (iter2.hasNext()) {
DiscoverInfo.Identity identity = iter2.next();
if (identity.getCategory().equals("proxy") && identity.getType().equals("stun"))
if (info.containsFeature(NAMESPACE))
return true;
}
LOGGER.debug(item.getName()+"-"+info.getType());
}
}
catch (XMPPException e) {
e.printStackTrace();
}
return false;
}
/**
* Provides easy abstract to store STUN Server Addresses and Ports
*/
public static class StunServerAddress {
private String server;
private String port;
public StunServerAddress(String server, String port) {
this.server = server;
this.port = port;
}
/**
* Get the Host Address
*
* @return
*/
public String getServer() {
return server;
}
/**
* Get the Server Port
*
* @return
*/
public String getPort() {
return port;
}
}
}

View file

@ -1,48 +1,48 @@
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
/**
* A Jingle Transport Manager implementation to be used on NAT networks with STUN Service NOT Blocked.
*
* @author Thiago Camargo
*/
public class STUNTransportManager extends JingleTransportManager {
STUNResolver stunResolver = null;
public STUNTransportManager() {
stunResolver = new STUNResolver() {
};
try {
stunResolver.initializeAndWait();
} catch (XMPPException e) {
e.printStackTrace();
}
}
protected TransportResolver createResolver(JingleSession session) {
try {
stunResolver.resolve(session);
} catch (XMPPException e) {
e.printStackTrace();
}
return stunResolver;
}
}
/**
*
* Copyright 2003-2006 Jive Software.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleSession;
/**
* A Jingle Transport Manager implementation to be used on NAT networks with STUN Service NOT Blocked.
*
* @author Thiago Camargo
*/
public class STUNTransportManager extends JingleTransportManager {
STUNResolver stunResolver = null;
public STUNTransportManager() {
stunResolver = new STUNResolver() {
};
try {
stunResolver.initializeAndWait();
} catch (XMPPException e) {
e.printStackTrace();
}
}
protected TransportResolver createResolver(JingleSession session) {
try {
stunResolver.resolve(session);
} catch (XMPPException e) {
e.printStackTrace();
}
return stunResolver;
}
}

View file

@ -12,108 +12,108 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.test.SmackTestCase;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class BridgedResolverTest extends SmackTestCase {
private int counter;
private final Object mutex = new Object();
public BridgedResolverTest(String arg) {
super(arg);
}
// Counter management
private void resetCounter() {
synchronized (mutex) {
counter = 0;
}
}
private void incCounter() {
synchronized (mutex) {
counter++;
}
}
private int valCounter() {
int val;
synchronized (mutex) {
val = counter;
}
return val;
}
public void testCheckService() {
assertTrue(RTPBridge.serviceAvailable(getConnection(0)));
}
public void testGetBridge() {
resetCounter();
RTPBridge rtpBridge = RTPBridge.getRTPBridge(getConnection(0), "001");
System.out.println(rtpBridge.getIp() + " portA:" + rtpBridge.getPortA() + " portB:" + rtpBridge.getPortB());
if (rtpBridge != null) {
if (rtpBridge.getIp() != null) incCounter();
if (rtpBridge.getPortA() != -1) incCounter();
if (rtpBridge.getPortB() != -1) incCounter();
}
assertTrue(valCounter() == 3);
}
public void testGetPublicIp() {
resetCounter();
String publicIp = RTPBridge.getPublicIP(getConnection(0));
System.out.println(publicIp);
if (publicIp != null) {
incCounter();
}
try {
InetAddress localaddr = InetAddress.getLocalHost();
System.out.println("main Local IP Address : " + localaddr.getHostAddress());
System.out.println("main Local hostname : " + localaddr.getHostName());
InetAddress[] localaddrs = InetAddress.getAllByName("localhost");
for (int i = 0; i < localaddrs.length; i++) {
if (!localaddrs[i].equals(localaddr)) {
System.out.println("alt Local IP Address : " + localaddrs[i].getHostAddress());
System.out.println("alt Local hostname : " + localaddrs[i].getHostName());
System.out.println();
}
}
}
catch (UnknownHostException e) {
System.err.println("Can't detect localhost : " + e);
}
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
assertTrue(valCounter() == 1);
}
protected int getMaxConnections() {
return 1;
}
}
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.test.SmackTestCase;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class BridgedResolverTest extends SmackTestCase {
private int counter;
private final Object mutex = new Object();
public BridgedResolverTest(String arg) {
super(arg);
}
// Counter management
private void resetCounter() {
synchronized (mutex) {
counter = 0;
}
}
private void incCounter() {
synchronized (mutex) {
counter++;
}
}
private int valCounter() {
int val;
synchronized (mutex) {
val = counter;
}
return val;
}
public void testCheckService() {
assertTrue(RTPBridge.serviceAvailable(getConnection(0)));
}
public void testGetBridge() {
resetCounter();
RTPBridge rtpBridge = RTPBridge.getRTPBridge(getConnection(0), "001");
System.out.println(rtpBridge.getIp() + " portA:" + rtpBridge.getPortA() + " portB:" + rtpBridge.getPortB());
if (rtpBridge != null) {
if (rtpBridge.getIp() != null) incCounter();
if (rtpBridge.getPortA() != -1) incCounter();
if (rtpBridge.getPortB() != -1) incCounter();
}
assertTrue(valCounter() == 3);
}
public void testGetPublicIp() {
resetCounter();
String publicIp = RTPBridge.getPublicIP(getConnection(0));
System.out.println(publicIp);
if (publicIp != null) {
incCounter();
}
try {
InetAddress localaddr = InetAddress.getLocalHost();
System.out.println("main Local IP Address : " + localaddr.getHostAddress());
System.out.println("main Local hostname : " + localaddr.getHostName());
InetAddress[] localaddrs = InetAddress.getAllByName("localhost");
for (int i = 0; i < localaddrs.length; i++) {
if (!localaddrs[i].equals(localaddr)) {
System.out.println("alt Local IP Address : " + localaddrs[i].getHostAddress());
System.out.println("alt Local hostname : " + localaddrs[i].getHostName());
System.out.println();
}
}
}
catch (UnknownHostException e) {
System.err.println("Can't detect localhost : " + e);
}
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
assertTrue(valCounter() == 1);
}
protected int getMaxConnections() {
return 1;
}
}

View file

@ -1,13 +1,13 @@
<?xml version="1.0"?>
<!-- Default configuration for Smack test cases. -->
<testcase>
<!-- Host and port of the XMPP server to use -->
<host>localhost</host>
<port>5222</port>
<!-- Chat and MUC domain names to use -->
<chat>chat</chat>
<muc>conference</muc>
<?xml version="1.0"?>
<!-- Default configuration for Smack test cases. -->
<testcase>
<!-- Host and port of the XMPP server to use -->
<host>localhost</host>
<port>5222</port>
<!-- Chat and MUC domain names to use -->
<chat>chat</chat>
<muc>conference</muc>
</testcase>