Remove advanced attributes processing from SDP/CallPeerMediaHandler classes.

cusax-fix
Sebastien Vincent 17 years ago
parent c6dbc987d8
commit ad07baba07

@ -19,7 +19,7 @@
/**
* Decodes incoming rtp data of type h264 and returns the result frames in RGB
* format.
*
*
* @author Damian Minkov
* @author Lubomir Marinov
*/
@ -376,6 +376,9 @@ public Format[] getSupportedOutputFormats(Format in)
/**
* Utility to perform format matching.
*
* @param in input format
* @param outs array of format
*/
public static Format matches(Format in, Format outs[])
{

@ -190,6 +190,12 @@ else if (MediaDeviceSession
*/
private CsrcTransformEngine csrcEngine;
/**
* Map of advanced attributes.
*/
protected Map<String, String> advancedAttributes =
new Hashtable<String, String>();
/**
* Initializes a new <tt>MediaStreamImpl</tt> instance which will use the
* specified <tt>MediaDevice</tt> for both capture and playback of media
@ -392,6 +398,18 @@ protected CsrcTransformEngine getCsrcEngine()
return csrcEngine;
}
/**
* Set list of advanced attributes.
*
* @param attrs advanced attributes map
*/
public void setAdvancedAttributes(Map<String, String> attrs)
{
if(attrs != null)
{
advancedAttributes.putAll(attrs);
}
}
/**
* Releases the resources allocated by this instance in the course of its
* execution and prepares it to be garbage collected.

@ -15,6 +15,7 @@
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.java.sip.communicator.impl.neomedia.format.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.neomedia.device.ScreenDevice;
import net.java.sip.communicator.service.neomedia.format.*;
/**
@ -154,11 +155,23 @@ public class MediaUtils
Map<String, String> h264FormatParams
= new HashMap<String, String>();
Map<String, String> h264AdvancedParams
Map<String, String> h264AdvancedAttributes
= new HashMap<String, String>();
h264FormatParams.put("packetization-mode", "1");
h264AdvancedParams.put("rtcp-fb", "nack pli");
h264AdvancedAttributes.put("rtcp-fb", "nack pli");
ScreenDevice screen = NeomediaActivator.getMediaServiceImpl().
getDefaultScreenDevice();
java.awt.Dimension res = null;
if(screen != null)
{
res = screen.getSize();
}
h264AdvancedAttributes.put("imageattr", createImageAttr(null, res));
addMediaFormats(
MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN,
@ -166,7 +179,7 @@ public class MediaUtils
MediaType.VIDEO,
Constants.H264_RTP,
h264FormatParams,
h264AdvancedParams);
h264AdvancedAttributes);
}
/**
@ -219,6 +232,8 @@ private static void addMediaFormats(
* associated with <tt>rtpPayloadType</tt>
* @param formatParameters the set of format-specific parameters of the
* <tt>MediaFormat</tt>s to be associated with <tt>rtpPayloadType</tt>
* @param advancedAttributes the set of advanced attributes of the
* <tt>MediaFormat</tt>s to be associated with <tt>rtpPayload</tt>
* @param clockRates the optional list of clock rates of the
* <tt>MediaFormat</tt>s to be associated with <tt>rtpPayloadType</tt>
*/
@ -228,7 +243,7 @@ private static void addMediaFormats(
MediaType mediaType,
String jmfEncoding,
Map<String, String> formatParameters,
Map<String, String> advancedParameters,
Map<String, String> advancedAttributes,
double... clockRates)
{
int clockRateCount = clockRates.length;
@ -260,7 +275,7 @@ private static void addMediaFormats(
format,
clockRate,
formatParameters,
advancedParameters);
advancedAttributes);
if (mediaFormat != null)
mediaFormats.add(mediaFormat);
@ -292,7 +307,7 @@ private static void addMediaFormats(
MediaFormat mediaFormat
= MediaFormatImpl
.createInstance(format, clockRate, formatParameters,
advancedParameters);
advancedAttributes);
if (mediaFormat != null)
mediaFormats.add(mediaFormat);
@ -530,4 +545,74 @@ else if (jmfEncoding.equals(VideoFormat.H261_RTP))
else
return MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN;
}
/**
* Creates value of an imgattr.
*
* http://tools.ietf.org/html/draft-ietf-mmusic-image-attributes-04
*
* @param sendSize maximum size peer can send
* @param maxRecvSize maximum size peer can display
* @return string that represent imgattr that can be encoded via SIP/SDP or
* XMPP/Jingle
*/
private static String createImageAttr(java.awt.Dimension sendSize,
java.awt.Dimension maxRecvSize)
{
StringBuffer img = new StringBuffer();
/* send width */
if(sendSize != null)
{
/* single value => send [x=width,y=height] */
img.append("send [x=");
img.append((int)sendSize.getWidth());
img.append(",y=");
img.append((int)sendSize.getHeight());
img.append("]");
/*
else
{
// range
img.append(" send [x=[");
img.append((int)minSendSize.getWidth());
img.append("-");
img.append((int)maxSendSize.getWidth());
img.append("],y=[");
img.append((int)minSendSize.getHeight());
img.append("-");
img.append((int)maxSendSize.getHeight());
img.append("]]");
}
*/
}
else
{
/* can send "all" sizes */
img.append("send *");
}
/* receive size */
if(maxRecvSize != null)
{
/* basically we can receive any size up to our
* screen display size
*/
/* recv [x=[min-max],y=[min-max]] */
img.append(" recv [x=[0-");
img.append((int)maxRecvSize.getWidth());
img.append("],y=[0-");
img.append((int)maxRecvSize.getHeight());
img.append("]]");
}
else
{
/* accept all sizes */
img.append(" recv *");
}
return img.toString();
}
}

@ -38,6 +38,9 @@ public RTCPConnectorInputStream(DatagramSocket socket)
/**
* Add an <tt>RTCPFeedbackListener</tt>.
*
* @param listener object that will listen to incoming RTCP feedback
* messages.
*/
public void addRTCPFeedbackListener(RTCPFeedbackListener listener)
{
@ -48,7 +51,9 @@ public void addRTCPFeedbackListener(RTCPFeedbackListener listener)
}
/**
* Removve an <tt>RTCPFeedbackListener</tt>.
* Remove an <tt>RTCPFeedbackListener</tt>.
*
* @param listener object to remove from listening RTCP feedback messages.
*/
public void removeRTCPFeedbackListener(RTCPFeedbackListener listener)
{

@ -6,10 +6,13 @@
*/
package net.java.sip.communicator.impl.neomedia;
import java.util.*;
import javax.media.rtp.*;
/**
* Represents an RTCP feedback packet as described in RFC4585.
*
* @author Sebastien Vincent
*/
public class RTCPFeedbackPacket
{
/**
@ -49,18 +52,18 @@ public RTCPFeedbackPacket(int type, int payloadType, long sender, long src)
}
/**
* Write packet to output stream.
* Write RTCP packet to output stream of a <tt>DatagramSocket</tt>.
*
* @param out <tt>OutputDataStream</tt>
* @param out <tt>OutputDataStream</tt> of a <tt>DatagramSocket</tt>
*/
public void writeTo(OutputDataStream out)
{
byte data[] = new byte[12];
byte vpfmt = (byte)((2 << 7) | (0 << 6) | (byte)fmt);
data[0] = vpfmt;
data[1] = (byte)payloadType;
/* length (in 32-bit words minus one) */
data[2] = 0;
data[3] = 2; /* common packet is 12 bytes so (12/4) - 1 */
@ -70,13 +73,13 @@ public void writeTo(OutputDataStream out)
data[5] = (byte)((senderSSRC >> 16) & 0xFF);
data[6] = (byte)((senderSSRC >> 8) & 0xFF);
data[7] = (byte)(senderSSRC & 0xFF);
/* source SSRC */
data[8] = (byte)(sourceSSRC >> 24);
data[9] = (byte)((sourceSSRC >> 16) & 0xFF);
data[10] = (byte)((sourceSSRC >> 8) & 0xFF);
data[11] = (byte)(sourceSSRC & 0xFF);
/* effective write */
out.write(data, 0, 12);
}

@ -8,6 +8,7 @@
import java.awt.*;
import java.util.*;
import java.util.regex.*;
import javax.media.*;
import javax.media.control.*;
@ -55,7 +56,7 @@ public class VideoMediaStreamImpl
private Dimension outputSize;
/**
* Use or not PLI.
* Use or not RTCP feedback Picture Loss Indication messages.
*/
private boolean usePLI = false;
@ -523,23 +524,156 @@ public void setDevice(MediaDevice device)
}
/**
* Use or not RTCP feedback Picture Loss Indication.
* Set list of advanced attributes.
*
* @param use use or not PLI
* @param attrs advanced attributes map
*/
public void setRtcpFeedbackPLI(boolean use)
public void setAdvancedAttributes(Map<String, String> attrs)
{
usePLI = use;
super.setAdvancedAttributes(attrs);
/* walk through advanced attributes and see
* if we recognized something we support
*/
if(attrs != null)
{
for(Map.Entry<String, String> mapEntry
: advancedAttributes.entrySet())
{
String key = mapEntry.getKey();
String value = mapEntry.getValue();
if(key.equals("rtcp-fb") && value.equals("nack pli"))
{
usePLI = true;
}
else if(key.equals("imageattr"))
{
Dimension res[] = parseSendRecvResolution(value);
if(res != null)
{
outputSize = res[1];
}
}
}
}
}
/**
* Set negociated output size.
* Extracts and returns maximum resolution can receive from the image
* attribute.
*
* @param size output size of video stream
* @param imgattr send/recv resolution string
* @return maximum resolution array (first element is send, second one is
* recv). Elements could be null if image attribute is not present or if
* resoluion is a wildcard.
*/
public void setOutputSize(Dimension size)
public static java.awt.Dimension[] parseSendRecvResolution(String imgattr)
{
outputSize = size;
java.awt.Dimension res[] = new java.awt.Dimension[2];
String token = null;
Pattern pSendSingle = Pattern.compile("send \\[x=[0-9]+,y=[0-9]+\\]");
Pattern pRecvSingle = Pattern.compile("recv \\[x=[0-9]+,y=[0-9]+\\]");
Pattern pSendRange = Pattern.compile(
"send \\[x=\\[[0-9]+-[0-9]+\\],y=\\[[0-9]+-[0-9]+\\]\\]");
Pattern pRecvRange = Pattern.compile(
"recv \\[x=\\[[0-9]+-[0-9]+\\],y=\\[[0-9]+-[0-9]+\\]\\]");
Pattern pNumeric = Pattern.compile("[0-9]+");
Matcher mSingle = null;
Matcher mRange = null;
Matcher m = null;
/* resolution (width and height) can be on four forms
*
* - single value [x=1920,y=1200]
* - range of values [x=[800-1024],y=[600-768]]
* - fixed range of values [x=[800,1024],y=[600,768]]
* - range of values with step [x=[800:32:1024],y=[600:32:768]]
*
* For the moment we only support the first two forms.
*/
/* send part */
mSingle = pSendSingle.matcher(imgattr);
mRange = pSendRange.matcher(imgattr);
if(mSingle.find())
{
int val[] = new int[2];
int i = 0;
token = imgattr.substring(mSingle.start(), mSingle.end());
m = pNumeric.matcher(token);
while(m.find() && i < 2)
{
val[i] = Integer.parseInt(token.substring(m.start(), m.end()));
}
res[0] = new java.awt.Dimension(val[0], val[1]);
}
else if(mRange.find()) /* try with range */
{
/* have two value for width and two for height (min-max) */
int val[] = new int[4];
int i = 0;
token = imgattr.substring(mRange.start(), mRange.end());
m = pNumeric.matcher(token);
while(m.find() && i < 4)
{
val[i] = Integer.parseInt(token.substring(m.start(), m.end()));
i++;
}
res[0] = new java.awt.Dimension(val[1], val[3]);
}
/* recv part */
mSingle = pRecvSingle.matcher(imgattr);
mRange = pRecvRange.matcher(imgattr);
if(mSingle.find())
{
int val[] = new int[2];
int i = 0;
token = imgattr.substring(mSingle.start(), mSingle.end());
m = pNumeric.matcher(token);
while(m.find() && i < 2)
{
val[i] = Integer.parseInt(token.substring(m.start(), m.end()));
}
res[1] = new java.awt.Dimension(val[0], val[1]);
}
else if(mRange.find()) /* try with range */
{
/* have two value for width and two for height (min-max) */
int val[] = new int[4];
int i = 0;
token = imgattr.substring(mRange.start(), mRange.end());
m = pNumeric.matcher(token);
while(m.find() && i < 4)
{
val[i] = Integer.parseInt(token.substring(m.start(), m.end()));
i++;
}
res[1] = new java.awt.Dimension(val[1], val[3]);
}
token = null;
mSingle = null;
mRange = null;
m = null;
pRecvRange = null;
pSendSingle = null;
pRecvSingle = null;
pSendRange = null;
return res;
}
/**

@ -479,6 +479,8 @@ public void setSSRC(long localSSRC, long remoteSSRC)
/**
* Use or not RTCP feedback PLI.
*
* @param use use or not RTCP PLI message
*/
public void setRtcpFeedbackPLI(boolean use)
{

@ -21,6 +21,7 @@
import net.java.sip.communicator.impl.neomedia.codec.video.h264.*;
import net.java.sip.communicator.impl.neomedia.imgstreaming.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.neomedia.format.*;
import net.java.sip.communicator.service.neomedia.event.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
@ -1019,16 +1020,25 @@ protected void setProcessorFormat(Processor processor, Format format)
{
Format newFormat = null;
VideoFormat tmp = (VideoFormat)format;
Dimension deviceSize = ((VideoMediaFormat)getDevice().getFormat()).getSize();
/* Add a size in the output format. As VideoFormat has no setter, we
* recreate the object.
* recreate the object. Check also if capture device can output
* this size.
*/
if(outputSize != null)
if((deviceSize != null && outputSize != null) &&
(outputSize.width > 0 && outputSize.height > 0) &&
(deviceSize.width > outputSize.width ||
deviceSize.height > outputSize.height))
{
newFormat = new VideoFormat(tmp.getEncoding(), outputSize,
tmp.getMaxDataLength(), tmp.getDataType(),
tmp.getFrameRate());
}
else
{
outputSize = null;
}
super.setProcessorFormat(
processor,

@ -68,6 +68,7 @@ else if (format instanceof VideoFormat)
* @param clockRate the clock rate of the new instance
* @param formatParameters the set of format-specific parameters of the new
* instance
* @param advancedAttrs advanced attributes of the new instance
* @return a new <tt>MediaFormat</tt> instance for the specified JMF
* <tt>Format</tt> and with the specified clock rate and set of
* format-specific parameters
@ -76,7 +77,7 @@ public static MediaFormatImpl<? extends Format> createInstance(
Format format,
double clockRate,
Map<String, String> formatParameters,
Map<String, String> advancedParameters)
Map<String, String> advancedAttrs)
{
if (format instanceof AudioFormat)
{
@ -93,7 +94,7 @@ public static MediaFormatImpl<? extends Format> createInstance(
(AudioFormat)
clockRateAudioFormat.intersects(audioFormat),
formatParameters,
advancedParameters);
advancedAttrs);
}
if (format instanceof VideoFormat)
return
@ -101,7 +102,7 @@ public static MediaFormatImpl<? extends Format> createInstance(
(VideoFormat) format,
clockRate,
formatParameters,
advancedParameters);
advancedAttrs);
return null;
}

@ -11,8 +11,6 @@
import java.util.*;
import java.beans.*;
import java.awt.Dimension; /* disambiguates java.awt.List and java.util.List */
import javax.sdp.*;
import net.java.sip.communicator.impl.protocol.sip.sdp.*;
@ -159,16 +157,6 @@ public class CallPeerMediaHandler
*/
private VideoMediaStream videoStream = null;
/**
* Image size that remote peer can send.
*/
private Dimension maxSendSize = null;
/**
* Image size that remote peer can receive
*/
private Dimension maxRecvSize = null;
/**
* The last-known local SSRC of {@link #videoStream}.
*/
@ -828,27 +816,12 @@ private MediaStream initStream(StreamConnector connector,
throws OperationFailedException
{
MediaStream stream = null;
Dimension size = null;
if (device.getMediaType() == MediaType.AUDIO)
stream = this.audioStream;
else
{
stream = this.videoStream;
if(device != null && device.getFormat() != null)
{
Dimension deviceSize = ((VideoMediaFormat)device.getFormat())
.getSize();
if((deviceSize != null && maxRecvSize != null) &&
(maxRecvSize.width > 0 && maxRecvSize.height > 0) &&
(deviceSize.width > maxRecvSize.width ||
deviceSize.height > maxRecvSize.height))
{
size = maxRecvSize;
}
}
}
if (stream == null)
@ -868,18 +841,7 @@ private MediaStream initStream(StreamConnector connector,
//this is a reinit
}
if(device != null && device.getMediaType() == MediaType.VIDEO)
{
/* set negociated output size for video stream */
((VideoMediaStream)stream).setOutputSize(size);
/* set rtcp-fb */
if(format.getAdvancedParameters().containsKey("rtcp-fb"))
{
((VideoMediaStream)stream).setRtcpFeedbackPLI(true);
}
}
stream.setAdvancedAttributes(format.getAdvancedParameters());
return configureAndStartStream(
device, format, target, direction, stream);
@ -1480,16 +1442,6 @@ private void processAnswer(SessionDescription answer)
MediaDirection direction
= devDirection.getDirectionForAnswer(remoteDirection);
/* extract remote peer maximum supported resolution */
Dimension res[] = SdpUtils.extractSendRecvResolution(
mediaDescription);
if(res != null)
{
maxSendSize = res[0];
maxRecvSize = res[1];
}
// create the corresponding stream...
initStream(connector, dev, supportedFormats.get(0), target,
direction);

@ -10,7 +10,6 @@
import java.net.*;
import java.net.URI;
import java.util.*;
import java.util.regex.*;
import javax.sdp.*;
import javax.sip.header.ContentTypeHeader; // disambiguates MediaType
@ -303,140 +302,6 @@ private static MediaDescription removeMediaDesc(
return null;
}
/**
* Extracts and returns maximum resolution can receive from the image
* attribute.
*
* @param mediaDesc the <tt>MediaDescription</tt> that we'd like to probe
* for maximum receive resolution.
* @return maximum resolution array (first element is send, second one is
* recv). Elements could be null if image attribute is not present or if
* resoluion is a wildcard.
*/
public static java.awt.Dimension[] extractSendRecvResolution(
MediaDescription mediaDesc)
{
java.awt.Dimension res[] = new java.awt.Dimension[2];
String imgattr = null;
String token = null;
Pattern pSendSingle = Pattern.compile("send \\[x=[0-9]+,y=[0-9]+\\]");
Pattern pRecvSingle = Pattern.compile("recv \\[x=[0-9]+,y=[0-9]+\\]");
Pattern pSendRange = Pattern.compile(
"send \\[x=\\[[0-9]+-[0-9]+\\],y=\\[[0-9]+-[0-9]+\\]\\]");
Pattern pRecvRange = Pattern.compile(
"recv \\[x=\\[[0-9]+-[0-9]+\\],y=\\[[0-9]+-[0-9]+\\]\\]");
Pattern pNumeric = Pattern.compile("[0-9]+");
Matcher mSingle = null;
Matcher mRange = null;
Matcher m = null;
try
{
imgattr = mediaDesc.getAttribute("imageattr");
}
catch (SdpParseException exc)
{
logger.debug("A funny thing just happened ...", exc);
return null;
}
if(imgattr == null)
{
return null;
}
/* resolution (width and height) can be on four forms
*
* - single value [x=1920,y=1200]
* - range of values [x=[800-1024],y=[600-768]]
* - fixed range of values [x=[800,1024],y=[600,768]]
* - range of values with step [x=[800:32:1024],y=[600:32:768]]
*
* For the moment we only support the first two forms.
*/
/* send part */
mSingle = pSendSingle.matcher(imgattr);
mRange = pSendRange.matcher(imgattr);
if(mSingle.find())
{
int val[] = new int[2];
int i = 0;
token = imgattr.substring(mSingle.start(), mSingle.end());
m = pNumeric.matcher(token);
while(m.find() && i < 2)
{
val[i] = Integer.parseInt(token.substring(m.start(), m.end()));
}
res[0] = new java.awt.Dimension(val[0], val[1]);
}
else if(mRange.find()) /* try with range */
{
/* have two value for width and two for height (min-max) */
int val[] = new int[4];
int i = 0;
token = imgattr.substring(mRange.start(), mRange.end());
m = pNumeric.matcher(token);
while(m.find() && i < 4)
{
val[i] = Integer.parseInt(token.substring(m.start(), m.end()));
i++;
}
res[0] = new java.awt.Dimension(val[1], val[3]);
}
/* recv part */
mSingle = pRecvSingle.matcher(imgattr);
mRange = pRecvRange.matcher(imgattr);
if(mSingle.find())
{
int val[] = new int[2];
int i = 0;
token = imgattr.substring(mSingle.start(), mSingle.end());
m = pNumeric.matcher(token);
while(m.find() && i < 2)
{
val[i] = Integer.parseInt(token.substring(m.start(), m.end()));
}
res[1] = new java.awt.Dimension(val[0], val[1]);
}
else if(mRange.find()) /* try with range */
{
/* have two value for width and two for height (min-max) */
int val[] = new int[4];
int i = 0;
token = imgattr.substring(mRange.start(), mRange.end());
m = pNumeric.matcher(token);
while(m.find() && i < 4)
{
val[i] = Integer.parseInt(token.substring(m.start(), m.end()));
i++;
}
res[1] = new java.awt.Dimension(val[1], val[3]);
}
token = null;
mSingle = null;
mRange = null;
m = null;
pRecvRange = null;
pSendSingle = null;
pRecvSingle = null;
pSendRange = null;
return res;
}
/**
* Extracts and returns the list of <tt>MediaFormat</tt>s advertised in
* <tt>mediaDesc</tt> preserving their oder and registering dynamic payload
@ -465,7 +330,6 @@ public static List<MediaFormat> extractFormats(
{
List<MediaFormat> mediaFmts = new ArrayList<MediaFormat>();
Vector<String> formatStrings;
List<Attribute> advp = new ArrayList<Attribute>();
try
{
@ -481,20 +345,6 @@ public static List<MediaFormat> extractFormats(
return mediaFmts;
}
try
{
Attribute rtcpFbAsterisk = findPayloadTypeSpecificAttribute(
mediaDesc.getAttributes(false), "rtcp-fb", "*");
if(rtcpFbAsterisk != null)
advp.add(rtcpFbAsterisk);
}
catch(SdpException e)
{
//there was a problem parsing the "*" rtcp-fb. try to ignore.
logger.debug("Does not seem like a valid rtcp-fb:* attribute", e);
}
for(String ptStr : formatStrings)
{
byte pt = -1;
@ -525,17 +375,11 @@ public static List<MediaFormat> extractFormats(
}
Attribute fmtp = null;
Attribute rtcpFb = null;
try
{
fmtp = findPayloadTypeSpecificAttribute(
mediaDesc.getAttributes(false), "fmtp", ptStr);
rtcpFb = findPayloadTypeSpecificAttribute(
mediaDesc.getAttributes(false), "rtcp-fb", ptStr);
if(rtcpFb != null)
advp.add(rtcpFb);
}
catch (SdpException exc)
{
@ -544,6 +388,18 @@ public static List<MediaFormat> extractFormats(
fmtp + " does not seem like a valid fmtp: attribute", exc);
}
List<Attribute> advp = null;
try
{
advp = findAdvancedAttributes(mediaDesc.getAttributes(false),
ptStr);
}
catch(SdpException exc)
{
logger.debug("Problem parsing advanced attributes", exc);
}
MediaFormat mediaFormat = null;
try
{
@ -727,7 +583,7 @@ private static RTPExtension parseRTPExtensionAttribute(
* @param rtpmap an SDP <tt>Attribute</tt> mapping the <tt>payloadType</tt>
* to an encoding name.
* @param fmtp a list of format specific parameters
* @param advp list of advanced parameters (rtcp-fb, ...)
* @param advp list of advanced parameters
* @param ptRegistry the {@link DynamicPayloadTypeRegistry} that we are to
* use in case <tt>payloadType</tt> is dynamic and <tt>rtpmap</tt> is
* <tt>null</tt> (in which case we can hope its in the registry).
@ -816,18 +672,14 @@ private static MediaFormat createFormat(
//Format parameters
Map<String, String> fmtParamsMap = null;
Map<String, String> advancedParamsMap = null;
Map<String, String> advancedAttrMap = null;
if ( fmtp != null)
fmtParamsMap = parseFmtpAttribute(fmtp);
for(Attribute attr : advp)
if(advp != null)
{
/* RTCP feedback support */
if (attr.getName().equals("rtcp-fb"))
{
advancedParamsMap = parseRTCPFeedbackAttribute(attr);
}
advancedAttrMap = parseAdvancedAttributes(advp);
}
//now create the format.
@ -841,7 +693,7 @@ private static MediaFormat createFormat(
clockRate,
numChannels,
fmtParamsMap,
advancedParamsMap);
advancedAttrMap);
/*
* We've just created a MediaFormat for the specified payloadType so we
@ -868,31 +720,33 @@ private static MediaFormat createFormat(
/**
* Parses the value of <tt>rtcpAttr</tt> attribute.
*
* @param rtcpAttr SDP attribute containing rtcp-fb parameters.
* @return
* @param attrs SDP advanced attributes
* @return map containing key/value of attribute
*/
private static Map<String, String> parseRTCPFeedbackAttribute(
Attribute rtcpAttr)
private static Map<String, String> parseAdvancedAttributes(
List<Attribute> attrs)
throws SdpException
{
Map<String, String> ret = new Hashtable<String, String>();
String attrVal = rtcpAttr.toString();
StringTokenizer tokenizer = new StringTokenizer(attrVal, " ", false);
/* valid rtcp-fb we support is on the form:
* a=rtcp-fb:100 nack pli
*/
if (tokenizer.countTokens() != 3)
if(attrs == null)
return null;
/* skip rtcp-fb:pt */
tokenizer.nextToken();
String ackType = tokenizer.nextToken();
String ackExt = tokenizer.nextToken();
Map<String, String> ret = new Hashtable<String, String>();
if(ackType.equals("nack") && (ackExt.equals("pli\r\n") ||
ackExt.equals("pli ")))
for(Attribute attr : attrs)
{
ret.put("rtcp-fb", "nack pli");
String attrName = attr.getName();
String attrVal = attr.getValue();
int idx = -1;
/* get the part after payloadtype */
idx = attrVal.indexOf(" ");
if(idx != -1)
{
attrVal = attrVal.substring(idx + 1, attrVal.length());
}
ret.put(attrName, attrVal);
}
if (ret.size() == 0)
@ -962,7 +816,6 @@ private static Map<String, String> parseFmtpAttribute(Attribute fmtpAttr)
String paramName = token.substring(0, indexOfEq );
String paramValue = token.substring(indexOfEq + 1, token.length());
fmtParamsMap.put(paramName, paramValue);
}
@ -973,6 +826,57 @@ private static Map<String, String> parseFmtpAttribute(Attribute fmtpAttr)
return fmtParamsMap;
}
/**
* Tries to find advanced attributes (i.e. that are not fmtp or rtpmap
* pertaining to the specified <tt>payloadType</tt> in the
* <tt>mediaAttributes</tt> list and returns them if they exists.
*
* @param mediaAttributes the list of <tt>Attribute</tt> fields where we
* are to look for the attribute.
* @param payloadType the payloadType that we are trying to find.
* @return the list of advanced <tt>Attribute</tt> and whose value pertains
* to <tt>payloadType</tt> or <tt>null</tt> if no
* such attributes was found.
*
* @throws SdpException when ... well never really, it's there just for ...
* fun?
*/
private static List<Attribute> findAdvancedAttributes(
Vector<Attribute> mediaAttributes,
String payloadType)
throws SdpException
{
if( mediaAttributes == null || mediaAttributes.size() == 0)
return null;
List<Attribute> ret = new ArrayList<Attribute>();
for(Attribute attr : mediaAttributes)
{
String attrName = attr.getName();
String attrValue = attr.getValue();
/* skip fmtp and rtpmap attribute */
if(attrName.equals("rtpmap") || attrName.equals("fmtp") ||
attrValue == null)
continue;
attrValue = attrValue.trim();
/* have to match payload type or wildcard */
if(!attrValue.startsWith(payloadType + " ") &&
!attrValue.startsWith("* "))
continue;
ret.add(attr);
}
if(ret.isEmpty())
return null;
return ret;
}
/**
* Tries to find an attribute with the specified <tt>attibuteName</tt>
* pertaining to the specified <tt>payloadType</tt> in the
@ -1412,7 +1316,7 @@ public static MediaDescription createMediaDescription(
mediaAttributes.add(fmtp);
}
/* add extra attributes (rtcp-fb, ...) */
/* add extra attributes */
Iterator<Map.Entry<String, String>> iter = format
.getAdvancedParameters().entrySet().iterator();
@ -1427,27 +1331,6 @@ public static MediaDescription createMediaDescription(
payloadTypesArray[i] = payloadType;
}
/* image attribute */
if(mediaType == MediaType.VIDEO)
{
/* one image attribute for all payload
*
* basically peer can send any size and can
* receive image size up to its display screen size
*/
ScreenDevice screen = SipActivator.getMediaService().
getDefaultScreenDevice();
java.awt.Dimension res = null;
if(screen != null)
{
res = screen.getSize();
}
Attribute imgattr = createImageAttribute((byte)0, null, res);
mediaAttributes.add(imgattr);
}
// rtcp: (only include it if different from the default (i.e. rtp + 1)
int rtpPort = connector.getDataSocket().getLocalPort();
int rtcpPort = connector.getControlSocket().getLocalPort();
@ -1571,84 +1454,6 @@ else if(MediaDirection.SENDRECV.equals(direction))
return sdpFactory.createAttribute(dirStr, null);
}
/**
* Creates an <tt>Attribute</tt> instance for send/recv image negociation.
*
* http://tools.ietf.org/html/draft-ietf-mmusic-image-attributes-04
*
* @param payloadType payload type
* @param format capture <tt>VideoMediaFormat</tt>
* @param maxRecvSize maximum size peer can display
* @return image <tt>Attribute</tt>
*/
private static Attribute createImageAttribute(byte payloadType,
java.awt.Dimension sendSize, java.awt.Dimension maxRecvSize)
{
StringBuffer img = new StringBuffer("imageattr:");
if(payloadType != 0)
{
img.append(payloadType);
}
else
{
img.append("*");
}
/* send width */
if(sendSize != null)
{
/* single value => send [x=width,y=height] */
img.append(" send [x=");
img.append((int)sendSize.getWidth());
img.append(",y=");
img.append((int)sendSize.getHeight());
img.append("]");
/*
else
{
// range
img.append(" send [x=[");
img.append((int)minSendSize.getWidth());
img.append("-");
img.append((int)maxSendSize.getWidth());
img.append("],y=[");
img.append((int)minSendSize.getHeight());
img.append("-");
img.append((int)maxSendSize.getHeight());
img.append("]]");
}
*/
}
else
{
/* can send "all" sizes */
img.append(" send *");
}
/* receive size */
if(maxRecvSize != null)
{
/* basically we can receive any size up to our
* screen display size
*/
/* recv [x=[min-max],y=[min-max]] */
img.append(" recv [x=[0-");
img.append((int)maxRecvSize.getWidth());
img.append("],y=[0-");
img.append((int)maxRecvSize.getHeight());
img.append("]]");
}
else
{
/* accept all sizes */
img.append(" recv *");
}
return sdpFactory.createAttribute(img.toString(), null);
}
/**
* Returns the media type (e.g. audio or video) for the specified media
* <tt>description</tt>.

@ -277,4 +277,11 @@ public void addDynamicRTPPayloadType(
* @return the <tt>ZrtpControl</tt> for the current stream.
*/
public ZrtpControl getZrtpControl();
/**
* Set list of advanced attributes.
*
* @param attrs advanced attributes map
*/
public void setAdvancedAttributes(Map<String, String> attrs);
}

@ -70,18 +70,4 @@ public interface VideoMediaStream
* <tt>VideoMediaStream</tt>
*/
public void removeVideoListener(VideoListener listener);
/**
* Set negociated output size.
*
* @param size output size of video stream
*/
public void setOutputSize(Dimension size);
/**
* Use or not RTCP feedback Picture Loss Indication.
*
* @param use use or not PLI
*/
public void setRtcpFeedbackPLI(boolean use);
}

@ -122,6 +122,8 @@ public MediaFormat createMediaFormat(
* for
* @param formatParams any codec specific parameters which have been
* received via SIP/SDP or XMPP/Jingle
* @param advancedAttrs advanced attributes received via SIP/SDP or
* XMPP/Jingle
* @return a <tt>MediaFormat</tt> with the specified <tt>encoding</tt>,
* <tt>clockRate</tt> and set of format parameters which is either an
* <tt>AudioMediaFormat</tt> or a <tt>VideoMediaFormat</tt> instance if
@ -132,7 +134,7 @@ public MediaFormat createMediaFormat(
String encoding,
double clockRate,
Map<String, String> formatParams,
Map<String, String> advancedParams);
Map<String, String> advancedAttrs);
/**
* Creates a <tt>MediaFormat</tt> for the specified <tt>encoding</tt>,
@ -150,6 +152,8 @@ public MediaFormat createMediaFormat(
* <tt>encoding</tt>; otherwise, ignored
* @param formatParams any codec specific parameters which have been
* received via SIP/SDP or XMPP/Jingle
* @param advancedAttrs advanced attributes received via SIP/SDP or
* XMPP/Jingle
* @return a <tt>MediaFormat</tt> with the specified <tt>encoding</tt>,
* <tt>clockRate</tt>, <tt>channels</tt> and set of format parameters which
* is either an <tt>AudioMediaFormat</tt> or a <tt>VideoMediaFormat</tt>
@ -161,7 +165,7 @@ public MediaFormat createMediaFormat(
double clockRate,
int channels,
Map<String, String> formatParams,
Map<String, String> advancedParams);
Map<String, String> advancedAttrs);
/**
* Creates a <tt>MediaFormat</tt> either for the specified
@ -188,6 +192,8 @@ public MediaFormat createMediaFormat(
* <tt>encoding</tt>; otherwise, ignored
* @param formatParams any codec specific parameters which have been
* received via SIP/SDP or XMPP/Jingle
* @param advancedAttrs advanced attributes received via SIP/SDP or
* XMPP/Jingle
* @return a <tt>MediaFormat</tt> with the specified <tt>encoding</tt>,
* <tt>clockRate</tt>, <tt>channels</tt> and set of format parameters which
* is either an <tt>AudioMediaFormat</tt> or a <tt>VideoMediaFormat</tt>
@ -200,5 +206,5 @@ public MediaFormat createMediaFormat(
double clockRate,
int channels,
Map<String, String> formatParams,
Map<String, String> advancedParams);
Map<String, String> advancedAttrs);
}

Loading…
Cancel
Save