/* * 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; import java.util.*; import javax.media.*; import javax.media.format.*; import javax.sdp.*; import org.jitsi.impl.neomedia.codec.*; import org.jitsi.impl.neomedia.codec.video.h264.*; import org.jitsi.impl.neomedia.device.*; import org.jitsi.impl.neomedia.format.*; import org.jitsi.service.configuration.*; import org.jitsi.service.libjitsi.*; import org.jitsi.service.neomedia.*; import org.jitsi.service.neomedia.codec.*; import org.jitsi.service.neomedia.device.*; import org.jitsi.service.neomedia.format.*; import org.jitsi.util.*; /** * Implements static utility methods used by media classes. * * @author Emil Ivov * @author Lyubomir Marinov * @author Boris Grozev */ public class MediaUtils { /** * An empty array with <tt>MediaFormat</tt> element type. Explicitly defined * in order to reduce unnecessary allocations, garbage collection. */ public static final MediaFormat[] EMPTY_MEDIA_FORMATS = new MediaFormat[0]; /** * The <tt>Map</tt> of JMF-specific encodings to well-known encodings as * defined in RFC 3551. */ private static final Map<String, String> jmfEncodingToEncodings = new HashMap<String, String>(); /** * The maximum number of channels for audio that is available through * <tt>MediaUtils</tt>. */ public static final int MAX_AUDIO_CHANNELS; /** * The maximum sample rate for audio that is available through * <tt>MediaUtils</tt>. */ public static final double MAX_AUDIO_SAMPLE_RATE; /** * The maximum sample size in bits for audio that is available through * <tt>MediaUtils</tt>. */ public static final int MAX_AUDIO_SAMPLE_SIZE_IN_BITS; /** * The <tt>MediaFormat</tt>s which do not have RTP payload types assigned by * RFC 3551 and are thus referred to as having dynamic RTP payload types. */ private static final List<MediaFormat> rtpPayloadTypelessMediaFormats = new ArrayList<MediaFormat>(); /** * The <tt>Map</tt> of RTP payload types (expressed as <tt>String</tt>s) to * <tt>MediaFormat</tt>s. */ private static final Map<String, MediaFormat[]> rtpPayloadTypeStrToMediaFormats = new HashMap<String, MediaFormat[]>(); static { addMediaFormats( (byte) SdpConstants.PCMU, "PCMU", MediaType.AUDIO, AudioFormat.ULAW_RTP, 8000); /* * Some codecs depend on JMF native libraries which are only available * on 32-bit Linux and 32-bit Windows. */ if(OSUtils.IS_LINUX32 || OSUtils.IS_WINDOWS32) { Map<String, String> g723FormatParams = new HashMap<String, String>(); g723FormatParams.put("annexa", "no"); g723FormatParams.put("bitrate", "6.3"); addMediaFormats( (byte) SdpConstants.G723, "G723", MediaType.AUDIO, AudioFormat.G723_RTP, g723FormatParams, null, 8000); } addMediaFormats( (byte) SdpConstants.GSM, "GSM", MediaType.AUDIO, AudioFormat.GSM_RTP, 8000); addMediaFormats( (byte) SdpConstants.PCMA, "PCMA", MediaType.AUDIO, Constants.ALAW_RTP, 8000); addMediaFormats( MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN, "iLBC", MediaType.AUDIO, Constants.ILBC_RTP, 8000); addMediaFormats( MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN, "speex", MediaType.AUDIO, Constants.SPEEX_RTP, 8000, 16000, 32000); addMediaFormats( (byte) SdpConstants.G722, "G722", MediaType.AUDIO, Constants.G722_RTP, 8000); if (EncodingConfigurationImpl.G729) { addMediaFormats( (byte) SdpConstants.G729, "G729", MediaType.AUDIO, AudioFormat.G729_RTP, 8000); } addMediaFormats( MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN, "telephone-event", MediaType.AUDIO, Constants.TELEPHONE_EVENT, 8000); ConfigurationService cfg = LibJitsi.getConfigurationService(); boolean advertiseFEC = cfg.getBoolean(Constants.PROP_SILK_ADVERSISE_FEC, false); Map<String,String> silkFormatParams = new HashMap<String, String>(); if(advertiseFEC) silkFormatParams.put("useinbandfec", "1"); addMediaFormats( MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN, "SILK", MediaType.AUDIO, Constants.SILK_RTP, silkFormatParams, null, 8000, 12000, 16000, 24000); Map<String, String> opusFormatParams = new HashMap<String,String>(); boolean opusFec = cfg.getBoolean(Constants.PROP_OPUS_FEC, true); if(!opusFec) opusFormatParams.put("useinbandfec", "0"); boolean opusDtx = cfg.getBoolean(Constants.PROP_OPUS_DTX, true); if(opusDtx) opusFormatParams.put("usedtx", "1"); addMediaFormats( MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN, "opus", MediaType.AUDIO, Constants.OPUS_RTP, 2, opusFormatParams, null, 48000); /* * We don't really support these. * addMediaFormats( (byte) SdpConstants.JPEG, "JPEG", MediaType.VIDEO, VideoFormat.JPEG_RTP); addMediaFormats( (byte) SdpConstants.H263, "H263", MediaType.VIDEO, VideoFormat.H263_RTP); addMediaFormats( (byte) SdpConstants.H261, "H261", MediaType.VIDEO, VideoFormat.H261_RTP); */ /* H264 */ Map<String, String> h264FormatParams = new HashMap<String, String>(); String packetizationMode = "packetization-mode"; Map<String, String> h264AdvancedAttributes = new HashMap<String, String>(); /* * Disable PLI because the periodic intra-refresh feature of FFmpeg/x264 * is used. */ // h264AdvancedAttributes.put("rtcp-fb", "nack pli"); /* * XXX The initialization of MediaServiceImpl is very complex so it is * wise to not reference it at the early stage of its initialization. */ ScreenDevice screen = ScreenDeviceImpl.getDefaultScreenDevice(); java.awt.Dimension res = (screen == null) ? null : screen.getSize(); h264AdvancedAttributes.put("imageattr", createImageAttr(null, res)); if ((cfg == null) || cfg .getString( "net.java.sip.communicator.impl.neomedia" + ".codec.video.h264.defaultProfile", JNIEncoder.MAIN_PROFILE) .equals(JNIEncoder.MAIN_PROFILE)) { // main profile, common features, HD capable level 3.1 h264FormatParams.put("profile-level-id", "4DE01f"); } else { // baseline profile, common features, HD capable level 3.1 h264FormatParams.put("profile-level-id", "42E01f"); } // By default, packetization-mode=1 is enabled. if ((cfg == null) || cfg.getBoolean( "net.java.sip.communicator.impl.neomedia" + ".codec.video.h264.packetization-mode-1.enabled", true)) { // packetization-mode=1 h264FormatParams.put(packetizationMode, "1"); addMediaFormats( MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN, "H264", MediaType.VIDEO, Constants.H264_RTP, h264FormatParams, h264AdvancedAttributes); } /* * XXX Android's current video CaptureDevice is based on MediaRecorder * and provides support for packetization-mode=1 only. */ if (!OSUtils.IS_ANDROID) { // packetization-mode=0 /* * XXX At the time of this writing, * EncodingConfiguration#compareEncodingPreferences(MediaFormat, * MediaFormat) is incomplete and considers two MediaFormats to be * equal if they have an equal number of format parameters (given * that the encodings and clock rates are equal, of course). Either * fix the method in question or don't add a format parameter for * packetization-mode 0 (which is equivalent to having * packetization-mode explicitly defined as 0 anyway, according to * the respective RFC). */ h264FormatParams.remove(packetizationMode); addMediaFormats( MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN, "H264", MediaType.VIDEO, Constants.H264_RTP, h264FormatParams, h264AdvancedAttributes); } /* H263+ */ Map<String, String> h263FormatParams = new HashMap<String, String>(); Map<String, String> h263AdvancedAttributes = new LinkedHashMap<String, String>(); /* * The maximum resolution we can receive is the size of our screen * device. */ if (res != null) h263FormatParams.put("CUSTOM", res.width + "," + res.height + ",2"); h263FormatParams.put("VGA", "2"); h263FormatParams.put("CIF", "1"); h263FormatParams.put("QCIF", "1"); addMediaFormats( MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN, "H263-1998", MediaType.VIDEO, Constants.H263P_RTP, h263FormatParams, h263AdvancedAttributes); addMediaFormats( MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN, "VP8", MediaType.VIDEO, Constants.VP8_RTP, null, null); // Calculate the values of the MAX_AUDIO_* static fields of MediaUtils. List<MediaFormat> audioMediaFormats = new ArrayList<MediaFormat>( rtpPayloadTypeStrToMediaFormats.size() + rtpPayloadTypelessMediaFormats.size()); for (MediaFormat[] mediaFormats : rtpPayloadTypeStrToMediaFormats.values()) for (MediaFormat mediaFormat : mediaFormats) if (MediaType.AUDIO.equals(mediaFormat.getMediaType())) audioMediaFormats.add(mediaFormat); for (MediaFormat mediaFormat : rtpPayloadTypelessMediaFormats) if (MediaType.AUDIO.equals(mediaFormat.getMediaType())) audioMediaFormats.add(mediaFormat); int maxAudioChannels = Format.NOT_SPECIFIED; double maxAudioSampleRate = Format.NOT_SPECIFIED; int maxAudioSampleSizeInBits = Format.NOT_SPECIFIED; for (MediaFormat mediaFormat : audioMediaFormats) { AudioMediaFormatImpl audioMediaFormat = (AudioMediaFormatImpl) mediaFormat; int channels = audioMediaFormat.getChannels(); double sampleRate = audioMediaFormat.getClockRate(); int sampleSizeInBits = audioMediaFormat.getFormat().getSampleSizeInBits(); if (maxAudioChannels < channels) maxAudioChannels = channels; if (maxAudioSampleRate < sampleRate) maxAudioSampleRate = sampleRate; if (maxAudioSampleSizeInBits < sampleSizeInBits) maxAudioSampleSizeInBits = sampleSizeInBits; } MAX_AUDIO_CHANNELS = maxAudioChannels; MAX_AUDIO_SAMPLE_RATE = maxAudioSampleRate; MAX_AUDIO_SAMPLE_SIZE_IN_BITS = maxAudioSampleSizeInBits; } /** * Adds a new mapping of a specific RTP payload type to a list of * <tt>MediaFormat</tt>s of a specific <tt>MediaType</tt>, with a specific * JMF encoding and, optionally, with specific clock rates. * * @param rtpPayloadType the RTP payload type to be associated with a list * of <tt>MediaFormat</tt>s * @param encoding the well-known encoding (name) corresponding to * <tt>rtpPayloadType</tt> (in contrast to the JMF-specific encoding * specified by <tt>jmfEncoding</tt>) * @param mediaType the <tt>MediaType</tt> of the <tt>MediaFormat</tt>s to * be associated with <tt>rtpPayloadType</tt> * @param jmfEncoding the JMF encoding of the <tt>MediaFormat</tt>s to be * associated with <tt>rtpPayloadType</tt> * @param clockRates the optional list of clock rates of the * <tt>MediaFormat</tt>s to be associated with <tt>rtpPayloadType</tt> */ private static void addMediaFormats( byte rtpPayloadType, String encoding, MediaType mediaType, String jmfEncoding, double... clockRates) { addMediaFormats( rtpPayloadType, encoding, mediaType, jmfEncoding, null, null, clockRates); } /** * Adds a new mapping of a specific RTP payload type to a list of * <tt>MediaFormat</tt>s of a specific <tt>MediaType</tt>, with a specific * JMF encoding and, optionally, with specific clock rates. * * @param rtpPayloadType the RTP payload type to be associated with a list * of <tt>MediaFormat</tt>s * @param encoding the well-known encoding (name) corresponding to * <tt>rtpPayloadType</tt> (in contrast to the JMF-specific encoding * specified by <tt>jmfEncoding</tt>) * @param mediaType the <tt>MediaType</tt> of the <tt>MediaFormat</tt>s to * be associated with <tt>rtpPayloadType</tt> * @param jmfEncoding the JMF encoding of the <tt>MediaFormat</tt>s to be * 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> */ private static void addMediaFormats( byte rtpPayloadType, String encoding, MediaType mediaType, String jmfEncoding, Map<String, String> formatParameters, Map<String, String> advancedAttributes, double... clockRates) { addMediaFormats( rtpPayloadType, encoding, mediaType, jmfEncoding, 1 /* channel */, formatParameters, advancedAttributes, clockRates); } /** * Adds a new mapping of a specific RTP payload type to a list of * <tt>MediaFormat</tt>s of a specific <tt>MediaType</tt>, with a specific * JMF encoding and, optionally, with specific clock rates. * * @param rtpPayloadType the RTP payload type to be associated with a list * of <tt>MediaFormat</tt>s * @param encoding the well-known encoding (name) corresponding to * <tt>rtpPayloadType</tt> (in contrast to the JMF-specific encoding * specified by <tt>jmfEncoding</tt>) * @param mediaType the <tt>MediaType</tt> of the <tt>MediaFormat</tt>s to * be associated with <tt>rtpPayloadType</tt> * @param jmfEncoding the JMF encoding of the <tt>MediaFormat</tt>s to be * associated with <tt>rtpPayloadType</tt> * @param channels number of channels * @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> */ @SuppressWarnings("unchecked") private static void addMediaFormats( byte rtpPayloadType, String encoding, MediaType mediaType, String jmfEncoding, int channels, Map<String, String> formatParameters, Map<String, String> advancedAttributes, double... clockRates) { int clockRateCount = clockRates.length; List<MediaFormat> mediaFormats = new ArrayList<MediaFormat>(clockRateCount); if (clockRateCount > 0) { for (double clockRate : clockRates) { Format format; switch (mediaType) { case AUDIO: if(channels == 1) format = new AudioFormat(jmfEncoding); else format = new AudioFormat( jmfEncoding, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, channels); break; case VIDEO: format = new ParameterizedVideoFormat( jmfEncoding, formatParameters); break; default: throw new IllegalArgumentException("mediaType"); } MediaFormat mediaFormat = MediaFormatImpl.createInstance( format, clockRate, formatParameters, advancedAttributes); if (mediaFormat != null) mediaFormats.add(mediaFormat); } } else { Format format; double clockRate; switch (mediaType) { case AUDIO: AudioFormat audioFormat = new AudioFormat(jmfEncoding); format = audioFormat; clockRate = audioFormat.getSampleRate(); break; case VIDEO: format = new ParameterizedVideoFormat( jmfEncoding, formatParameters); clockRate = VideoMediaFormatImpl.DEFAULT_CLOCK_RATE; break; default: throw new IllegalArgumentException("mediaType"); } MediaFormat mediaFormat = MediaFormatImpl.createInstance( format, clockRate, formatParameters, advancedAttributes); if (mediaFormat != null) mediaFormats.add(mediaFormat); } if (mediaFormats.size() > 0) { if (MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN == rtpPayloadType) rtpPayloadTypelessMediaFormats.addAll(mediaFormats); else rtpPayloadTypeStrToMediaFormats.put( Byte.toString(rtpPayloadType), mediaFormats.toArray(EMPTY_MEDIA_FORMATS)); jmfEncodingToEncodings.put( ((MediaFormatImpl<? extends Format>) mediaFormats.get(0)) .getJMFEncoding(), encoding); } } /** * 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 */ public 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("]");*/ /* send [x=[min-max],y=[min-max]] */ img.append("send [x=[0-"); img.append((int)sendSize.getWidth()); img.append("],y=[0-"); 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(); } /** * Gets a <tt>MediaFormat</tt> predefined in <tt>MediaUtils</tt> which * represents a specific JMF <tt>Format</tt>. If there is no such * representing <tt>MediaFormat</tt> in <tt>MediaUtils</tt>, returns * <tt>null</tt>. * * @param format the JMF <tt>Format</tt> to get the <tt>MediaFormat</tt> * representation for * @return a <tt>MediaFormat</tt> predefined in <tt>MediaUtils</tt> which * represents <tt>format</tt> if any; <tt>null</tt> if there is no such * representing <tt>MediaFormat</tt> in <tt>MediaUtils</tt> */ @SuppressWarnings("unchecked") public static MediaFormat getMediaFormat(Format format) { double clockRate; if (format instanceof AudioFormat) clockRate = ((AudioFormat) format).getSampleRate(); else if (format instanceof VideoFormat) clockRate = VideoMediaFormatImpl.DEFAULT_CLOCK_RATE; else clockRate = Format.NOT_SPECIFIED; byte rtpPayloadType = getRTPPayloadType(format.getEncoding(), clockRate); if (MediaFormatImpl.RTP_PAYLOAD_TYPE_UNKNOWN != rtpPayloadType) { for (MediaFormat mediaFormat : getMediaFormats(rtpPayloadType)) { MediaFormatImpl<? extends Format> mediaFormatImpl = (MediaFormatImpl<? extends Format>) mediaFormat; if (format.matches(mediaFormatImpl.getFormat())) return mediaFormat; } } return null; } /** * Gets the <tt>MediaFormat</tt> known to <tt>MediaUtils</tt> and having the * specified well-known <tt>encoding</tt> (name) and <tt>clockRate</tt>. * * @param encoding the well-known encoding (name) of the * <tt>MediaFormat</tt> to get * @param clockRate the clock rate of the <tt>MediaFormat</tt> to get * @return the <tt>MediaFormat</tt> known to <tt>MediaUtils</tt> and having * the specified <tt>encoding</tt> and <tt>clockRate</tt> */ public static MediaFormat getMediaFormat(String encoding, double clockRate) { return getMediaFormat(encoding, clockRate, null); } /** * Gets the <tt>MediaFormat</tt> known to <tt>MediaUtils</tt> and having the * specified well-known <tt>encoding</tt> (name), <tt>clockRate</tt> and * matching format parameters. * * @param encoding the well-known encoding (name) of the * <tt>MediaFormat</tt> to get * @param clockRate the clock rate of the <tt>MediaFormat</tt> to get * @param fmtps the format parameters of the <tt>MediaFormat</tt> to get * @return the <tt>MediaFormat</tt> known to <tt>MediaUtils</tt> and having * the specified <tt>encoding</tt> (name), <tt>clockRate</tt> and matching * format parameters */ public static MediaFormat getMediaFormat( String encoding, double clockRate, Map<String, String> fmtps) { for (MediaFormat format : getMediaFormats(encoding)) if ((format.getClockRate() == clockRate) && format.formatParametersMatch(fmtps)) return format; return null; } /** * Gets the index of a specific <tt>MediaFormat</tt> instance within the * internal storage of <tt>MediaUtils</tt>. Since the index is in the * internal storage which may or may not be one and the same for the various * <tt>MediaFormat</tt> instances and which may or may not be searched for * the purposes of determining the index, the index is not to be used as a * way to determine whether <tt>MediaUtils</tt> knows the specified * <tt>mediaFormat</tt> * * @param mediaFormat the <tt>MediaFormat</tt> to determine the index of * @return the index of the specified <tt>mediaFormat</tt> in the internal * storage of <tt>MediaUtils</tt> */ public static int getMediaFormatIndex(MediaFormat mediaFormat) { return rtpPayloadTypelessMediaFormats.indexOf(mediaFormat); } /** * Gets the <tt>MediaFormat</tt>s (expressed as an array) corresponding to * a specific RTP payload type. * * @param rtpPayloadType the RTP payload type to retrieve the * corresponding <tt>MediaFormat</tt>s for * @return an array of <tt>MediaFormat</tt>s corresponding to the specified * RTP payload type */ public static MediaFormat[] getMediaFormats(byte rtpPayloadType) { MediaFormat[] mediaFormats = rtpPayloadTypeStrToMediaFormats.get(Byte.toString(rtpPayloadType)); return (mediaFormats == null) ? EMPTY_MEDIA_FORMATS : mediaFormats.clone(); } /** * Gets the <tt>MediaFormat</tt>s known to <tt>MediaUtils</tt> and being of * the specified <tt>MediaType</tt>. * * @param mediaType the <tt>MediaType</tt> of the <tt>MediaFormat</tt>s to * get * @return the <tt>MediaFormat</tt>s known to <tt>MediaUtils</tt> and being * of the specified <tt>mediaType</tt> */ public static MediaFormat[] getMediaFormats(MediaType mediaType) { List<MediaFormat> mediaFormats = new ArrayList<MediaFormat>(); for (MediaFormat[] formats : rtpPayloadTypeStrToMediaFormats.values()) for (MediaFormat format : formats) if (format.getMediaType().equals(mediaType)) mediaFormats.add(format); for (MediaFormat format : rtpPayloadTypelessMediaFormats) if (format.getMediaType().equals(mediaType)) mediaFormats.add(format); return mediaFormats.toArray(EMPTY_MEDIA_FORMATS); } /** * Gets the <tt>MediaFormat</tt>s predefined in <tt>MediaUtils</tt> with a * specific well-known encoding (name) as defined by RFC 3551 "RTP Profile * for Audio and Video Conferences with Minimal Control". * * @param encoding the well-known encoding (name) to get the corresponding * <tt>MediaFormat</tt>s of * @return a <tt>List</tt> of <tt>MediaFormat</tt>s corresponding to the * specified encoding (name) */ @SuppressWarnings("unchecked") public static List<MediaFormat> getMediaFormats(String encoding) { String jmfEncoding = null; for (Map.Entry<String, String> jmfEncodingToEncoding : jmfEncodingToEncodings.entrySet()) if (jmfEncodingToEncoding.getValue().equals(encoding)) { jmfEncoding = jmfEncodingToEncoding.getKey(); break; } List<MediaFormat> mediaFormats = new ArrayList<MediaFormat>(); if (jmfEncoding != null) { for (MediaFormat[] rtpPayloadTypeMediaFormats : rtpPayloadTypeStrToMediaFormats.values()) for (MediaFormat rtpPayloadTypeMediaFormat : rtpPayloadTypeMediaFormats) if (((MediaFormatImpl<? extends Format>) rtpPayloadTypeMediaFormat) .getJMFEncoding().equals(jmfEncoding)) mediaFormats.add(rtpPayloadTypeMediaFormat); if (mediaFormats.size() < 1) { for (MediaFormat rtpPayloadTypelessMediaFormat : rtpPayloadTypelessMediaFormats) if (((MediaFormatImpl<? extends Format>) rtpPayloadTypelessMediaFormat) .getJMFEncoding().equals(jmfEncoding)) mediaFormats.add(rtpPayloadTypelessMediaFormat); } } return mediaFormats; } /** * Gets the RTP payload type corresponding to a specific JMF encoding and * clock rate. * * @param jmfEncoding the JMF encoding as returned by * {@link Format#getEncoding()} or the respective <tt>AudioFormat</tt> and * <tt>VideoFormat</tt> encoding constants to get the corresponding RTP * payload type of * @param clockRate the clock rate to be taken into account in the search * for the RTP payload type if the JMF encoding does not uniquely identify * it * @return the RTP payload type corresponding to the specified JMF encoding * and clock rate if known in RFC 3551 "RTP Profile for Audio and Video * Conferences with Minimal Control"; otherwise, * {@link MediaFormat#RTP_PAYLOAD_TYPE_UNKNOWN} */ public static byte getRTPPayloadType(String jmfEncoding, double clockRate) { if (jmfEncoding == null) return MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN; else if (jmfEncoding.equals(AudioFormat.ULAW_RTP)) return SdpConstants.PCMU; else if (jmfEncoding.equals(Constants.ALAW_RTP)) return SdpConstants.PCMA; else if (jmfEncoding.equals(AudioFormat.GSM_RTP)) return SdpConstants.GSM; else if (jmfEncoding.equals(AudioFormat.G723_RTP)) return SdpConstants.G723; else if (jmfEncoding.equals(AudioFormat.DVI_RTP) && (clockRate == 8000)) return SdpConstants.DVI4_8000; else if (jmfEncoding.equals(AudioFormat.DVI_RTP) && (clockRate == 16000)) return SdpConstants.DVI4_16000; else if (jmfEncoding.equals(AudioFormat.ALAW)) return SdpConstants.PCMA; else if (jmfEncoding.equals(Constants.G722)) return SdpConstants.G722; else if (jmfEncoding.equals(Constants.G722_RTP)) return SdpConstants.G722; else if (jmfEncoding.equals(AudioFormat.GSM)) return SdpConstants.GSM; else if (jmfEncoding.equals(AudioFormat.GSM_RTP)) return SdpConstants.GSM; else if (jmfEncoding.equals(AudioFormat.G728_RTP)) return SdpConstants.G728; else if (jmfEncoding.equals(AudioFormat.G729_RTP)) return SdpConstants.G729; else if (jmfEncoding.equals(VideoFormat.H263_RTP)) return SdpConstants.H263; else if (jmfEncoding.equals(VideoFormat.JPEG_RTP)) return SdpConstants.JPEG; else if (jmfEncoding.equals(VideoFormat.H261_RTP)) return SdpConstants.H261; else return MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN; } /** * Gets the well-known encoding (name) as defined in RFC 3551 "RTP Profile * for Audio and Video Conferences with Minimal Control" corresponding to a * given JMF-specific encoding. * * @param jmfEncoding the JMF encoding to get the corresponding well-known * encoding of * @return the well-known encoding (name) as defined in RFC 3551 "RTP * Profile for Audio and Video Conferences with Minimal Control" * corresponding to <tt>jmfEncoding</tt> if any; otherwise, <tt>null</tt> */ public static String jmfEncodingToEncoding(String jmfEncoding) { return jmfEncodingToEncodings.get(jmfEncoding); } }