名流时尚服饰 dior 夏季 男装 男士t恤衬衫卫衣休闲裤牛仔裤英伦

socool 搜酷女包◆任选两款正价包包邮◆5周年店庆◆5折疯抢

紫紫 超人气包邮特价创意家居收纳压缩袋饰品服饰配件包包

socool 搜酷女包◆任选两款正价包包邮◆5周年店庆◆5折疯抢

dior 风格 CF Homme 男装 男士t恤衬衫卫衣休闲裤牛仔裤英伦

【1970流行馆】(春装日韩女装瑞丽女装)

非凡瑞丽衣衫 日韩 瑞丽 女装 韩版 2011 欧美 米娜 春夏装 女装

芮诗凯诗国际家居馆\欧美田园家居\复古家居\韩式家居\乡村家居

【徽商联盟】cool-百衣百顺 续写男装 ★冲双冠★两件包邮★

美美箱包专卖店 全场19元起,满58免运费,麦包包韩版女包新款。

import java.io.
*;
import java.awt.
*;
import java.net.
*;
import java.awt.
event.*;
import java.util.Vector;

import javax.media.
*;
import javax.media.rtp.
*;
import javax.media.rtp.
event.*;
import javax.media.rtp.rtcp.
*;
import javax.media.protocol.
*;
import javax.media.protocol.DataSource;
import javax.media.format.AudioFormat;
import javax.media.format.VideoFormat;
import javax.media.Format;
import javax.media.format.FormatChangeEvent;
import javax.media.control.BufferControl;


/**
 * AVReceive3 to receive RTP transmission using the RTPConnector.
 
*/
public class AVReceive3 implements ReceiveStreamListener, SessionListener, 
    ControllerListener
{
    String sessions[] 
= null;
    RTPManager mgrs[] 
= null;
    Vector playerWindows 
= null;

    boolean dataReceived 
= false;
    Object dataSync 
= new Object();


    
public AVReceive3(String sessions[]) {
    
this.sessions = sessions;
    }

    
protected boolean initialize() {

        
try {
        mgrs 
= new RTPManager[sessions.length];
        playerWindows 
= new Vector();

        SessionLabel session;

        
// Open the RTP sessions.
        for (int i = 0; i < sessions.length; i++) {

         
// Parse the session addresses.
        try {
            session 
= new SessionLabel(sessions[i]);
        } 
catch (IllegalArgumentException e) {
            System.err.println(
"Failed to parse the session address given: " + sessions[i]);
            
return false;
        }

        System.err.println(
"  - Open RTP session for: addr: " + session.addr + " port: " + session.port + " ttl: " + session.ttl);

        mgrs[i] 
= (RTPManager) RTPManager.newInstance();
        mgrs[i].addSessionListener(
this);
        mgrs[i].addReceiveStreamListener(
this);

        
// Initialize the RTPManager with the RTPSocketAdapter
        mgrs[i].initialize(new RTPSocketAdapter(
                    InetAddress.getByName(session.addr), 
                    session.port, session.ttl));

        
// You can try out some other buffer size to see
        
// if you can get better smoothness.
        BufferControl bc = (BufferControl)mgrs[i].getControl("javax.media.control.BufferControl");
        
if (bc != null)
            bc.setBufferLength(
350);
        }

        } 
catch (Exception e){
            System.err.println(
"Cannot create the RTP Session: " + e.getMessage());
            
return false;
        }

    
// Wait for data to arrive before moving on.

    
long then = System.currentTimeMillis();
    
long waitingPeriod = 30000;  // wait for a maximum of 30 secs.

    
try{
        synchronized (dataSync) {
        
while (!dataReceived && 
            System.currentTimeMillis() 
- then < waitingPeriod) {
            
if (!dataReceived)
            System.err.println(
"  - Waiting for RTP data to arrive基于JMF RTP的音视频传输_ide");
            dataSync.wait(
1000);
        }
        }
    } 
catch (Exception e) {}

    
if (!dataReceived) {
        System.err.println(
"No RTP data was received.");
        close();
        
return false;
    }

        
return true;
    }


    
public boolean isDone() {
    
return playerWindows.size() == 0;
    }


    
/**
     * Close the players and the session managers.
     
*/
    
protected void close() {

    
for (int i = 0; i < playerWindows.size(); i++) {
        
try {
        ((PlayerWindow)playerWindows.elementAt(i)).close();
        } 
catch (Exception e) {}
    }

    playerWindows.removeAllElements();

    
// close the RTP session.
    for (int i = 0; i < mgrs.length; i++) {
        
if (mgrs[i] != null) {
                mgrs[i].removeTargets( 
"Closing session from AVReceive3");
                mgrs[i].dispose();
        mgrs[i] 
= null;
        }
    }
    }


    PlayerWindow find(Player p) {
    
for (int i = 0; i < playerWindows.size(); i++) {
        PlayerWindow pw 
= (PlayerWindow)playerWindows.elementAt(i);
        
if (pw.player == p)
        
return pw;
    }
    
return null;
    }


    PlayerWindow find(ReceiveStream strm) {
    
for (int i = 0; i < playerWindows.size(); i++) {
        PlayerWindow pw 
= (PlayerWindow)playerWindows.elementAt(i);
        
if (pw.stream == strm)
        
return pw;
    }
    
return null;
    }


    
/**
     * SessionListener.
     
*/
    
public synchronized void update(SessionEvent evt) {
    
if (evt instanceof NewParticipantEvent) {
        Participant p 
= ((NewParticipantEvent)evt).getParticipant();
        System.err.println(
"  - A new participant had just joined: " + p.getCNAME());
    }
    }


    
/**
     * ReceiveStreamListener
     
*/
    
public synchronized void update( ReceiveStreamEvent evt) {

    RTPManager mgr 
= (RTPManager)evt.getSource();
    Participant participant 
= evt.getParticipant();    // could be null.
    ReceiveStream stream = evt.getReceiveStream();  // could be null.

    
if (evt instanceof RemotePayloadChangeEvent) {
     
        System.err.println(
"  - Received an RTP PayloadChangeEvent.");
        System.err.println(
"Sorry, cannot handle payload change.");
        System.exit(
0);

    }
    
    
else if (evt instanceof NewReceiveStreamEvent) {

        
try {
        stream 
= ((NewReceiveStreamEvent)evt).getReceiveStream();
        DataSource ds 
= stream.getDataSource();

        
// Find out the formats.
        RTPControl ctl = (RTPControl)ds.getControl("javax.media.rtp.RTPControl");
        
if (ctl != null){
            System.err.println(
"  - Recevied new RTP stream: " + ctl.getFormat());
        } 
else
            System.err.println(
"  - Recevied new RTP stream");

        
if (participant == null)
            System.err.println(
"      The sender of this stream had yet to be identified.");
        
else {
            System.err.println(
"      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();
        PlayerWindow pw 
= new PlayerWindow(p, stream);
        playerWindows.addElement(pw);

        
// Notify intialize() that a new stream had arrived.
        synchronized (dataSync) {
            dataReceived 
= true;
            dataSync.notifyAll();
        }

        } 
catch (Exception e) {
        System.err.println(
"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.media.rtp.RTPControl");
        System.err.println(
"  - The previously unidentified stream ");
        
if (ctl != null)
            System.err.println(
"      " + ctl.getFormat());
        System.err.println(
"      had now been identified as sent by: " + participant.getCNAME());
         }
    }

    
else if (evt instanceof ByeEvent) {

         System.err.println(
"  - Got \"bye\" from: " + participant.getCNAME());
         PlayerWindow pw 
= find(stream);
         
if (pw != null) {
        pw.close();
        playerWindows.removeElement(pw);
         }
    }

    }


    
/**
     * 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) {
        PlayerWindow pw 
= find(p);
        
if (pw == null) {
        
// Some strange happened.
        System.err.println("Internal error!");
        System.exit(
-1);
        }
        pw.initialize();
        pw.setVisible(
true);
        p.start();
    }

    
if (ce instanceof ControllerErrorEvent) {
        p.removeControllerListener(
this);
        PlayerWindow pw 
= find(p);
        
if (pw != null) {
        pw.close();    
        playerWindows.removeElement(pw);
        }
        System.err.println(
"AVReceive3 internal error: " + ce);
    }

    }


    
/**
     * A utility class to parse the session addresses.
     
*/
    
class SessionLabel {

    
public String addr = null;
    
public int port;
    
public int ttl = 1;

    SessionLabel(String session) throws IllegalArgumentException {

        
int off;
        String portStr 
= null, ttlStr = null;

        
if (session != null && session.length() > 0) {
        
while (session.length() > 1 && session.charAt(0== '/')
            session 
= session.substring(1);

        
// Now see if there's a addr specified.
        off = session.indexOf('/');
        
if (off == -1) {
            
if (!session.equals(""))
            addr 
= session;
        } 
else {
            addr 
= session.substring(0, off);
            session 
= session.substring(off + 1);
            
// Now see if there's a port specified
            off = session.indexOf('/');
            
if (off == -1) {
            
if (!session.equals(""))
                portStr 
= session;
            } 
else {
            portStr 
= session.substring(0, off);
            session 
= session.substring(off + 1);
            
// Now see if there's a ttl specified
            off = session.indexOf('/');
            
if (off == -1) {
                
if (!session.equals(""))
                ttlStr 
= session;
            } 
else {
                ttlStr 
= session.substring(0, off);
            }
            }
        }
        }

        
if (addr == null)
        
throw new IllegalArgumentException();

        
if (portStr != null) {
        
try {
            Integer integer 
= Integer.valueOf(portStr);
            
if (integer != null)
            port 
= integer.intValue();
        } 
catch (Throwable t) {
            
throw new IllegalArgumentException();
        }
        } 
else
        
throw new IllegalArgumentException();

        
if (ttlStr != null) {
        
try {
            Integer integer 
= Integer.valueOf(ttlStr);
            
if (integer != null)
            ttl 
= integer.intValue();
        } 
catch (Throwable t) {
            
throw new IllegalArgumentException();
        }
        }
    }
    }


    
/**
     * GUI classes for the Player.
     
*/
    
class PlayerWindow extends Frame {

    Player player;
    ReceiveStream stream;

    PlayerWindow(Player p, ReceiveStream strm) {
        player 
= p;
        stream 
= strm;
    }

    
public void initialize() {
        add(
new PlayerPanel(player));
    }

    
public void close() {
        player.close();
        setVisible(
false);
        dispose();
    }

    
public void addNotify() {
        super.addNotify();
        pack();
    }
    }


    
/**
     * GUI classes for the Player.
     
*/
    
class PlayerPanel extends Panel {

    Component vc, cc;

    PlayerPanel(Player p) {
        setLayout(
new BorderLayout());
        
if ((vc = p.getVisualComponent()) != null)
        add(
"Center", vc);
        
if ((cc = p.getControlPanelComponent()) != null)
        add(
"South", cc);
    }

    
public Dimension getPreferredSize() {
        
int w = 0, h = 0;
        
if (vc != null) {
        Dimension size 
= vc.getPreferredSize();
        w 
= size.width;
        h 
= size.height;
        }
        
if (cc != null) {
        Dimension size 
= cc.getPreferredSize();
        
if (w == 0)
            w 
= size.width;
        h 
+= size.height;
        }
        
if (w < 160)
        w 
= 160;
        
return new Dimension(w, h);
    }
    }


    
public static void main(String argv[]) {
    
if (argv.length == 0)
        prUsage();

    AVReceive3 avReceive 
= new AVReceive3(argv);
    
if (!avReceive.initialize()) {
        System.err.println(
"Failed to initialize the sessions.");
        System.exit(
-1);
    }

    
// Check to see if AVReceive3 is done.
    try {
        
while (!avReceive.isDone())
        Thread.sleep(
1000);
    } 
catch (Exception e) {}

    System.err.println(
"Exiting AVReceive3");
    }


    
static void prUsage() {
    System.err.println(
"Usage: AVReceive3 <session> <session> 基于JMF RTP的音视频传输_ide");
    System.err.println(
"     <session>: <address>/<port>/<ttl>");
    System.exit(
0);
    }

}
// end of AVReceive3 

发送端代码:

import java.awt.*;
import java.io.
*;
import java.net.InetAddress;
import javax.media.
*;
import javax.media.protocol.
*;
import javax.media.protocol.DataSource;
import javax.media.format.
*;
import javax.media.control.TrackControl;
import javax.media.control.QualityControl;
import javax.media.rtp.
*;
import javax.media.rtp.rtcp.
*;
import com.sun.media.rtp.
*;

public class AVTransmit3 {

    
// Input MediaLocator
    
// Can be a file or http or capture source
    private MediaLocator locator;
    
private String ipAddress;
    
private int portBase;

    
private Processor processor = null;
    
private RTPManager rtpMgrs[];
    
private DataSource dataOutput = null;
    
    
public AVTransmit3(MediaLocator locator,
             String ipAddress,
             String pb,
             Format format) {
    
    
this.locator = locator;
    
this.ipAddress = ipAddress;
    Integer integer 
= Integer.valueOf(pb);
    
if (integer != null)
        
this.portBase = integer.intValue();
    }

    
/**
     * Starts the transmission. Returns null if transmission started ok.
     * Otherwise it returns a string with the reason why the setup failed.
     
*/
    
public synchronized String start() {
    String result;

    
// Create a processor for the specified media locator
    
// and program it to output JPEG/RTP
    result = createProcessor();
    
if (result != null)
        
return result;

    
// Create an RTP session to transmit the output of the
    
// processor to the specified IP address and port no.
    result = createTransmitter();
    
if (result != null) {
        processor.close();
        processor 
= null;
        
return result;
    }

    
// Start the transmission
    processor.start();
    
    
return null;
    }

    
/**
     * Stops the transmission if already started
     
*/
    
public void stop() {
    synchronized (
this) {
        
if (processor != null) {
        processor.stop();
        processor.close();
        processor 
= null;
        
for (int i = 0; i < rtpMgrs.length; i++) {
            rtpMgrs[i].removeTargets( 
"Session ended.");
            rtpMgrs[i].dispose();
        }
        }
    }
    }

    
private String createProcessor() {
    
if (locator == null)
        
return "Locator is null";

    DataSource ds;
    DataSource clone;

    
try {
        ds 
= javax.media.Manager.createDataSource(locator);
    } 
catch (Exception e) {
        
return "Couldn't create DataSource";
    }

    
// Try to create a processor to handle the input media locator
    try {
        processor 
= javax.media.Manager.createProcessor(ds);
    } 
catch (NoProcessorException npe) {
        
return "Couldn't create processor";
    } 
catch (IOException ioe) {
        
return "IOException creating processor";
    } 

    
// Wait for it to configure
    boolean result = waitForState(processor, Processor.Configured);
    
if (result == false)
        
return "Couldn't configure processor";

    
// Get the tracks from the processor
    TrackControl [] tracks = processor.getTrackControls();

    
// Do we have atleast one track?
    if (tracks == null || tracks.length < 1)
        
return "Couldn't find tracks in processor";

    
// Set the output content descriptor to RAW_RTP
    
// This will limit the supported formats reported from
    
// Track.getSupportedFormats to only valid RTP formats.
    ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
    processor.setContentDescriptor(cd);

    Format supported[];
    Format chosen;
    boolean atLeastOneTrack 
= false;

    
// Program the tracks.
    for (int i = 0; i < tracks.length; i++) {
        Format format 
= tracks[i].getFormat();
        
if (tracks[i].isEnabled()) {

        supported 
= tracks[i].getSupportedFormats();

        
// We've set the output content to the RAW_RTP.
        
// So all the supported formats should work with RTP.
        
// We'll just pick the first one.

        
if (supported.length > 0) {
            
if (supported[0] instanceof VideoFormat) {
            
// For video formats, we should double check the
            
// sizes since not all formats work in all sizes.
            chosen = checkForVideoSizes(tracks[i].getFormat(), 
                            supported[
0]);
            } 
else
            chosen 
= supported[0];
            tracks[i].setFormat(chosen);
            System.err.println(
"Track " + i + " is set to transmit as:");
            System.err.println(
"  " + chosen);
            atLeastOneTrack 
= true;
        } 
else
            tracks[i].setEnabled(
false);
        } 
else
        tracks[i].setEnabled(
false);
    }

    
if (!atLeastOneTrack)
        
return "Couldn't set any of the tracks to a valid RTP format";

    
// Realize the processor. This will internally create a flow
    
// graph and attempt to create an output datasource for JPEG/RTP
    
// audio frames.
    result = waitForState(processor, Controller.Realized);
    
if (result == false)
        
return "Couldn't realize processor";

    
// Set the JPEG quality to .5.
    setJPEGQuality(processor, 0.5f);

    
// Get the output data source of the processor
    dataOutput = processor.getDataOutput();

    
return null;
    }


    
/**
     * Use the RTPManager API to create sessions for each media 
     * track of the processor.
     
*/
    
private String createTransmitter() {

    
// Cheated.  Should have checked the type.
    PushBufferDataSource pbds = (PushBufferDataSource)dataOutput;
    PushBufferStream pbss[] 
= pbds.getStreams();

    rtpMgrs 
= new RTPManager[pbss.length];
    SendStream sendStream;
    
int port;
    SourceDescription srcDesList[];

    
for (int i = 0; i < pbss.length; i++) {
        
try {
        rtpMgrs[i] 
= RTPManager.newInstance();        

        port 
= portBase + 2*i;
        
        
// Initialize the RTPManager with the RTPSocketAdapter
        rtpMgrs[i].initialize(new RTPSocketAdapter(
                    InetAddress.getByName(ipAddress), 
                    port));

        System.err.println( 
"Created RTP session: " + ipAddress + " " + port);
        
        sendStream 
= rtpMgrs[i].createSendStream(dataOutput, i);        
        sendStream.start();
        } 
catch (Exception  e) {
        
return e.getMessage();
        }
    }

    
return null;
    }


    
/**
     * For JPEG and H263, we know that they only work for particular
     * sizes.  So we'll perform extra checking here to make sure they
     * are of the right sizes.
     
*/
    Format checkForVideoSizes(Format original, Format supported) {

    
int width, height;
    Dimension size 
= ((VideoFormat)original).getSize();
    Format jpegFmt 
= new Format(VideoFormat.JPEG_RTP);
    Format h263Fmt 
= new Format(VideoFormat.H263_RTP);

    
if (supported.matches(jpegFmt)) {
        
// For JPEG, make sure width and height are divisible by 8.
        width = (size.width % 8 == 0 ? size.width :
                (
int)(size.width / 8* 8);
        height 
= (size.height % 8 == 0 ? size.height :
                (
int)(size.height / 8* 8);
    } 
else if (supported.matches(h263Fmt)) {
        
// For H.263, we only support some specific sizes.
        if (size.width < 128) {
        width 
= 128;
        height 
= 96;
        } 
else if (size.width < 176) {
        width 
= 176;
        height 
= 144;
        } 
else {
        width 
= 352;
        height 
= 288;
        }
    } 
else {
        
// We don't know this particular format.  We'll just
        
// leave it alone then.
        return supported;
    }

    
return (new VideoFormat(null
                
new Dimension(width, height), 
                Format.NOT_SPECIFIED,
                
null,
                Format.NOT_SPECIFIED)).intersects(supported);
    }


    
/**
     * Setting the encoding quality to the specified value on the JPEG encoder.
     * 0.5 is a good default.
     
*/
    
void setJPEGQuality(Player p, float val) {

    Control cs[] 
= p.getControls();
    QualityControl qc 
= null;
    VideoFormat jpegFmt 
= new VideoFormat(VideoFormat.JPEG);

    
// Loop through the controls to find the Quality control for
     
// the JPEG encoder.
    for (int i = 0; i < cs.length; i++) {

        
if (cs[i] instanceof QualityControl &&
        cs[i] instanceof Owned) {
        Object owner 
= ((Owned)cs[i]).getOwner();

        
// Check to see if the owner is a Codec.
        
// Then check for the output format.
        if (owner instanceof Codec) {
            Format fmts[] 
= ((Codec)owner).getSupportedOutputFormats(null);
            
for (int j = 0; j < fmts.length; j++) {
            
if (fmts[j].matches(jpegFmt)) {
                qc 
= (QualityControl)cs[i];
                    qc.setQuality(val);
                System.err.println(
"- Setting quality to " + 
                    val 
+ " on " + qc);
                
break;
            }
            }
        }
        
if (qc != null)
            
break;
        }
    }
    }


    
/****************************************************************
     * Convenience methods to handle processor's state changes.
     ***************************************************************
*/
    
    
private Integer stateLock = new Integer(0);
    
private boolean failed = false;
    
    Integer getStateLock() {
    
return stateLock;
    }

    
void setFailed() {
    failed 
= true;
    }
    
    
private synchronized boolean waitForState(Processor p, int state) {
    p.addControllerListener(
new StateListener());
    failed 
= false;

    
// Call the required method on the processor
    if (state == Processor.Configured) {
        p.configure();
    } 
else if (state == Processor.Realized) {
        p.realize();
    }
    
    
// Wait until we get an event that confirms the
    
// success of the method, or a failure event.
    
// See StateListener inner class
    while (p.getState() < state && !failed) {
        synchronized (getStateLock()) {
        
try {
            getStateLock().wait();
        } 
catch (InterruptedException ie) {
            
return false;
        }
        }
    }

    
if (failed)
        
return false;
    
else
        
return true;
    }

    
/****************************************************************
     * Inner Classes
     ***************************************************************
*/

    
class StateListener implements ControllerListener {

    
public void controllerUpdate(ControllerEvent ce) {

        
// If there was an error during configure or
        
// realize, the processor will be closed
        if (ce instanceof ControllerClosedEvent)
        setFailed();

        
// All controller events, send a notification
        
// to the waiting thread in waitForState method.
        if (ce instanceof ControllerEvent) {
        synchronized (getStateLock()) {
            getStateLock().notifyAll();
        }
        }
    }
    }


    
/****************************************************************
     * Sample Usage for AVTransmit3 class
     ***************************************************************
*/
    
    
public static void main(String [] args) {
    
// We need three parameters to do the transmission
    
// For example,
    
//   java AVTransmit3 file:/C:/media/test.mov  129.130.131.132 42050
    
    
if (args.length < 3) {
        prUsage();
    }

    Format fmt 
= null;
    
int i = 0;

    
// Create a audio transmit object with the specified params.
    AVTransmit3 at = new AVTransmit3(new MediaLocator(args[i]),
                         args[i
+1], args[i+2], fmt);
    
// Start the transmission
    String result = at.start();

    
// result will be non-null if there was an error. The return
    
// value is a String describing the possible error. Print it.
    if (result != null) {
        System.err.println(
"Error : " + result);
        System.exit(
0);
    }
    
    System.err.println(
"Start transmission for 60 seconds基于JMF RTP的音视频传输_ide");

    
// Transmit for 60 seconds and then close the processor
    
// This is a safeguard when using a capture data source
    
// so that the capture device will be properly released
    
// before quitting.
    
// The right thing to do would be to have a GUI with a
    
// "Stop" button that would call stop on AVTransmit3
    try {
        Thread.currentThread().sleep(
60000);
    } 
catch (InterruptedException ie) {
    }

    
// Stop the transmission
    at.stop();
    
    System.err.println(
"基于JMF RTP的音视频传输_idetransmission ended.");

    System.exit(
0);
    }


    
static void prUsage() {
    System.err.println(
"Usage: AVTransmit3 <sourceURL> <destIP> <destPortBase>");
    System.err.println(
"     <sourceURL>: input URL or file name");
    System.err.println(
"     <destIP>: multicast, broadcast or unicast IP address for the transmission");
    System.err.println(
"     <destPortBase>: network port numbers for the transmission.");
    System.err.println(
"                     The first track will use the destPortBase.");
    System.err.println(
"                     The next track will use destPortBase + 2 and so on.\n");
    System.exit(
0);
    }
}

 

底层传输部分代码:

import java.io.IOException;
import java.net.InetAddress;
import java.net.DatagramSocket;
import java.net.MulticastSocket;
import java.net.DatagramPacket;
import java.net.SocketException;

import javax.media.protocol.DataSource;
import javax.media.protocol.PushSourceStream;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.SourceTransferHandler;
import javax.media.rtp.RTPConnector;
import javax.media.rtp.OutputDataStream;


/**
 * An implementation of RTPConnector based on UDP sockets.
 
*/
public class RTPSocketAdapter implements RTPConnector {

    DatagramSocket dataSock;
    DatagramSocket ctrlSock;

    InetAddress addr;
    
int port;

    SockInputStream dataInStrm 
= null, ctrlInStrm = null;
    SockOutputStream dataOutStrm 
= null, ctrlOutStrm = null;


    
public RTPSocketAdapter(InetAddress addr, int port) throws IOException {
    
this(addr, port, 1);
    }

    
public RTPSocketAdapter(InetAddress addr, int port, int ttl) throws IOException {

    
try {

        
if (addr.isMulticastAddress()) {
        dataSock 
= new MulticastSocket(port);
        ctrlSock 
= new MulticastSocket(port+1);
        ((MulticastSocket)dataSock).joinGroup(addr);
        ((MulticastSocket)dataSock).setTimeToLive(ttl);
        ((MulticastSocket)ctrlSock).joinGroup(addr);
        ((MulticastSocket)ctrlSock).setTimeToLive(ttl);
        } 
else {
        dataSock 
= new DatagramSocket(port, InetAddress.getLocalHost());
        ctrlSock 
= new DatagramSocket(port+1, InetAddress.getLocalHost());
        }


    } 
catch (SocketException e) {
        
throw new IOException(e.getMessage());
    }

    
this.addr = addr;
    
this.port = port;
    }

    
/**
     * Returns an input stream to receive the RTP data. 
     
*/
    
public PushSourceStream getDataInputStream() throws IOException {
    
if (dataInStrm == null) {
        dataInStrm 
= new SockInputStream(dataSock, addr, port);
        dataInStrm.start();
    }
    
return dataInStrm;
    }

    
/**
     * Returns an output stream to send the RTP data.
     
*/
    
public OutputDataStream getDataOutputStream() throws IOException {
    
if (dataOutStrm == null)
        dataOutStrm 
= new SockOutputStream(dataSock, addr, port);
    
return dataOutStrm;
    }

    
/**
     * Returns an input stream to receive the RTCP data.
     
*/
    
public PushSourceStream getControlInputStream() throws IOException {
    
if (ctrlInStrm == null) {
        ctrlInStrm 
= new SockInputStream(ctrlSock, addr, port+1);
        ctrlInStrm.start();
    }
    
return ctrlInStrm;
    }

    
/**
     * Returns an output stream to send the RTCP data.
     
*/
    
public OutputDataStream getControlOutputStream() throws IOException {
    
if (ctrlOutStrm == null)
        ctrlOutStrm 
= new SockOutputStream(ctrlSock, addr, port+1);
    
return ctrlOutStrm;
    }

    
/**
     * Close all the RTP, RTCP streams.
     
*/
    
public void close() {
    
if (dataInStrm != null)
        dataInStrm.kill();
    
if (ctrlInStrm != null)
        ctrlInStrm.kill();
    dataSock.close();
    ctrlSock.close();
    }

    
/**
     * Set the receive buffer size of the RTP data channel.
     * This is only a hint to the implementation.  The actual implementation
     * may not be able to do anything to this.
     
*/
    
public void setReceiveBufferSize( int size) throws IOException {
    dataSock.setReceiveBufferSize(size);
    }

    
/**
     * Get the receive buffer size set on the RTP data channel.
     * Return -1 if the receive buffer size is not applicable for 
     * the implementation.
     
*/
    
public int getReceiveBufferSize() {
    
try {
        
return dataSock.getReceiveBufferSize();
    } 
catch (Exception e) {
        
return -1;
    }
    }

    
/**
     * Set the send buffer size of the RTP data channel.
     * This is only a hint to the implementation.  The actual implementation
     * may not be able to do anything to this.
     
*/
    
public void setSendBufferSize( int size) throws IOException {
    dataSock.setSendBufferSize(size);
    }

    
/**
     * Get the send buffer size set on the RTP data channel.
     * Return -1 if the send buffer size is not applicable for 
     * the implementation.
     
*/
    
public int getSendBufferSize() {
    
try {
        
return dataSock.getSendBufferSize();
    } 
catch (Exception e) {
        
return -1;
    }
    }

    
/**
     * Return the RTCP bandwidth fraction.  This value is used to
     * initialize the RTPManager.  Check RTPManager for more detauls.
     * Return -1 to use the default values.
     
*/
    
public double getRTCPBandwidthFraction() {
    
return -1;
    }

    
/**
     * Return the RTCP sender bandwidth fraction.  This value is used to
     * initialize the RTPManager.  Check RTPManager for more detauls.
     * Return -1 to use the default values.
     
*/
    
public double getRTCPSenderBandwidthFraction() {
    
return -1;
    }


    
/**
     * An inner class to implement an OutputDataStream based on UDP sockets.
     
*/
    
class SockOutputStream implements OutputDataStream {

    DatagramSocket sock;
    InetAddress addr;
    
int port;

    
public SockOutputStream(DatagramSocket sock, InetAddress addr, int port) {
        
this.sock = sock;
        
this.addr = addr;
        
this.port = port;
    }

    
public int write(byte data[], int offset, int len) {
        
try {
        sock.send(
new DatagramPacket(data, offset, len, addr, port));
        } 
catch (Exception e) {
        
return -1;
        }
        
return len;
    }
    }


    
/**
     * An inner class to implement an PushSourceStream based on UDP sockets.
     
*/
    
class SockInputStream extends Thread implements PushSourceStream {

    DatagramSocket sock;
    InetAddress addr;
    
int port;
    boolean done 
= false;
    boolean dataRead 
= false;

    SourceTransferHandler sth 
= null;

    
public SockInputStream(DatagramSocket sock, InetAddress addr, int port) {
        
this.sock = sock;
        
this.addr = addr;
        
this.port = port;
    }

    
public int read(byte buffer[], int offset, int length) {
        DatagramPacket p 
= new DatagramPacket(buffer, offset, length, addr, port);
        
try {
        sock.receive(p);
        } 
catch (IOException e) {
        
return -1;
        }
        synchronized (
this) {
        dataRead 
= true;
        notify();
        }
        
return p.getLength();
    }

    
public synchronized void start() {
        super.start();
        
if (sth != null) {
        dataRead 
= true;
        notify();
        }
    }

    
public synchronized void kill() {
        done 
= true;
        notify();
    }

    
public int getMinimumTransferSize() {
        
return 2 * 1024;    // twice the MTU size, just to be safe.
    }

    
public synchronized void setTransferHandler(SourceTransferHandler sth) {
        
this.sth = sth;
        dataRead 
= true;
        notify();
    }

    
// Not applicable.
    public ContentDescriptor getContentDescriptor() {
        
return null;
    }

    
// Not applicable.
    public long getContentLength() {
        
return LENGTH_UNKNOWN;
    }

    
// Not applicable.
    public boolean endOfStream() {
        
return false;
    }

    
// Not applicable.
    public Object[] getControls() {
        
return new Object[0];
    }

    
// Not applicable.
    public Object getControl(String type) {
        
return null;
    }

    
/**
     * Loop and notify the transfer handler of new data.
     
*/
    
public void run() {
        
while (!done) {

        synchronized (
this) {
            
while (!dataRead && !done) {
            
try {
                wait();
            } 
catch (InterruptedException e) { }
            }
            dataRead 
= false;
        }

        
if (sth != null && !done) {
            sth.transferData(
this);
        }
        }
    }
    }
}