001: /*
002: *
003: * Copyright (c) 2000-2001 Silvere Martin-Michiellot All Rights Reserved.
004: *
005: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
006: * royalty free, license to use, modify but not to redistribute this
007: * software in source and binary code form,
008: * provided that i) this copyright notice and license appear on all copies of
009: * the software; and ii) Licensee does not utilize the software in a manner
010: * which is disparaging to Silvere Martin-Michiellot.
011: *
012: * This software is provided "AS IS," without a warranty of any kind. ALL
013: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
014: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
015: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. Silvere Martin-Michiellot
016: * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
017: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
018: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
019: * Silvere Martin-Michiellot OR ITS LICENSORS BE LIABLE
020: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
021: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
022: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
023: * OR INABILITY TO USE SOFTWARE, EVEN IF Silvere Martin-Michiellot HAS BEEN
024: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
025: *
026: * This software is not designed or intended for use in on-line control of
027: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
028: * the design, construction, operation or maintenance of any nuclear
029: * facility. Licensee represents and warrants that it will not use or
030: * redistribute the Software for such purposes.
031: *
032: *
033: */
034:
035: package com.db.media.rtp;
036:
037: import javax.media.rtp.*;
038: import javax.media.*;
039: import javax.media.protocol.*;
040: import java.io.*;
041: import java.net.*;
042: import com.sun.media.ui.*;
043:
044: /**
045: * A RTP over UDP player which will receive RTP UDP packets and stream
046: * them to the JMF RTP Player or (RTPSM) which is not aware of the
047: * underlying network/transport protocol. This sample uses the
048: * interfaces defined in javax.media.rtp.RTPSocket and its related classes.
049: */
050: public class VideoChatRTP implements ControllerListener {
051:
052: /**
053: * RTP Session address, multicast, unicast or broadcast address
054: */
055: String address = "";
056: /**
057: * RTP Session port
058: */
059: int port = 49200;
060: /**en
061: * Media Type i.e. one of audio or video
062: */
063: String media = "video";
064:
065: /////////////DO NOT CHANGE ANYTHING BELOW THIS LINE//////////////////////////
066:
067: // our main rtpsocket abstraction to which we will create and send
068: // to the Manager for appropriate handler creation
069: RTPSocket rtpsocket = null;
070: // the control RTPIODataSource of the RTPSocket above
071: RTPPushDataSource rtcpsource = null;
072: // The GUI to handle our player
073: PlayerWindow playerWindow;
074: // The handler created for our RTP session, as returned by the Manager
075: Player player = null;
076: // maximum size of buffer for UDP receive from the sockets
077: private int maxsize = 2000;
078:
079: UDPHandler rtp = null;
080: UDPHandler rtcp = null;
081:
082: public VideoChatRTP(String address, int port) {
083:
084: this .address = address;
085: this .port = port;
086: try {
087: // create the RTPSocket
088: rtpsocket = new RTPSocket();
089: // set its content type : rtpraw/video for a video session and
090: // rtpraw/audio for an audio session
091: String content = "rtpraw/" + media;
092: rtpsocket.setContentType(content);
093: // set the RTP Session address and port of the RTP data
094: rtp = new UDPHandler(address, port);
095: // set the above UDP Handler to be the sourcestream of the rtpsocket
096: rtpsocket.setOutputStream(rtp);
097: // set the RTP Session address and port of the RTCP data
098: rtcp = new UDPHandler(address, port + 1);
099: // get a handle over the RTCP Datasource so that we can set
100: // the sourcestream and deststream of this source to the rtcp
101: // udp handler we created above.
102: rtcpsource = rtpsocket.getControlChannel();
103: // Since we intend to send RTCP packets from the network to
104: // RTPSM and vice-versa, we need to set the RTCP UDP handler
105: // as both the input and output stream of the rtcpsource.
106: rtcpsource.setOutputStream(rtcp);
107: rtcpsource.setInputStream(rtcp);
108: // set the dynamic info on the RTPSocket, so that we can
109: // playback DVI as well
110: if (media.equals("audio"))
111: EncodingUtil.Init(rtpsocket);
112: // start & connect the RTP socket data source before creating
113: // the player
114: try {
115: rtpsocket.connect();
116: player = Manager.createPlayer(rtpsocket);
117: //rtpsocket.start();
118: } catch (NoPlayerException e) {
119: System.err.println(e.getMessage());
120: // e.printStackTrace();
121: return;
122: } catch (IOException e) {
123: System.err.println(e.getMessage());
124: // e.printStackTrace();
125: return;
126: }
127: if (player != null) {
128: player.addControllerListener(this );
129: // send this player to out playerwindow
130: playerWindow = new PlayerWindow(player);
131: }
132: } catch (Exception e) {
133: System.out.println("could not connect to RTP stream.");
134: }
135:
136: }
137:
138: public synchronized void controllerUpdate(ControllerEvent ce) {
139:
140: if ((ce instanceof DeallocateEvent)
141: || (ce instanceof ControllerErrorEvent)) {
142: // stop udp handlers
143: if (rtp != null)
144: rtp.close();
145: if (rtcp != null)
146: rtcp.close();
147: }
148:
149: }
150:
151: // method used by inner class UDPHandler to open a datagram or
152: // multicast socket as the case maybe
153: private DatagramSocket InitSocket(String sockaddress, int sockport) {
154:
155: InetAddress addr = null;
156: DatagramSocket sock = null;
157: try {
158: addr = InetAddress.getByName(sockaddress);
159: if (addr.isMulticastAddress()) {
160: MulticastSocket msock = new MulticastSocket(sockport);
161: msock.joinGroup(addr);
162: sock = (DatagramSocket) msock;
163: } else {
164: sock = new DatagramSocket(sockport, addr);
165: }
166: return sock;
167: } catch (SocketException e) {
168: e.printStackTrace();
169: return null;
170: } catch (UnknownHostException e) {
171: e.printStackTrace();
172: return null;
173: } catch (IOException e) {
174: e.printStackTrace();
175: return null;
176: }
177:
178: }// end of InitSocket
179:
180: //INNER CLASS UDPHandler which will receive UDP RTP Packets and
181: //stream them to the handler of the sources stream. IN case of
182: //RTCP , it will also accept RTCP packets and send them on the
183: //underlying network.
184: public class UDPHandler extends Thread implements PushSourceStream,
185: OutputDataStream {
186:
187: DatagramSocket mysock = null;
188: DatagramPacket dp = null;
189: SourceTransferHandler outputhandler = null;
190: String myaddress = null;
191: int myport;
192: boolean closed = false;
193:
194: // in the constructor we open the socket and create the main
195: // UDPHandler thread.
196: public UDPHandler(String haddress, int hport) {
197:
198: myaddress = haddress;
199: myport = hport;
200: mysock = InitSocket(myaddress, myport);
201: setDaemon(true);
202: start();
203:
204: }
205:
206: // the main thread simply receives RTP data packets from the
207: // network and transfer's this data to the output handler of
208: // this stream.
209: public void run() {
210: int len;
211: while (true) {
212: if (closed) {
213: cleanup();
214: return;
215: }
216: try {
217: do {
218: dp = new DatagramPacket(new byte[maxsize],
219: maxsize);
220: mysock.receive(dp);
221: if (closed) {
222: cleanup();
223: return;
224: }
225: len = dp.getLength();
226: if (len > (maxsize >> 1))
227: maxsize = len << 1;
228: } while (len >= dp.getData().length);
229: } catch (Exception e) {
230: cleanup();
231: return;
232: }
233:
234: if (outputhandler != null)
235: outputhandler.transferData(this );
236: }
237: }
238:
239: public void close() {
240: closed = true;
241: }
242:
243: private void cleanup() {
244: mysock.close();
245: stop();
246: }
247:
248: // methods of PushSourceStream
249: public Object[] getControls() {
250: return new Object[0];
251: }
252:
253: public Object getControl(String controlName) {
254: return null;
255: }
256:
257: public ContentDescriptor getContentDescriptor() {
258: return null;
259: }
260:
261: public long getContentLength() {
262: return SourceStream.LENGTH_UNKNOWN;
263: }
264:
265: public boolean endOfStream() {
266: return false;
267: }
268:
269: // method by which data is transferred from the underlying
270: // network to the RTPSM.
271: public int read(byte buffer[], int offset, int length) {
272:
273: System.arraycopy(dp.getData(), 0, buffer, offset, dp
274: .getLength());
275: return dp.getData().length;
276:
277: }
278:
279: public int getMinimumTransferSize() {
280: return dp.getLength();
281: }
282:
283: public void setTransferHandler(
284: SourceTransferHandler transferHandler) {
285: this .outputhandler = transferHandler;
286: }
287:
288: // methods of PushDestStream used by teh RTPSM to transfer
289: // data to the underlying network.
290: public int write(byte[] buffer, int offset, int length) {
291:
292: InetAddress addr = null;
293: try {
294: addr = InetAddress.getByName(myaddress);
295: } catch (UnknownHostException e) {
296: }
297: DatagramPacket dp = new DatagramPacket(buffer, length,
298: addr, myport);
299: try {
300: mysock.send(dp);
301: } catch (IOException e) {
302: }
303: return dp.getLength();
304:
305: }
306:
307: }
308:
309: }
|