Exemplo n.º 1
0
        /// <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;

            if (_isCheckConsumer)
            {
                _checkConsumersTimer = new Timer(CheckConsumers, null, TimeSpan.FromSeconds(CheckConsumersTimeSeconds), TimeSpan.FromMilliseconds(-1));
            }
            HandleWorkerNotifications();
        }
Exemplo n.º 2
0
        /// <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.
            // 在 mediasoup-worker 中,要求 Encodings 至少要有一个元素。
            if (producerOptions.RtpParameters.Encodings.IsNullOrEmpty())
            {
                producerOptions.RtpParameters.Encodings = new List <RtpEncodingParameters>
                {
                    // 对 RtpEncodingParameters 序列化时,Rid、CodecPayloadType 和 Rtx 为 null 会忽略,因为客户端库对其有校验。
                    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.
                // 对 RtcpParameters 序列化时,CNAME 和 ReducedSize 为 null 会忽略,因为客户端库对其有校验。
                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 resData = await Channel.RequestAsync(MethodId.TRANSPORT_PRODUCE, @internal, reqData);

            var responseData = JsonSerializer.Deserialize <TransportProduceResponseData>(resData !, ObjectExtensions.DefaultJsonSerializerOptions) !;
            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);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "@close");
                }
                finally
                {
                    ProducersLock.Set();
                }
            });

            await ProducersLock.WaitAsync();

            try
            {
                Producers[producer.ProducerId] = producer;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "ProduceAsync()");
            }
            finally
            {
                ProducersLock.Set();
            }

            Emit("@newproducer", producer);

            // Emit observer event.
            Observer.Emit("newproducer", producer);

            return(producer);
        }