diff --git a/src/org/jitsi/impl/neomedia/MediaStreamImpl.java b/src/org/jitsi/impl/neomedia/MediaStreamImpl.java index ced31e1f2d229c5128c103e1aa4c56be7e70b123..4145f3b5107b50e19af1c044e4aa5c9e60511afc 100644 --- a/src/org/jitsi/impl/neomedia/MediaStreamImpl.java +++ b/src/org/jitsi/impl/neomedia/MediaStreamImpl.java @@ -25,6 +25,7 @@ import org.jitsi.impl.neomedia.transform.*; import org.jitsi.impl.neomedia.transform.csrc.*; import org.jitsi.impl.neomedia.transform.dtmf.*; +import org.jitsi.impl.neomedia.transform.pt.*; import org.jitsi.impl.neomedia.transform.rtcp.*; import org.jitsi.impl.neomedia.transform.zrtp.*; import org.jitsi.service.neomedia.*; @@ -223,6 +224,11 @@ else if (MediaDeviceSession.SSRC_LIST.equals(propertyName)) */ private MediaStreamStatsImpl mediaStreamStatsImpl; + /** + * Engine chain overriding payload type if needed. + */ + private PayloadTypeTransformEngine ptTransformEngine; + /** * Initializes a new <tt>MediaStreamImpl</tt> instance which will use the * specified <tt>MediaDevice</tt> for both capture and playback of media. @@ -373,6 +379,12 @@ private TransformEngineChain createTransformEngineChain() statisticsEngine = new StatisticsEngine(this); engineChain.add(statisticsEngine); + // here comes the override payload type transformer + // as it changes headers of packets, need to go before encryption + if(ptTransformEngine == null) + ptTransformEngine = new PayloadTypeTransformEngine(); + engineChain.add(ptTransformEngine); + // SRTP engineChain.add(srtpControl.getTransformEngine()); @@ -2845,4 +2857,24 @@ public FECDecoderControl getFecDecoderControl(ReceiveStream receiveStream) } return null; } + + /** + * Adds additional RTP payload mappings that will override the ones in the + * "dynamicPayloadTypes" map for outgoing packets. This is necessary so + * that we can support the RFC3264 case where the answerer has the right + * to declare what payload type mappings it wants to receive even if they + * are different from those in the offer. RFC3264 claims this is for + * support of legacy protocols such as H.323 but we've been bumping with + * a number of cases where multi-component pure SIP systems also need to + * behave this way. + * The <tt>Map<Byte, Byte></tt> maps source payload to payload to use + * for packets when sending. + * @param mappingOverride <tt>Map<Byte, Byte></tt> that maps + * source payload to payload to use for packets when sending. + */ + public void setPTMappingOverrides(Map<Byte, Byte> mappingOverride) + { + if(ptTransformEngine != null) + ptTransformEngine.setPTMappingOverride(mappingOverride); + } } diff --git a/src/org/jitsi/impl/neomedia/transform/pt/PayloadTypeTransformEngine.java b/src/org/jitsi/impl/neomedia/transform/pt/PayloadTypeTransformEngine.java new file mode 100644 index 0000000000000000000000000000000000000000..298deadaa11dc67af469eef383df1e91b91cff90 --- /dev/null +++ b/src/org/jitsi/impl/neomedia/transform/pt/PayloadTypeTransformEngine.java @@ -0,0 +1,116 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package org.jitsi.impl.neomedia.transform.pt; + +import org.jitsi.impl.neomedia.*; +import org.jitsi.impl.neomedia.transform.*; + +import java.util.*; + +/** + * We use this engine to change payload types of outgoing RTP packets if needed. + * This is necessary so that we can support the RFC3264 case where the answerer + * has the right to declare what payload type mappings it wants to receive even + * if they are different from those in the offer. RFC3264 claims this is for + * support of legacy protocols such as H.323 but we've been bumping with + * a number of cases where multi-component pure SIP systems also need to + * behave this way. + * + * @author Damian Minkov + */ +public class PayloadTypeTransformEngine + implements TransformEngine, + PacketTransformer +{ + /** + * The mapping we use to override payloads. By default it is empty + * and we do nothing, packets are passed through without modification. + * Maps source payload to target payload. + */ + private Map<Byte, Byte> mappingOverride = new HashMap<Byte, Byte>(); + + /** + * Checks if there are any override mappings, if no setting just pass + * through the packet. + * If the <tt>RawPacket</tt> payload has entry in mappings to override, + * we override packet payload type. + * + * @param pkt the RTP <tt>RawPacket</tt> that we check for need to change + * payload type. + * + * @return the updated <tt>RawPacket</tt> instance containing the changed + * payload type. + */ + public RawPacket transform(RawPacket pkt) + { + if(mappingOverride.isEmpty()) + return pkt; + + Byte newPT = mappingOverride.get(pkt.getPayloadType()); + if(newPT != null) + pkt.setPayload(newPT); + + return pkt; + } + + /** + * Do nothing just passes the incoming packet. + * + * @param pkt the RTP <tt>RawPacket</tt> that we will pass through. + * + * @return the same <tt>RawPacket</tt> that is passing through. + */ + public RawPacket reverseTransform(RawPacket pkt) + { + return pkt; + } + + /** + * Closes this <tt>PacketTransformer</tt> i.e. releases the resources + * allocated by it and prepares it for garbage collection. + */ + public void close() + { + } + + /** + * Returns a reference to this class since it is performing RTP + * transformations in here. + * + * @return a reference to <tt>this</tt> instance of the + * <tt>PayloadTypeTransformEngine</tt>. + */ + public PacketTransformer getRTPTransformer() + { + return this; + } + + /** + * Always returns <tt>null</tt> since this engine does not require any + * RTCP transformations. + * + * @return <tt>null</tt> since this engine does not require any + * RTCP transformations. + */ + public PacketTransformer getRTCPTransformer() + { + return null; + } + + /** + * Adds additional RTP payload mappings used to override the outgoing + * payload type. The <tt>Map<Byte, Byte></tt> maps source payload to + * payload to use for packets when sending. + * @param mappingOverride <tt>Map<Byte, Byte></tt> that maps + * source payload to payload to use for packets when sending. + */ + public void setPTMappingOverride(Map<Byte, Byte> mappingOverride) + { + if(mappingOverride != null) + this.mappingOverride = mappingOverride; + } +} diff --git a/src/org/jitsi/service/neomedia/MediaStream.java b/src/org/jitsi/service/neomedia/MediaStream.java index 6ace1dca63f2f5917e750af8e1297f5853dd4c8a..479104d15cf41381037b3fc8911c8137d1ab8e4d 100644 --- a/src/org/jitsi/service/neomedia/MediaStream.java +++ b/src/org/jitsi/service/neomedia/MediaStream.java @@ -237,6 +237,22 @@ public void addDynamicRTPPayloadType( */ public Map<Byte, MediaFormat> getDynamicRTPPayloadTypes(); + /** + * Adds additional RTP payload mappings that will override the ones in the + * "dynamicPayloadTypes" map for outgoing packets. This is necessary so + * that we can support the RFC3264 case where the answerer has the right + * to declare what payload type mappings it wants to receive even if they + * are different from those in the offer. RFC3264 claims this is for + * support of legacy protocols such as H.323 but we've been bumping with + * a number of cases where multi-component pure SIP systems also need to + * behave this way. + * The <tt>Map<Byte, Byte></tt> maps source payload to payload to use + * for packets when sending. + * @param mappingOverride <tt>Map<Byte, Byte></tt> that maps + * source payload to payload to use for packets when sending. + */ + public void setPTMappingOverrides(Map<Byte, Byte> mappingOverride); + /** * Adds or updates an association in this <tt>MediaStream</tt> mapping the * specified <tt>extensionID</tt> to <tt>rtpExtension</tt> and enabling or