예제 #1
0
        /// <summary>
        /// Create a Consumer.
        /// </summary>
        /// <param name="consumerOptions"></param>
        /// <returns></returns>
        public virtual async Task <Consumer> ConsumeAsync(ConsumerOptions consumerOptions)
        {
            _logger.LogDebug($"ConsumeAsync() | Transport:{TransportId}");

            if (consumerOptions.ProducerId.IsNullOrWhiteSpace())
            {
                throw new ArgumentException("missing producerId");
            }

            if (consumerOptions.RtpCapabilities == null)
            {
                throw new ArgumentException(nameof(consumerOptions.RtpCapabilities));
            }

            if (consumerOptions.Mid != null && consumerOptions.Mid.Length == 0)
            {
                throw new ArgumentException(nameof(consumerOptions.Mid));
            }

            if (!consumerOptions.Paused.HasValue)
            {
                consumerOptions.Paused = false;
            }

            // This may throw.
            ORTC.ValidateRtpCapabilities(consumerOptions.RtpCapabilities);

            var producer = GetProducerById(consumerOptions.ProducerId);

            if (producer == null)
            {
                throw new NullReferenceException($"Producer with id {consumerOptions.ProducerId} not found");
            }

            var pipe = consumerOptions.Pipe.HasValue && consumerOptions.Pipe.Value;
            // This may throw.
            var rtpParameters = ORTC.GetConsumerRtpParameters(producer.ConsumableRtpParameters, consumerOptions.RtpCapabilities, pipe);

            if (!pipe)
            {
                if (consumerOptions.Mid != null)
                {
                    rtpParameters.Mid = consumerOptions.Mid;
                }
                else
                {
                    lock (_nextMidForConsumersLock)
                    {
                        // Set MID.
                        rtpParameters.Mid = (_nextMidForConsumers++).ToString();

                        // We use up to 8 bytes for MID (string).
                        if (_nextMidForConsumers == 100_000_000)
                        {
                            _logger.LogDebug($"ConsumeAsync() | Reaching max MID value {_nextMidForConsumers}");
                            _nextMidForConsumers = 0;
                        }
                    }
                }
            }

            var @internal = new ConsumerInternalData
                            (
                Internal.RouterId,
                Internal.TransportId,
                consumerOptions.ProducerId,
                Guid.NewGuid().ToString()
                            );

            var reqData = new
            {
                producer.Kind,
                RtpParameters          = rtpParameters,
                Type                   = pipe ? ProducerType.Pipe : producer.Type,
                ConsumableRtpEncodings = producer.ConsumableRtpParameters.Encodings,
                consumerOptions.Paused,
                consumerOptions.PreferredLayers
            };

            var resData = await Channel.RequestAsync(MethodId.TRANSPORT_CONSUME, @internal, reqData);

            var responseData = JsonSerializer.Deserialize <TransportConsumeResponseData>(resData !, ObjectExtensions.DefaultJsonSerializerOptions) !;

            var data = new
            {
                producer.Kind,
                RtpParameters = rtpParameters,
                Type          = (ConsumerType)(pipe ? ProducerType.Pipe : producer.Type), // 注意:类型转换。ProducerType 的每一种值在 ConsumerType 都有对应且相同的值。
            };

            var consumer = new Consumer(_loggerFactory,
                                        @internal,
                                        data.Kind,
                                        data.RtpParameters,
                                        data.Type,
                                        Channel,
                                        PayloadChannel,
                                        AppData,
                                        responseData.Paused,
                                        responseData.ProducerPaused,
                                        responseData.Score,
                                        responseData.PreferredLayers);

            consumer.On("@close", async(_, _) =>
            {
                await ConsumersLock.WaitAsync();
                try
                {
                    Consumers.Remove(consumer.ConsumerId);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "@close");
                }
                finally
                {
                    ConsumersLock.Set();
                }
            });
            consumer.On("@producerclose", async(_, _) =>
            {
                await ConsumersLock.WaitAsync();
                try
                {
                    Consumers.Remove(consumer.ConsumerId);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "@producerclose");
                }
                finally
                {
                    ConsumersLock.Set();
                }
            });

            await ConsumersLock.WaitAsync();

            try
            {
                Consumers[consumer.ConsumerId] = consumer;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "ConsumeAsync()");
            }
            finally
            {
                ConsumersLock.Set();
            }

            // Emit observer event.
            Observer.Emit("newconsumer", consumer);

            return(consumer);
        }