名流时尚服饰 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
"
);
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>
"
);
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
"
);
//
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(
"
transmission 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
);
}
}
}
}
}