mediasoup 3.24.1 → 3.24.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/package.json +3 -3
- package/worker/include/RTC/DataConsumer.hpp +12 -0
- package/worker/src/RTC/DataConsumer.cpp +59 -67
- package/worker/src/RTC/Router.cpp +44 -31
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
### NEXT
|
|
4
4
|
|
|
5
|
+
### 3.24.2
|
|
6
|
+
|
|
7
|
+
- Worker: Verify `DataConsumer` subchannels before cloning the message ([PR #1880](https://github.com/versatica/mediasoup/pull/1880)).
|
|
8
|
+
|
|
5
9
|
### 3.24.1
|
|
6
10
|
|
|
7
11
|
- Worker: Don't check `ignoredSubchannel` in piped `DataConsumers` ([PR #1879](https://github.com/versatica/mediasoup/pull/1879)).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mediasoup",
|
|
3
|
-
"version": "3.24.
|
|
3
|
+
"version": "3.24.2",
|
|
4
4
|
"description": "Cutting Edge WebRTC Video Conferencing",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Iñaki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)",
|
|
@@ -121,8 +121,8 @@
|
|
|
121
121
|
"@types/debug": "^4.1.13",
|
|
122
122
|
"@types/ini": "^4.1.1",
|
|
123
123
|
"@types/jest": "^30.0.0",
|
|
124
|
-
"@types/node": "^26.
|
|
125
|
-
"eslint": "^10.8.
|
|
124
|
+
"@types/node": "^26.2.0",
|
|
125
|
+
"eslint": "^10.8.1",
|
|
126
126
|
"eslint-config-prettier": "^10.1.8",
|
|
127
127
|
"eslint-plugin-jest": "^29.16.0",
|
|
128
128
|
"eslint-plugin-prettier": "^5.5.6",
|
|
@@ -93,6 +93,18 @@ namespace RTC
|
|
|
93
93
|
void SctpBufferedAmountLow(uint32_t bufferedAmount) const;
|
|
94
94
|
void SctpSendBufferFull() const;
|
|
95
95
|
void DataProducerClosed();
|
|
96
|
+
/**
|
|
97
|
+
* Verifies if given subchannels would allow a message to be delivered to
|
|
98
|
+
* the DataConsumer endpoint or not.
|
|
99
|
+
*
|
|
100
|
+
* @remarks
|
|
101
|
+
* - This method must be called before invoking `SendMessage()` if subchannels
|
|
102
|
+
* are given to `SendMessage()`.
|
|
103
|
+
*/
|
|
104
|
+
bool VerifySubchannels(
|
|
105
|
+
const std::vector<uint16_t>& subchannels,
|
|
106
|
+
std::optional<uint16_t> requiredSubchannel,
|
|
107
|
+
std::optional<uint16_t> ignoredSubchannel) const;
|
|
96
108
|
bool SendMessage(
|
|
97
109
|
RTC::SCTP::Message message,
|
|
98
110
|
std::vector<uint16_t>& subchannels,
|
|
@@ -482,101 +482,93 @@ namespace RTC
|
|
|
482
482
|
this->listener->OnDataConsumerDataProducerClosed(this);
|
|
483
483
|
}
|
|
484
484
|
|
|
485
|
-
bool DataConsumer::
|
|
486
|
-
|
|
487
|
-
std::vector<uint16_t>& subchannels,
|
|
485
|
+
bool DataConsumer::VerifySubchannels(
|
|
486
|
+
const std::vector<uint16_t>& subchannels,
|
|
488
487
|
std::optional<uint16_t> requiredSubchannel,
|
|
489
|
-
std::optional<uint16_t> ignoredSubchannel
|
|
490
|
-
const onQueuedCallback* cb)
|
|
488
|
+
std::optional<uint16_t> ignoredSubchannel) const
|
|
491
489
|
{
|
|
492
490
|
MS_TRACE();
|
|
493
491
|
|
|
494
|
-
if
|
|
492
|
+
// Only verify subchannels if this is not a piped DataConsumer or if this
|
|
493
|
+
// is a piped DataConsumer and it's subscribed to at least one subchannel.
|
|
494
|
+
const bool verifySubchannels = !this->pipe || !this->subchannels.empty();
|
|
495
|
+
|
|
496
|
+
if (!verifySubchannels)
|
|
495
497
|
{
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
(*cb)(false, false);
|
|
499
|
-
delete cb;
|
|
500
|
-
}
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
501
500
|
|
|
501
|
+
// If a required subchannel is given, verify that this data consumer is
|
|
502
|
+
// subscribed to it.
|
|
503
|
+
if (requiredSubchannel.has_value() && !this->subchannels.contains(requiredSubchannel.value()))
|
|
504
|
+
{
|
|
502
505
|
return false;
|
|
503
506
|
}
|
|
504
507
|
|
|
505
|
-
//
|
|
506
|
-
//
|
|
507
|
-
|
|
508
|
+
// If an ignored subchannel is given, verify that this data consumer is
|
|
509
|
+
// not subscribed to it, otherwise don't send this message to it.
|
|
510
|
+
// NOTE: We don't check this in piped DataConsumers on purpose. Otherwise
|
|
511
|
+
// a message generated by peer X and forwarded to all peers in another
|
|
512
|
+
// host wouldn't pass this filter in the local PipeTransport.
|
|
513
|
+
if (!this->pipe && ignoredSubchannel.has_value() && this->subchannels.contains(ignoredSubchannel.value()))
|
|
514
|
+
{
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
508
517
|
|
|
509
|
-
|
|
518
|
+
// If subchannels are given, verify that this data consumer is subscribed
|
|
519
|
+
// to at least one of them.
|
|
520
|
+
if (!subchannels.empty())
|
|
510
521
|
{
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
522
|
+
bool subchannelMatched{ false };
|
|
523
|
+
|
|
524
|
+
for (const auto subchannel : subchannels)
|
|
514
525
|
{
|
|
515
|
-
if (
|
|
526
|
+
if (this->subchannels.contains(subchannel))
|
|
516
527
|
{
|
|
517
|
-
|
|
518
|
-
delete cb;
|
|
519
|
-
}
|
|
528
|
+
subchannelMatched = true;
|
|
520
529
|
|
|
521
|
-
|
|
530
|
+
break;
|
|
531
|
+
}
|
|
522
532
|
}
|
|
523
533
|
|
|
524
|
-
|
|
525
|
-
// not subscribed to it, otherwise don't send this message to it.
|
|
526
|
-
// NOTE: We don't check this in piped DataConsumers on purpose. Otherwise
|
|
527
|
-
// a message generated by peer X and forwarded to all peers in another
|
|
528
|
-
// host wouldn't pass this filter in the local PipeTransport.
|
|
529
|
-
if (
|
|
530
|
-
!this->pipe && ignoredSubchannel.has_value() &&
|
|
531
|
-
this->subchannels.contains(ignoredSubchannel.value()))
|
|
534
|
+
if (!subchannelMatched)
|
|
532
535
|
{
|
|
533
|
-
if (cb)
|
|
534
|
-
{
|
|
535
|
-
(*cb)(false, false);
|
|
536
|
-
delete cb;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
536
|
return false;
|
|
540
537
|
}
|
|
538
|
+
}
|
|
541
539
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
if (!subchannels.empty())
|
|
545
|
-
{
|
|
546
|
-
bool subchannelMatched{ false };
|
|
547
|
-
|
|
548
|
-
for (const auto subchannel : subchannels)
|
|
549
|
-
{
|
|
550
|
-
if (this->subchannels.contains(subchannel))
|
|
551
|
-
{
|
|
552
|
-
subchannelMatched = true;
|
|
553
|
-
|
|
554
|
-
break;
|
|
555
|
-
}
|
|
556
|
-
}
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
557
542
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
543
|
+
bool DataConsumer::SendMessage(
|
|
544
|
+
RTC::SCTP::Message message,
|
|
545
|
+
std::vector<uint16_t>& subchannels,
|
|
546
|
+
std::optional<uint16_t> requiredSubchannel,
|
|
547
|
+
std::optional<uint16_t> ignoredSubchannel,
|
|
548
|
+
const onQueuedCallback* cb)
|
|
549
|
+
{
|
|
550
|
+
MS_TRACE();
|
|
565
551
|
|
|
566
|
-
|
|
567
|
-
|
|
552
|
+
if (!IsActive())
|
|
553
|
+
{
|
|
554
|
+
if (cb)
|
|
555
|
+
{
|
|
556
|
+
(*cb)(false, false);
|
|
557
|
+
delete cb;
|
|
568
558
|
}
|
|
559
|
+
|
|
560
|
+
return false;
|
|
569
561
|
}
|
|
570
562
|
|
|
571
|
-
// If this is a piped DataConsumer, encode given subchannels
|
|
572
|
-
//
|
|
573
|
-
//
|
|
563
|
+
// If this is a piped DataConsumer, encode given subchannels at the beginning
|
|
564
|
+
// of the message payload so the receiving PipeTransport can decode them and
|
|
565
|
+
// apply them to its own DataConsumers.
|
|
574
566
|
if (this->pipe)
|
|
575
567
|
{
|
|
576
|
-
//
|
|
577
|
-
//
|
|
568
|
+
// Encode just those subchannels this DataConsumer is subscribed to.
|
|
569
|
+
// Otherwise the receiving Router would deliver the message to
|
|
578
570
|
// DataConsumers subscribed to subchannels that this pipe does not carry.
|
|
579
|
-
const bool reduceSubchannels =
|
|
571
|
+
const bool reduceSubchannels = !this->subchannels.empty();
|
|
580
572
|
|
|
581
573
|
std::vector<uint16_t> reducedSubchannels;
|
|
582
574
|
|
|
@@ -917,44 +917,57 @@ namespace RTC
|
|
|
917
917
|
|
|
918
918
|
auto& dataConsumers = this->mapDataProducerDataConsumers.at(dataProducer);
|
|
919
919
|
|
|
920
|
-
|
|
920
|
+
const auto getStreamId = [](const RTC::DataConsumer* dataConsumer) -> uint16_t
|
|
921
921
|
{
|
|
922
|
-
|
|
922
|
+
return dataConsumer->GetType() == DataConsumer::Type::SCTP
|
|
923
|
+
? dataConsumer->GetSctpStreamParameters().streamId
|
|
924
|
+
: 0;
|
|
925
|
+
};
|
|
923
926
|
|
|
924
|
-
|
|
927
|
+
// NOTE: We don't send the message to a matching DataConsumer right away.
|
|
928
|
+
// Instead we hold it as pending until we know whether there is another
|
|
929
|
+
// matching DataConsumer after it. This way just the last matching one needs
|
|
930
|
+
// no message clone since it can take ownership of the original message.
|
|
931
|
+
RTC::DataConsumer* pendingDataConsumer{ nullptr };
|
|
932
|
+
|
|
933
|
+
for (auto* dataConsumer : dataConsumers)
|
|
934
|
+
{
|
|
935
|
+
// Verify subchannels first to avoid cloning the message needlessly.
|
|
936
|
+
if (!dataConsumer->IsActive() || !dataConsumer->VerifySubchannels(subchannels, requiredSubchannel, ignoredSubchannel))
|
|
925
937
|
{
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
? dataConsumer->GetSctpStreamParameters().streamId
|
|
929
|
-
: 0);
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
930
940
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
dataConsumer->SendMessage(
|
|
941
|
-
std::move(message), subchannels, requiredSubchannel, ignoredSubchannel);
|
|
942
|
-
}
|
|
943
|
-
// NOTE: Here we are cloning the message before passing it to each
|
|
944
|
-
// DataConsumer because each DataConsumer will pass std::move(message)
|
|
945
|
-
// internally to its SCTP association.
|
|
946
|
-
else
|
|
947
|
-
{
|
|
948
|
-
auto clonedMessage = message.Clone();
|
|
941
|
+
// There is a matching DataConsumer after the pending one, so the pending
|
|
942
|
+
// one must be given a clone of the message.
|
|
943
|
+
// NOTE: Here we are cloning the message before passing it to the
|
|
944
|
+
// DataConsumer because each DataConsumer will pass std::move(message)
|
|
945
|
+
// internally to its SCTP association.
|
|
946
|
+
if (pendingDataConsumer)
|
|
947
|
+
{
|
|
948
|
+
auto clonedMessage = message.Clone();
|
|
949
949
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
950
|
+
// We must update the message`s `streamId` for each destination
|
|
951
|
+
// DataConsumer.
|
|
952
|
+
clonedMessage.SetStreamId(getStreamId(pendingDataConsumer));
|
|
953
953
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
}
|
|
954
|
+
pendingDataConsumer->SendMessage(
|
|
955
|
+
std::move(clonedMessage), subchannels, requiredSubchannel, ignoredSubchannel);
|
|
957
956
|
}
|
|
957
|
+
|
|
958
|
+
pendingDataConsumer = dataConsumer;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// The last matching DataConsumer (if any) takes ownership of the original
|
|
962
|
+
// message.
|
|
963
|
+
if (pendingDataConsumer)
|
|
964
|
+
{
|
|
965
|
+
// We must update the message`s `streamId` for each destination
|
|
966
|
+
// DataConsumer.
|
|
967
|
+
message.SetStreamId(getStreamId(pendingDataConsumer));
|
|
968
|
+
|
|
969
|
+
pendingDataConsumer->SendMessage(
|
|
970
|
+
std::move(message), subchannels, requiredSubchannel, ignoredSubchannel);
|
|
958
971
|
}
|
|
959
972
|
}
|
|
960
973
|
|