/// <summary> /// Create a DataConsumer. /// </summary> /// <param name="dataConsumerOptions"></param> /// <returns></returns> public async Task <DataConsumer> ConsumeDataAsync(DataConsumerOptions dataConsumerOptions) { _logger.LogDebug($"ConsumeDataAsync() | Transport:{TransportId}"); if (dataConsumerOptions.DataProducerId.IsNullOrWhiteSpace()) { throw new Exception("Missing dataProducerId"); } var dataProducer = GetDataProducerById(dataConsumerOptions.DataProducerId); if (dataProducer == null) { throw new Exception($"DataProducer with id {dataConsumerOptions.DataProducerId} not found"); } DataProducerType type; SctpStreamParameters?sctpStreamParameters = null; int sctpStreamId = -1; // If this is not a DirectTransport, use sctpStreamParameters from the // DataProducer (if type 'sctp') unless they are given in method parameters. // TODO: (alby)反模式 if (GetType() != typeof(DirectTransport)) { type = DataProducerType.Sctp; sctpStreamParameters = dataProducer.SctpStreamParameters.DeepClone <SctpStreamParameters>(); // This may throw. lock (_sctpStreamIdsLock) { sctpStreamId = GetNextSctpStreamId(); if (_sctpStreamIds == null || sctpStreamId > _sctpStreamIds.Length - 1) { throw new IndexOutOfRangeException(nameof(_sctpStreamIds)); } _sctpStreamIds[sctpStreamId] = 1; sctpStreamParameters.StreamId = sctpStreamId; } } // If this is a DirectTransport, sctpStreamParameters must not be used. else { type = DataProducerType.Direct; if (dataConsumerOptions.Ordered.HasValue || dataConsumerOptions.MaxPacketLifeTime.HasValue || dataConsumerOptions.MaxRetransmits.HasValue ) { _logger.LogWarning("ConsumeDataAsync() | Ordered, maxPacketLifeTime and maxRetransmits are ignored when consuming data on a DirectTransport"); } } var @internal = new DataConsumerInternalData ( Internal.RouterId, Internal.TransportId, dataConsumerOptions.DataProducerId, Guid.NewGuid().ToString() ); var reqData = new { Type = type.GetEnumStringValue(), SctpStreamParameters = sctpStreamParameters, dataProducer.Label, dataProducer.Protocol }; var status = await Channel.RequestAsync(MethodId.TRANSPORT_CONSUME_DATA, @internal, reqData); var responseData = JsonConvert.DeserializeObject <TransportDataConsumeResponseData>(status !); var dataConsumer = new DataConsumer(_loggerFactory, @internal, responseData.SctpStreamParameters, responseData.Label, responseData.Protocol, Channel, PayloadChannel, AppData); dataConsumer.On("@close", async _ => { await DataConsumersLock.WaitAsync(); try { DataConsumers.Remove(dataConsumer.DataConsumerId); lock (_sctpStreamIdsLock) { if (_sctpStreamIds != null && sctpStreamId >= 0) { _sctpStreamIds[sctpStreamId] = 0; } } } finally { DataConsumersLock.Set(); } }); dataConsumer.On("@dataproducerclose", async _ => { await DataConsumersLock.WaitAsync(); try { DataConsumers.Remove(dataConsumer.DataConsumerId); lock (_sctpStreamIdsLock) { if (_sctpStreamIds != null && sctpStreamId >= 0) { _sctpStreamIds[sctpStreamId] = 0; } } } finally { DataConsumersLock.Set(); } }); await DataConsumersLock.WaitAsync(); try { DataConsumers[dataConsumer.DataConsumerId] = dataConsumer; } finally { DataConsumersLock.Set(); } // Emit observer event. Observer.Emit("newdataconsumer", dataConsumer); return(dataConsumer); }