text: const { toBeType } = require('jest-tobetype');
  const { UnsupportedError } = require('../lib/errors');
  const ortc = require('../lib/ortc');
  
  expect.extend({ toBeType });
  
  test('generateRouterRtpCapabilities() succeeds', () =>
  {
  	const mediaCodecs =
  	[
  		{
  			kind       : 'audio',
  			mimeType   : 'audio/opus',
  			clockRate  : 48000,
  			channels   : 2,
  			parameters :
  			{
  				useinbandfec : 1,
  				foo          : 'bar'
  			}
  		},
  		{
  			kind                 : 'video',
  			mimeType             : 'video/VP8',
  			preferredPayloadType : 125, // Let's force it.
  			clockRate            : 90000
  		},
  		{
  			kind       : 'video',
  			mimeType   : 'video/H264',
  			clockRate  : 90000,
  			parameters :
  			{
  				'level-asymmetry-allowed' : 1,
  				'profile-level-id'        : '42e01f',
  				foo                       : 'bar'
  			},
  			rtcpFeedback : [] // Will be ignored.
  		}
  	];
  
  	const rtpCapabilities = ortc.generateRouterRtpCapabilities(mediaCodecs);
  
  	expect(rtpCapabilities.codecs.length).toBe(5);
  
  	// opus.
  	expect(rtpCapabilities.codecs[0]).toEqual(
  		{
  			kind                 : 'audio',
  			mimeType             : 'audio/opus',
  			preferredPayloadType : 100, // 100 is the first available dynamic PT.
  			clockRate            : 48000,
  			channels             : 2,
  			parameters           :
  			{
  				useinbandfec : 1,
  				foo          : 'bar'
  			},
  			rtcpFeedback :
  			[
  				{ type: 'transport-cc', parameter: '' }
  			]
  		});
  
  	// VP8.
  	expect(rtpCapabilities.codecs[1]).toEqual(
  		{
  			kind                 : 'video',
  			mimeType             : 'video/VP8',
  			preferredPayloadType : 125,
  			clockRate            : 90000,
  			parameters           : {},
  			rtcpFeedback         :
  			[
  				{ type: 'nack', parameter: '' },
  				{ type: 'nack', parameter: 'pli' },
  				{ type: 'ccm', parameter: 'fir' },
  				{ type: 'goog-remb', parameter: '' },
  				{ type: 'transport-cc', parameter: '' }
  			]
  		});
  
  	// VP8 RTX.
  	expect(rtpCapabilities.codecs[2]).toEqual(
  		{
  			kind                 : 'video',
  			mimeType             : 'video/rtx',
  			preferredPayloadType : 101, // 101 is the second available dynamic PT.
  			clockRate            : 90000,
  			parameters           :
  			{
  				apt : 125
  			},
  			rtcpFeedback : []
  		});
  
  	// H264.
  	expect(rtpCapabilities.codecs[3]).toEqual(
  		{
  			kind                 : 'video',
  			mimeType             : 'video/H264',
  			preferredPayloadType : 102, // 102 is the third available dynamic PT.
  			clockRate            : 90000,
  			parameters           :
  			{
  				// Since packetization-mode param was not included in the H264 codec
  				// and it's default value is 0, it's not added by ortc file.
  				// 'packetization-mode'      : 0,
  				'level-asymmetry-allowed' : 1,
  				'profile-level-id'        : '42e01f',
  				foo                       : 'bar'
  			},
  			rtcpFeedback :
  			[
  				{ type: 'nack', parameter: '' },
  				{ type: 'nack', parameter: 'pli' },
  				{ type: 'ccm', parameter: 'fir' },
  				{ type: 'goog-remb', parameter: '' },
  				{ type: 'transport-cc', parameter: '' }
  			]
  		});
  
  	// H264 RTX.
  	expect(rtpCapabilities.codecs[4]).toEqual(
  		{
  			kind                 : 'video',
  			mimeType             : 'video/rtx',
  			preferredPayloadType : 103,
  			clockRate            : 90000,
  			parameters           :
  			{
  				apt : 102
  			},
  			rtcpFeedback : []
  		});
  });
  
  test('generateRouterRtpCapabilities() with unsupported codecs throws UnsupportedError', () =>
  {
  	let mediaCodecs;
  
  	mediaCodecs =
  	[
  		{
  			kind      : 'audio',
  			mimeType  : 'audio/chicken',
  			clockRate : 8000,
  			channels  : 4
  		}
  	];
  
  	expect(() => ortc.generateRouterRtpCapabilities(mediaCodecs))
  		.toThrow(UnsupportedError);
  
  	mediaCodecs =
  	[
  		{
  			kind      : 'audio',
  			mimeType  : 'audio/opus',
  			clockRate : 48000,
  			channels  : 1
  		}
  	];
  
  	expect(() => ortc.generateRouterRtpCapabilities(mediaCodecs))
  		.toThrow(UnsupportedError);
  });
  
  test('generateRouterRtpCapabilities() with too many codecs throws', () =>
  {
  	const mediaCodecs = [];
  
  	for (let i = 0; i < 100; ++i)
  	{
  		mediaCodecs.push(
  			{
  				kind      : 'audio',
  				mimeType  : 'audio/opus',
  				clockRate : 48000,
  				channels  : 2
  			});
  	}
  
  	expect(() => ortc.generateRouterRtpCapabilities(mediaCodecs))
  		.toThrow('cannot allocate');
  });
  
  test('getProducerRtpParametersMapping(), getConsumableRtpParameters(), getConsumerRtpParameters() and getPipeConsumerRtpParameters() succeed', () =>
  {
  	const mediaCodecs =
  	[
  		{
  			kind      : 'audio',
  			mimeType  : 'audio/opus',
  			clockRate : 48000,
  			channels  : 2
  		},
  		{
  			kind       : 'video',
  			mimeType   : 'video/H264',
  			clockRate  : 90000,
  			parameters :
  			{
  				'level-asymmetry-allowed' : 1,
  				'packetization-mode'      : 1,
  				'profile-level-id'        : '4d0032',
  				bar                       : 'lalala'
  			}
  		}
  	];
  
  	const routerRtpCapabilities = ortc.generateRouterRtpCapabilities(mediaCodecs);
  
  	const rtpParameters =
  	{
  		codecs :
  		[
  			{
  				mimeType    : 'video/H264',
  				payloadType : 111,
  				clockRate   : 90000,
  				parameters  :
  				{
  					foo                  : 1234,
  					'packetization-mode' : 1,
  					'profile-level-id'   : '4d0032'
  				},
  				rtcpFeedback :
  				[
  					{ type: 'nack', parameter: '' },
  					{ type: 'nack', parameter: 'pli' },
  					{ type: 'goog-remb', parameter: '' }
  				]
  			},
  			{
  				mimeType    : 'video/rtx',
  				payloadType : 112,
  				clockRate   : 90000,
  				parameters  :
  				{
  					apt : 111
  				},
  				rtcpFeedback : []
  			}
  		],
  		headerExtensions :
  		[
  			{
  				uri : 'urn:ietf:params:rtp-hdrext:sdes:mid',
  				id  : 1
  			},
  			{
  				uri : 'urn:3gpp:video-orientation',
  				id  : 2
  			}
  		],
  		encodings :
  		[
  			{
  				ssrc            : 11111111,
  				rtx             : { ssrc: 11111112 },
  				maxBitrate      : 111111,
  				scalabilityMode : 'L1T3'
  			},
  			{
  				ssrc            : 21111111,
  				rtx             : { ssrc: 21111112 },
  				maxBitrate      : 222222,
  				scalabilityMode : 'L1T3'
  			},
  			{
  				rid             : 'high',
  				maxBitrate      : 333333,
  				scalabilityMode : 'L1T3'
  			}
  		],
  		rtcp :
  		{
  			cname : 'qwerty1234'
  		}
  	};
  
  	const rtpMapping =
  		ortc.getProducerRtpParametersMapping(rtpParameters, routerRtpCapabilities);
  
  	expect(rtpMapping.codecs).toEqual(
  		[
  			{ payloadType: 111, mappedPayloadType: 101 },
  			{ payloadType: 112, mappedPayloadType: 102 }
  		]);
  
  	expect(rtpMapping.encodings[0].ssrc).toBe(11111111);
  	expect(rtpMapping.encodings[0].rid).toBeUndefined();
  	expect(rtpMapping.encodings[0].mappedSsrc).toBeType('number');
  	expect(rtpMapping.encodings[1].ssrc).toBe(21111111);
  	expect(rtpMapping.encodings[1].rid).toBeUndefined();
  	expect(rtpMapping.encodings[1].mappedSsrc).toBeType('number');
  	expect(rtpMapping.encodings[2].ssrc).toBeUndefined();
  	expect(rtpMapping.encodings[2].rid).toBe('high');
  	expect(rtpMapping.encodings[2].mappedSsrc).toBeType('number');
  
  	const consumableRtpParameters = ortc.getConsumableRtpParameters(
  		'video', rtpParameters, routerRtpCapabilities, rtpMapping);
  
  	expect(consumableRtpParameters.codecs[0].mimeType).toBe('video/H264');
  	expect(consumableRtpParameters.codecs[0].payloadType).toBe(101);
  	expect(consumableRtpParameters.codecs[0].clockRate).toBe(90000);
  	expect(consumableRtpParameters.codecs[0].parameters).toEqual(
  		{
  			foo                  : 1234,
  			'packetization-mode' : 1,
  			'profile-level-id'   : '4d0032'
  		});
  
  	expect(consumableRtpParameters.codecs[1].mimeType).toBe('video/rtx');
  	expect(consumableRtpParameters.codecs[1].payloadType).toBe(102);
  	expect(consumableRtpParameters.codecs[1].clockRate).toBe(90000);
  	expect(consumableRtpParameters.codecs[1].parameters).toEqual({ apt: 101 });
  
  	expect(consumableRtpParameters.encodings[0]).toEqual(
  		{
  			ssrc            : rtpMapping.encodings[0].mappedSsrc,
  			maxBitrate      : 111111,
  			scalabilityMode : 'L1T3'
  		});
  	expect(consumableRtpParameters.encodings[1]).toEqual(
  		{
  			ssrc            : rtpMapping.encodings[1].mappedSsrc,
  			maxBitrate      : 222222,
  			scalabilityMode : 'L1T3'
  		});
  	expect(consumableRtpParameters.encodings[2]).toEqual(
  		{
  			ssrc            : rtpMapping.encodings[2].mappedSsrc,
  			maxBitrate      : 333333,
  			scalabilityMode : 'L1T3'
  		});
  
  	expect(consumableRtpParameters.rtcp).toEqual(
  		{
  			cname       : rtpParameters.rtcp.cname,
  			reducedSize : true,
  			mux         : true
  		});
  
  	const remoteRtpCapabilities =
  	{
  		codecs :
  		[
  			{
  				kind                 : 'audio',
  				mimeType             : 'audio/opus',
  				preferredPayloadType : 100,
  				clockRate            : 48000,
  				channels             : 2,
  				parameters           : {},
  				rtcpFeedback         : []
  			},
  			{
  				kind                 : 'video',
  				mimeType             : 'video/H264',
  				preferredPayloadType : 101,
  				clockRate            : 90000,
  				parameters           :
  				{
  					'packetization-mode' : 1,
  					'profile-level-id'   : '4d0032',
  					baz                  : 'LOLOLO'
  				},
  				rtcpFeedback :
  				[
  					{ type: 'nack', parameter: '' },
  					{ type: 'nack', parameter: 'pli' },
  					{ type: 'foo', parameter: 'FOO' }
  				]
  			},
  			{
  				kind                 : 'video',
  				mimeType             : 'video/rtx',
  				preferredPayloadType : 102,
  				clockRate            : 90000,
  				parameters           :
  				{
  					apt : 101
  				},
  				rtcpFeedback : []
  			}
  		],
  		headerExtensions :
  		[
  			{
  				kind             : 'audio',
  				uri              : 'urn:ietf:params:rtp-hdrext:sdes:mid',
  				preferredId      : 1,
  				preferredEncrypt : false,
  				direction        : 'sendrecv'
  			},
  			{
  				kind             : 'video',
  				uri              : 'urn:ietf:params:rtp-hdrext:sdes:mid',
  				preferredId      : 1,
  				preferredEncrypt : false,
  				direction        : 'sendrecv'
  			},
  			{
  				kind             : 'video',
  				uri              : 'urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id',
  				preferredId      : 2,
  				preferredEncrypt : false,
  				direction        : 'sendrecv'
  			},
  			{
  				kind             : 'audio',
  				uri              : 'urn:ietf:params:rtp-hdrext:ssrc-audio-level',
  				preferredId      : 8,
  				preferredEncrypt : false,
  				direction        : 'sendrecv'
  			},
  			{
  				kind             : 'video',
  				uri              : 'urn:3gpp:video-orientation',
  				preferredId      : 11,
  				preferredEncrypt : false,
  				direction        : 'sendrecv'
  			},
  			{
  				kind             : 'video',
  				uri              : 'urn:ietf:params:rtp-hdrext:toffset',
  				preferredId      : 12,
  				preferredEncrypt : false,
  				direction        : 'sendrecv'
  			}
  		]
  	};
  
  	const consumerRtpParameters =
  		ortc.getConsumerRtpParameters(consumableRtpParameters, remoteRtpCapabilities, false);
  
  	expect(consumerRtpParameters.codecs.length).toEqual(2);
  	expect(consumerRtpParameters.codecs[0]).toEqual(
  		{
  			mimeType    : 'video/H264',
  			payloadType : 101,
  			clockRate   : 90000,
  			parameters  :
  			{
  				foo                  : 1234,
  				'packetization-mode' : 1,
  				'profile-level-id'   : '4d0032'
  			},
  			rtcpFeedback :
  			[
  				{ type: 'nack', parameter: '' },
  				{ type: 'nack', parameter: 'pli' },
  				{ type: 'foo', parameter: 'FOO' }
  			]
  		});
  	expect(consumerRtpParameters.codecs[1]).toEqual(
  		{
  			mimeType    : 'video/rtx',
  			payloadType : 102,
  			clockRate   : 90000,
  			parameters  :
  			{
  				apt : 101
  			},
  			rtcpFeedback : []
  		});
  
  	expect(consumerRtpParameters.encodings.length).toBe(1);
  	expect(consumerRtpParameters.encodings[0].ssrc).toBeType('number');
  	expect(consumerRtpParameters.encodings[0].rtx).toBeType('object');
  	expect(consumerRtpParameters.encodings[0].rtx.ssrc).toBeType('number');
  	expect(consumerRtpParameters.encodings[0].scalabilityMode).toBe('S3T3');
  	expect(consumerRtpParameters.encodings[0].maxBitrate).toBe(333333);
  
  	expect(consumerRtpParameters.headerExtensions).toEqual(
  		[
  			{
  				uri        : 'urn:ietf:params:rtp-hdrext:sdes:mid',
  				id         : 1,
  				encrypt    : false,
  				parameters : {}
  			},
  			{
  				uri        : 'urn:3gpp:video-orientation',
  				id         : 11,
  				encrypt    : false,
  				parameters : {}
  			},
  			{
  				uri        : 'urn:ietf:params:rtp-hdrext:toffset',
  				id         : 12,
  				encrypt    : false,
  				parameters : {}
  			}
  		]);
  
  	expect(consumerRtpParameters.rtcp).toEqual(
  		{
  			cname       : rtpParameters.rtcp.cname,
  			reducedSize : true,
  			mux         : true
  		});
  
  	const pipeConsumerRtpParameters =
  		ortc.getPipeConsumerRtpParameters(consumableRtpParameters);
  
  	expect(pipeConsumerRtpParameters.codecs.length).toEqual(1);
  	expect(pipeConsumerRtpParameters.codecs[0]).toEqual(
  		{
  			mimeType    : 'video/H264',
  			payloadType : 101,
  			clockRate   : 90000,
  			parameters  :
  			{
  				foo                  : 1234,
  				'packetization-mode' : 1,
  				'profile-level-id'   : '4d0032'
  			},
  			rtcpFeedback :
  			[
  				{ type: 'nack', parameter: 'pli' },
  				{ type: 'ccm', parameter: 'fir' }
  			]
  		});
  
  	expect(pipeConsumerRtpParameters.encodings.length).toBe(3);
  	expect(pipeConsumerRtpParameters.encodings[0].ssrc).toBeType('number');
  	expect(pipeConsumerRtpParameters.encodings[0].rtx).toBeUndefined();
  	expect(pipeConsumerRtpParameters.encodings[0].maxBitrate).toBeType('number');
  	expect(pipeConsumerRtpParameters.encodings[0].scalabilityMode).toBe('L1T3');
  	expect(pipeConsumerRtpParameters.encodings[1].ssrc).toBeType('number');
  	expect(pipeConsumerRtpParameters.encodings[1].rtx).toBeUndefined();
  	expect(pipeConsumerRtpParameters.encodings[1].maxBitrate).toBeType('number');
  	expect(pipeConsumerRtpParameters.encodings[1].scalabilityMode).toBe('L1T3');
  	expect(pipeConsumerRtpParameters.encodings[2].ssrc).toBeType('number');
  	expect(pipeConsumerRtpParameters.encodings[2].rtx).toBeUndefined();
  	expect(pipeConsumerRtpParameters.encodings[2].maxBitrate).toBeType('number');
  	expect(pipeConsumerRtpParameters.encodings[2].scalabilityMode).toBe('L1T3');
  
  	expect(pipeConsumerRtpParameters.rtcp).toEqual(
  		{
  			cname       : rtpParameters.rtcp.cname,
  			reducedSize : true,
  			mux         : true
  		});
  });
  
  test('getProducerRtpParametersMapping() with incompatible params throws UnsupportedError', () =>
  {
  	const mediaCodecs =
  	[
  		{
  			kind      : 'audio',
  			mimeType  : 'audio/opus',
  			clockRate : 48000,
  			channels  : 2
  		},
  		{
  			kind       : 'video',
  			mimeType   : 'video/H264',
  			clockRate  : 90000,
  			parameters :
  			{
  				'packetization-mode' : 1,
  				'profile-level-id'   : '640032'
  			}
  		}
  	];
  
  	const routerRtpCapabilities = ortc.generateRouterRtpCapabilities(mediaCodecs);
  
  	const rtpParameters =
  	{
  		codecs :
  		[
  			{
  				mimeType     : 'video/VP8',
  				payloadType  : 120,
  				clockRate    : 90000,
  				rtcpFeedback :
  				[
  					{ type: 'nack', parameter: '' },
  					{ type: 'nack', parameter: 'fir' }
  				]
  			}
  		],
  		headerExtensions : [],
  		encodings        :
  		[
  			{ ssrc: 11111111 }
  		],
  		rtcp :
  		{
  			cname : 'qwerty1234'
  		}
  	};
  
  	expect(
  		() => ortc.getProducerRtpParametersMapping(rtpParameters, routerRtpCapabilities))
  		.toThrow(UnsupportedError);
  });
  