001/** 002 * 003 * Copyright 2003-2006 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.jingle.mediaimpl.jmf; 018 019import java.io.IOException; 020import java.net.ServerSocket; 021import java.util.logging.Logger; 022 023import javax.media.MediaLocator; 024 025import org.jivesoftware.smackx.jingle.JingleSession; 026import org.jivesoftware.smackx.jingle.media.JingleMediaSession; 027import org.jivesoftware.smackx.jingle.media.PayloadType; 028import org.jivesoftware.smackx.jingle.nat.TransportCandidate; 029 030/** 031 * This Class implements a complete JingleMediaSession. 032 * It sould be used to transmit and receive audio captured from the Mic. 033 * This Class should be automaticly controlled by JingleSession. 034 * But you could also use in any VOIP application. 035 * For better NAT Traversal support this implementation don't support only receive or only transmit. 036 * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit() 037 * 038 * @author Thiago Camargo 039 */ 040public class AudioMediaSession extends JingleMediaSession { 041 042 private static final Logger LOGGER = Logger.getLogger(AudioMediaSession.class.getName()); 043 044 private AudioChannel audioChannel; 045 046 /** 047 * Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates 048 * 049 * @param payloadType Payload of the jmf 050 * @param remote the remote information. The candidate that the jmf will be sent to. 051 * @param local the local information. The candidate that will receive the jmf 052 * @param locator media locator 053 */ 054 public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote, 055 final TransportCandidate local, String locator, JingleSession jingleSession) { 056 super(payloadType, remote, local, locator==null?"dsound://":locator,jingleSession); 057 initialize(); 058 } 059 060 /** 061 * Initialize the Audio Channel to make it able to send and receive audio 062 */ 063 public void initialize() { 064 065 String ip; 066 String localIp; 067 int localPort; 068 int remotePort; 069 070 if (this.getLocal().getSymmetric() != null) { 071 ip = this.getLocal().getIp(); 072 localIp = this.getLocal().getLocalIp(); 073 localPort = getFreePort(); 074 remotePort = this.getLocal().getSymmetric().getPort(); 075 076 LOGGER.fine(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort); 077 078 } 079 else { 080 ip = this.getRemote().getIp(); 081 localIp = this.getLocal().getLocalIp(); 082 localPort = this.getLocal().getPort(); 083 remotePort = this.getRemote().getPort(); 084 } 085 086 audioChannel = new AudioChannel(new MediaLocator(this.getMediaLocator()), localIp, ip, localPort, remotePort, AudioFormatUtils.getAudioFormat(this.getPayloadType()),this); 087 } 088 089 /** 090 * Starts transmission and for NAT Traversal reasons start receiving also. 091 */ 092 public void startTrasmit() { 093 audioChannel.start(); 094 } 095 096 /** 097 * Set transmit activity. If the active is true, the instance should trasmit. 098 * If it is set to false, the instance should pause transmit. 099 * 100 * @param active active state 101 */ 102 public void setTrasmit(boolean active) { 103 audioChannel.setTrasmit(active); 104 } 105 106 /** 107 * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf 108 */ 109 public void startReceive() { 110 // Do nothing 111 } 112 113 /** 114 * Stops transmission and for NAT Traversal reasons stop receiving also. 115 */ 116 public void stopTrasmit() { 117 if (audioChannel != null) 118 audioChannel.stop(); 119 } 120 121 /** 122 * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf 123 */ 124 public void stopReceive() { 125 // Do nothing 126 } 127 128 /** 129 * Obtain a free port we can use. 130 * 131 * @return A free port number. 132 */ 133 protected int getFreePort() { 134 ServerSocket ss; 135 int freePort = 0; 136 137 for (int i = 0; i < 10; i++) { 138 freePort = (int) (10000 + Math.round(Math.random() * 10000)); 139 freePort = freePort % 2 == 0 ? freePort : freePort + 1; 140 try { 141 ss = new ServerSocket(freePort); 142 freePort = ss.getLocalPort(); 143 ss.close(); 144 return freePort; 145 } 146 catch (IOException e) { 147 e.printStackTrace(); 148 } 149 } 150 try { 151 ss = new ServerSocket(0); 152 freePort = ss.getLocalPort(); 153 ss.close(); 154 } 155 catch (IOException e) { 156 e.printStackTrace(); 157 } 158 return freePort; 159 } 160 161}