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.jingleold.mediaimpl.jmf; 018 019import java.io.IOException; 020import java.net.ServerSocket; 021import java.util.logging.Level; 022import java.util.logging.Logger; 023 024import javax.media.MediaLocator; 025 026import org.jivesoftware.smackx.jingleold.JingleSession; 027import org.jivesoftware.smackx.jingleold.media.JingleMediaSession; 028import org.jivesoftware.smackx.jingleold.media.PayloadType; 029import org.jivesoftware.smackx.jingleold.nat.TransportCandidate; 030 031/** 032 * This Class implements a complete JingleMediaSession. 033 * It sould be used to transmit and receive audio captured from the Mic. 034 * This Class should be automaticly controlled by JingleSession. 035 * But you could also use in any VOIP application. 036 * For better NAT Traversal support this implementation don't support only receive or only transmit. 037 * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit() 038 * 039 * @author Thiago Camargo 040 */ 041public class AudioMediaSession extends JingleMediaSession { 042 043 private static final Logger LOGGER = Logger.getLogger(AudioMediaSession.class.getName()); 044 045 private AudioChannel audioChannel; 046 047 /** 048 * Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates. 049 * 050 * @param payloadType Payload of the jmf 051 * @param remote the remote information. The candidate that the jmf will be sent to. 052 * @param local the local information. The candidate that will receive the jmf 053 * @param locator media locator 054 */ 055 public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote, 056 final TransportCandidate local, String locator, JingleSession jingleSession) { 057 super(payloadType, remote, local, locator==null?"dsound://":locator,jingleSession); 058 initialize(); 059 } 060 061 /** 062 * Initialize the Audio Channel to make it able to send and receive audio. 063 */ 064 @Override 065 public void initialize() { 066 067 String ip; 068 String localIp; 069 int localPort; 070 int remotePort; 071 072 if (this.getLocal().getSymmetric() != null) { 073 ip = this.getLocal().getIp(); 074 localIp = this.getLocal().getLocalIp(); 075 localPort = getFreePort(); 076 remotePort = this.getLocal().getSymmetric().getPort(); 077 078 LOGGER.fine(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort); 079 080 } 081 else { 082 ip = this.getRemote().getIp(); 083 localIp = this.getLocal().getLocalIp(); 084 localPort = this.getLocal().getPort(); 085 remotePort = this.getRemote().getPort(); 086 } 087 088 audioChannel = new AudioChannel(new MediaLocator(this.getMediaLocator()), localIp, ip, localPort, remotePort, AudioFormatUtils.getAudioFormat(this.getPayloadType()),this); 089 } 090 091 /** 092 * Starts transmission and for NAT Traversal reasons start receiving also. 093 */ 094 @Override 095 public void startTrasmit() { 096 audioChannel.start(); 097 } 098 099 /** 100 * Set transmit activity. If the active is true, the instance should trasmit. 101 * If it is set to false, the instance should pause transmit. 102 * 103 * @param active active state 104 */ 105 @Override 106 public void setTrasmit(boolean active) { 107 audioChannel.setTrasmit(active); 108 } 109 110 /** 111 * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf 112 */ 113 @Override 114 public void startReceive() { 115 // Do nothing 116 } 117 118 /** 119 * Stops transmission and for NAT Traversal reasons stop receiving also. 120 */ 121 @Override 122 public void stopTrasmit() { 123 if (audioChannel != null) 124 audioChannel.stop(); 125 } 126 127 /** 128 * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf 129 */ 130 @Override 131 public void stopReceive() { 132 // Do nothing 133 } 134 135 /** 136 * Obtain a free port we can use. 137 * 138 * @return A free port number. 139 */ 140 protected int getFreePort() { 141 ServerSocket ss; 142 int freePort = 0; 143 144 for (int i = 0; i < 10; i++) { 145 freePort = (int) (10000 + Math.round(Math.random() * 10000)); 146 freePort = freePort % 2 == 0 ? freePort : freePort + 1; 147 try { 148 ss = new ServerSocket(freePort); 149 freePort = ss.getLocalPort(); 150 ss.close(); 151 return freePort; 152 } 153 catch (IOException e) { 154 LOGGER.log(Level.WARNING, "exception", e); 155 } 156 } 157 try { 158 ss = new ServerSocket(0); 159 freePort = ss.getLocalPort(); 160 ss.close(); 161 } 162 catch (IOException e) { 163 LOGGER.log(Level.WARNING, "exception", e); 164 } 165 return freePort; 166 } 167 168}