public static MediaDescriptionField buildMediaDescription(MediaChannel channel, boolean offer) {
		MediaDescriptionField md = new MediaDescriptionField();
		
		md.setMedia(channel.getMediaType());
		md.setPort(channel.getRtpPort());
		MediaProfile profile = channel.isDtlsEnabled() ? MediaProfile.RTP_SAVPF : MediaProfile.RTP_AVP;
		md.setProtocol(profile.getProfile());
        final String externalAddress = channel.getExternalAddress() == null || channel.getExternalAddress().isEmpty() ? null : channel.getExternalAddress();
        md.setConnection(new ConnectionField("IN", "IP4", externalAddress != null ? externalAddress : channel.getRtpAddress()));
		md.setPtime(new PacketTimeAttribute(20));
        md.setRtcp(new RtcpAttribute(channel.getRtcpPort(), "IN", "IP4", externalAddress != null ? externalAddress : channel.getRtcpAddress()));
		if (channel.isRtcpMux()) {
			md.setRtcpMux(new RtcpMuxAttribute());
		}
		
		// ICE attributes
		if (channel.isIceEnabled()) {
			md.setIceUfrag(new IceUfragAttribute(channel.getIceUfrag()));
			md.setIcePwd(new IcePwdAttribute(channel.getIcePwd()));
			
			// Fix connection address based on default (only) candidate
            md.getConnection().setAddress(externalAddress != null ? externalAddress : channel.getRtpAddress());
			md.setPort(channel.getRtpPort());
			
			// Fix RTCP if rtcp-mux is used
			if(channel.isRtcpMux()) {
                md.getRtcp().setAddress(externalAddress != null ? externalAddress : channel.getRtpAddress());
			    md.getRtcp().setPort(channel.getRtpPort());
			}
			
			// Add HOST candidate
			md.addCandidate(processHostCandidate(channel, IceComponent.RTP_ID));
			if(!channel.isRtcpMux()) {
			    md.addCandidate(processHostCandidate(channel, IceComponent.RTCP_ID));
			}
			
			if(channel.getExternalAddress() != null && !channel.getExternalAddress().isEmpty()) {
			    // Add SRFLX candidate
			    md.addCandidate(processSrflxCandidate(channel, IceComponent.RTP_ID));
			    if(!channel.isRtcpMux()) {
			        md.addCandidate(processSrflxCandidate(channel, IceComponent.RTCP_ID));
			    }
			}
			
//			List<LocalCandidateWrapper> rtpCandidates = channel.getRtpCandidates();
//			if(!rtpCandidates.isEmpty()) {
//				// Fix connection address based on default candidate
//				IceCandidate defaultCandidate = channel.getDefaultRtpCandidate().getCandidate();
//				md.getConnection().setAddress(defaultCandidate.getHostString());
//				md.setPort(defaultCandidate.getPort());
//				
//				// Fix RTCP if rtcp-mux is used
//				if(channel.isRtcpMux()) {
//					md.getRtcp().setAddress(defaultCandidate.getHostString());
//					md.getRtcp().setPort(defaultCandidate.getPort());
//				}
//				
//				// Add candidates list for ICE negotiation
//				for (LocalCandidateWrapper candidate : rtpCandidates) {
//					md.addCandidate(processCandidate(candidate.getCandidate()));
//				}
//			}
			
//			if (!channel.isRtcpMux()) {
//				List<LocalCandidateWrapper> rtcpCandidates = channel.getRtcpCandidates();
//				
//				if(!rtcpCandidates.isEmpty()) {
//					// Fix RTCP based on default RTCP candidate
//					IceCandidate defaultCandidate = channel.getDefaultRtcpCandidate().getCandidate();
//					md.getRtcp().setAddress(defaultCandidate.getHostString());
//					md.getRtcp().setPort(defaultCandidate.getPort());
//					
//					// Add candidates list for ICE negotiation
//					for (LocalCandidateWrapper candidate : rtcpCandidates) {
//						md.addCandidate(processCandidate(candidate.getCandidate()));
//					}
//				}
//			}
		}

		// Media formats
		RTPFormat[] negotiatedFormats = channel.getFormats().toArray();
		for (int index = 0; index < negotiatedFormats.length; index++) {
			RTPFormat f = negotiatedFormats[index];
			// Fixes #61 - MMS SDP offer should offer only 101 telephone-event
			if(offer && AVProfile.isDtmf(f) && !AVProfile.isDefaultDtmf(f)) {
			    continue;
			}
			RtpMapAttribute rtpMap = new RtpMapAttribute();
			rtpMap.setPayloadType(f.getID());
			rtpMap.setCodec(f.getFormat().getName().toString());
			rtpMap.setClockRate(f.getClockRate());
			
			switch (channel.getMediaType()) {
			case AudioChannel.MEDIA_TYPE:
				AudioFormat audioFormat = (AudioFormat) f.getFormat();

				if (audioFormat.getChannels() > 1) {
					rtpMap.setCodecParams(audioFormat.getChannels());
				}
				
				if (audioFormat.getOptions() != null) {
					rtpMap.setParameters(new FormatParameterAttribute(f.getID(), audioFormat.getOptions().toString()));
				}
				break;

			default:
				throw new IllegalArgumentException("Media type " + channel.getMediaType() + " not supported.");
			}
			
			md.addPayloadType(String.valueOf(f.getID()));
			md.addFormat(rtpMap);
		}

		// DTLS attributes
		if (channel.isDtlsEnabled()) {
			md.setSetup(new SetupAttribute(offer ? SetupAttribute.ACTPASS : SetupAttribute.PASSIVE));
			String fingerprint = channel.getDtlsFingerprint();
			int whitespace = fingerprint.indexOf(" ");
			String fingerprintHash = fingerprint.substring(0, whitespace);
			String fingerprintValue = fingerprint.substring(whitespace + 1);
			md.setFingerprint(new FingerprintAttribute(fingerprintHash, fingerprintValue));
		}
		
		md.setConnectionMode(new ConnectionModeAttribute(ConnectionModeAttribute.SENDRECV));
		SsrcAttribute ssrcAttribute = new SsrcAttribute(Long.toString(channel.getSsrc()));
		ssrcAttribute.addAttribute("cname", channel.getCname());
		md.setSsrc(ssrcAttribute);
		
		return md;
	}
public static MediaDescriptionField buildMediaDescription ( MediaChannel channel , boolean offer ) { MediaDescriptionField md = new MediaDescriptionField ( ) ; md . setMedia ( channel . getMediaType ( ) ) ; md . setPort ( channel . getRtpPort ( ) ) ; MediaProfile profile = channel . isDtlsEnabled ( ) ? MediaProfile . RTP_SAVPF : MediaProfile . RTP_AVP ; md . setProtocol ( profile . getProfile ( ) ) ; final String externalAddress = channel . getExternalAddress ( ) == null || channel . getExternalAddress ( ) . isEmpty ( ) ? null : channel . getExternalAddress ( ) ; md . setConnection ( new ConnectionField ( "IN" , "IP4" , externalAddress != null ? externalAddress : channel . getRtpAddress ( ) ) ) ; md . setPtime ( new PacketTimeAttribute ( 20 ) ) ; md . setRtcp ( new RtcpAttribute ( channel . getRtcpPort ( ) , "IN" , "IP4" , externalAddress != null ? externalAddress : channel . getRtcpAddress ( ) ) ) ; if ( channel . isRtcpMux ( ) ) { md . setRtcpMux ( new RtcpMuxAttribute ( ) ) ; } if ( channel . isIceEnabled ( ) ) { md . setIceUfrag ( new IceUfragAttribute ( channel . getIceUfrag ( ) ) ) ; md . setIcePwd ( new IcePwdAttribute ( channel . getIcePwd ( ) ) ) ; md . getConnection ( ) . setAddress ( externalAddress != null ? externalAddress : channel . getRtpAddress ( ) ) ; md . setPort ( channel . getRtpPort ( ) ) ; if ( channel . isRtcpMux ( ) ) { md . getRtcp ( ) . setAddress ( externalAddress != null ? externalAddress : channel . getRtpAddress ( ) ) ; md . getRtcp ( ) . setPort ( channel . getRtpPort ( ) ) ; } md . addCandidate ( processHostCandidate ( channel , IceComponent . RTP_ID ) ) ; if ( ! channel . isRtcpMux ( ) ) { md . addCandidate ( processHostCandidate ( channel , IceComponent . RTCP_ID ) ) ; } if ( channel . getExternalAddress ( ) != null && ! channel . getExternalAddress ( ) . isEmpty ( ) ) { md . addCandidate ( processSrflxCandidate ( channel , IceComponent . RTP_ID ) ) ; if ( ! channel . isRtcpMux ( ) ) { md . addCandidate ( processSrflxCandidate ( channel , IceComponent . RTCP_ID ) ) ; } } } RTPFormat [ ] negotiatedFormats = channel . getFormats ( ) . toArray ( ) ; for ( int index = 0 ; index < negotiatedFormats . length ; index ++ ) { RTPFormat f = negotiatedFormats [ index ] ; if ( offer && AVProfile . isDtmf ( f ) && ! AVProfile . isDefaultDtmf ( f ) ) { continue ; } RtpMapAttribute rtpMap = new RtpMapAttribute ( ) ; rtpMap . setPayloadType ( f . getID ( ) ) ; rtpMap . setCodec ( f . getFormat ( ) . getName ( ) . toString ( ) ) ; rtpMap . setClockRate ( f . getClockRate ( ) ) ; switch ( channel . getMediaType ( ) ) { case AudioChannel . MEDIA_TYPE : AudioFormat audioFormat = ( AudioFormat ) f . getFormat ( ) ; if ( audioFormat . getChannels ( ) > 1 ) { rtpMap . setCodecParams ( audioFormat . getChannels ( ) ) ; } if ( audioFormat . getOptions ( ) != null ) { rtpMap . setParameters ( new FormatParameterAttribute ( f . getID ( ) , audioFormat . getOptions ( ) . toString ( ) ) ) ; } break ; default : throw new IllegalArgumentException ( "Media type " + channel . getMediaType ( ) + " not supported." ) ; } md . addPayloadType ( String . valueOf ( f . getID ( ) ) ) ; md . addFormat ( rtpMap ) ; } if ( channel . isDtlsEnabled ( ) ) { md . setSetup ( new SetupAttribute ( offer ? SetupAttribute . ACTPASS : SetupAttribute . PASSIVE ) ) ; String fingerprint = channel . getDtlsFingerprint ( ) ; int whitespace = fingerprint . indexOf ( " " ) ; String fingerprintHash = fingerprint . substring ( 0 , whitespace ) ; String fingerprintValue = fingerprint . substring ( whitespace + 1 ) ; md . setFingerprint ( new FingerprintAttribute ( fingerprintHash , fingerprintValue ) ) ; } md . setConnectionMode ( new ConnectionModeAttribute ( ConnectionModeAttribute . SENDRECV ) ) ; SsrcAttribute ssrcAttribute = new SsrcAttribute ( Long . toString ( channel . getSsrc ( ) ) ) ; ssrcAttribute . addAttribute ( "cname" , channel . getCname ( ) ) ; md . setSsrc ( ssrcAttribute ) ; return md ; }
Build an SDP description for a media channel.

@param channel
The channel to read information from
@return The SDP media description