/// <summary> /// <para>Events:</para> /// <para>@emits transportclose</para></para> /// <para>@emits score - (score: ProducerScore[])</para> /// <para>@emits videoorientationchange - (videoOrientation: ProducerVideoOrientation)</para> /// <para>@emits trace - (trace: ProducerTraceEventData)</para> /// <para>@emits @close</para> /// <para>Observer events:</para> /// <para>@emits close</para> /// <para>@emits pause</para> /// <para>@emits resume</para> /// <para>@emits score - (score: ProducerScore[])</para> /// <para>@emits videoorientationchange - (videoOrientation: ProducerVideoOrientation)</para> /// <para>@emits trace - (trace: ProducerTraceEventData)</para> /// </summary> /// <param name="loggerFactory"></param> /// <param name="producerInternalData"></param> /// <param name="kind"></param> /// <param name="rtpParameters"></param> /// <param name="type"></param> /// <param name="consumableRtpParameters"></param> /// <param name="channel"></param> /// <param name="appData"></param> /// <param name="paused"></param> public Producer(ILoggerFactory loggerFactory, ProducerInternalData producerInternalData, MediaKind kind, RtpParameters rtpParameters, ProducerType type, RtpParameters consumableRtpParameters, Channel channel, PayloadChannel payloadChannel, Dictionary <string, object>?appData, bool paused ) { _logger = loggerFactory.CreateLogger <Producer>(); // Internal _internal = producerInternalData; // Data Kind = kind; RtpParameters = rtpParameters; Type = type; ConsumableRtpParameters = consumableRtpParameters; _channel = channel; _payloadChannel = payloadChannel; AppData = appData; _paused = paused; _checkConsumersTimer = new Timer(CheckConsumers, null, TimeSpan.FromSeconds(CheckConsumersTimeSeconds), TimeSpan.FromMilliseconds(-1)); HandleWorkerNotifications(); }
/// <summary> /// <para>Events:</para> /// <para>@emits transportclose</para></para> /// <para>@emits score - (score: ProducerScore[])</para> /// <para>@emits videoorientationchange - (videoOrientation: ProducerVideoOrientation)</para> /// <para>@emits trace - (trace: ProducerTraceEventData)</para> /// <para>@emits @close</para> /// <para>Observer events:</para> /// <para>@emits close</para> /// <para>@emits pause</para> /// <para>@emits resume</para> /// <para>@emits score - (score: ProducerScore[])</para> /// <para>@emits videoorientationchange - (videoOrientation: ProducerVideoOrientation)</para> /// <para>@emits trace - (trace: ProducerTraceEventData)</para> /// </summary> /// <param name="loggerFactory"></param> /// <param name="producerInternalData"></param> /// <param name="kind"></param> /// <param name="rtpParameters"></param> /// <param name="type"></param> /// <param name="consumableRtpParameters"></param> /// <param name="channel"></param> /// <param name="appData"></param> /// <param name="paused"></param> public Producer(ILoggerFactory loggerFactory, ProducerInternalData producerInternalData, MediaKind kind, RtpParameters rtpParameters, ProducerType type, RtpParameters consumableRtpParameters, Channel channel, Dictionary <string, object>?appData, bool paused) { _logger = loggerFactory.CreateLogger <Producer>(); // Internal Internal = producerInternalData; // Data Kind = kind; RtpParameters = rtpParameters; Type = type; ConsumableRtpParameters = consumableRtpParameters; _channel = channel; AppData = appData; Paused = paused; HandleWorkerNotifications(); }
/// <summary> /// Create a Producer. /// </summary> public virtual async Task <Producer> ProduceAsync(ProducerOptions producerOptions) { _logger.LogDebug($"ProduceAsync() | Transport:{TransportId}"); if (!producerOptions.Id.IsNullOrWhiteSpace() && Producers.ContainsKey(producerOptions.Id !)) { throw new Exception($"a Producer with same id \"{ producerOptions.Id }\" already exists"); } // This may throw. ORTC.ValidateRtpParameters(producerOptions.RtpParameters); // If missing or empty encodings, add one. // TODO: (alby)注意检查这样做是否合适 // 在 mediasoup-worker 中,要求 Encodings 至少要有一个元素。 if (producerOptions.RtpParameters.Encodings.IsNullOrEmpty()) { producerOptions.RtpParameters.Encodings = new List <RtpEncodingParameters> { new RtpEncodingParameters() }; } // Don't do this in PipeTransports since there we must keep CNAME value in // each Producer. // TODO: (alby)反模式 if (GetType() != typeof(PipeTransport)) { // If CNAME is given and we don't have yet a CNAME for Producers in this // Transport, take it. if (_cnameForProducers.IsNullOrWhiteSpace() && producerOptions.RtpParameters.Rtcp != null && !producerOptions.RtpParameters.Rtcp.CNAME.IsNullOrWhiteSpace()) { _cnameForProducers = producerOptions.RtpParameters.Rtcp.CNAME; } // Otherwise if we don't have yet a CNAME for Producers and the RTP parameters // do not include CNAME, create a random one. else if (_cnameForProducers.IsNullOrWhiteSpace()) { _cnameForProducers = Guid.NewGuid().ToString().Substring(0, 8); } // Override Producer's CNAME. // TODO: (alby)注意检查这样做是否合适 producerOptions.RtpParameters.Rtcp = producerOptions.RtpParameters.Rtcp ?? new RtcpParameters(); producerOptions.RtpParameters.Rtcp.CNAME = _cnameForProducers; } var routerRtpCapabilities = GetRouterRtpCapabilities(); // This may throw. var rtpMapping = ORTC.GetProducerRtpParametersMapping(producerOptions.RtpParameters, routerRtpCapabilities); // This may throw. var consumableRtpParameters = ORTC.GetConsumableRtpParameters(producerOptions.Kind, producerOptions.RtpParameters, routerRtpCapabilities, rtpMapping); var @internal = new ProducerInternalData ( Internal.RouterId, Internal.TransportId, producerOptions.Id.NullOrWhiteSpaceReplace(Guid.NewGuid().ToString()) ); var reqData = new { producerOptions.Kind, producerOptions.RtpParameters, RtpMapping = rtpMapping, producerOptions.KeyFrameRequestDelay, producerOptions.Paused, }; var status = await Channel.RequestAsync(MethodId.TRANSPORT_PRODUCE, @internal, reqData); var responseData = JsonConvert.DeserializeObject <TransportProduceResponseData>(status !); var data = new { producerOptions.Kind, producerOptions.RtpParameters, responseData.Type, ConsumableRtpParameters = consumableRtpParameters }; var producer = new Producer(_loggerFactory, @internal, data.Kind, data.RtpParameters, data.Type, data.ConsumableRtpParameters, Channel, PayloadChannel, producerOptions.AppData, producerOptions.Paused !.Value); producer.On("@close", async _ => { await ProducersLock.WaitAsync(); try { Producers.Remove(producer.ProducerId); Emit("@producerclose", producer); } finally { ProducersLock.Set(); } }); await ProducersLock.WaitAsync(); try { Producers[producer.ProducerId] = producer; } finally { ProducersLock.Set(); } Emit("@newproducer", producer); // Emit observer event. Observer.Emit("newproducer", producer); return(producer); }