mixStreams function
Mixes video and audio streams and participants based on specified parameters.
Combines alVideoStreams, nonAlVideoStreams, and refParticipants by interleaving
muted and unmuted streams, while ensuring prioritized positioning for streams with specific identifiers.
options(MixStreamsOptions): The options for mixing streams.alVideoStreams(List<Stream>): List of "al" category video and audio streams to mix.nonAlVideoStreams(List<Stream>): List of non-"al" category streams to mix.refParticipants(List<Stream>): List of reference participants.
Returns:
A Future<List<Stream>> that completes with the mixed streams list.
Example:
final mixedStreams = await mixStreams(
options: MixStreamsOptions(
alVideoStreams: [stream1, stream2],
nonAlVideoStreams: [participant1, participant2],
refParticipants: [participant1, participant2],
),
);
print('Mixed streams: $mixedStreams');
Throws: If an error occurs during the process of mixing streams, it logs the error in debug mode and rethrows it.
Implementation
Future<List<Stream>> mixStreams({
required MixStreamsOptions options,
}) async {
try {
List<Stream> alVideoStreams = List.from(options.alVideoStreams);
List<Stream> nonAlVideoStreams = List.from(options.nonAlVideoStreams);
var refParticipants = options.refParticipants;
var mixedStreams = <Stream>[];
// Identify "youyou" or "youyouyou" stream
var youyouStream = alVideoStreams.firstWhere(
(obj) => obj.producerId == 'youyou' || obj.producerId == 'youyouyou',
orElse: () => Stream(
producerId: '',
name: '',
muted: false,
),
);
alVideoStreams = alVideoStreams
.where((obj) =>
obj.producerId != 'youyou' && obj.producerId != 'youyouyou')
.toList();
// Separate unmuted and muted streams
var unmutedAlVideoStreams = alVideoStreams.where((obj) {
var participant = refParticipants.firstWhere(
(p) => p.videoID == obj.producerId,
orElse: () => Participant(
name: 'none', videoID: '', audioID: '', muted: false));
return !obj.muted! &&
participant.muted == false &&
(participant.name != 'none');
}).toList();
var mutedAlVideoStreams = alVideoStreams.where((obj) {
var participant = refParticipants.firstWhere(
(p) => p.videoID == obj.producerId,
orElse: () => Participant(
name: 'none', videoID: '', audioID: '', muted: false));
return obj.muted! ||
(participant.name != 'none' && participant.muted == true);
}).toList();
// Add unmutedAlVideoStreams to mixedStreams
mixedStreams.addAll(unmutedAlVideoStreams);
// Interleave the mutedAlVideoStreams and nonAlVideoStreams
var nonAlIndex = 0;
for (var i = 0; i < mutedAlVideoStreams.length; i++) {
if (nonAlIndex < nonAlVideoStreams.length) {
mixedStreams.add(nonAlVideoStreams[nonAlIndex]);
nonAlIndex++;
}
mixedStreams.add(mutedAlVideoStreams[i]);
}
// Add any remaining nonAlVideoStreams
mixedStreams.addAll(nonAlVideoStreams.sublist(nonAlIndex));
// Insert 'youyou' or 'youyouyou' stream at the start
if (youyouStream.producerId.isNotEmpty) {
mixedStreams.insert(0, youyouStream);
}
return mixedStreams;
} catch (error) {
if (kDebugMode) {
print('Error mixing streams: ${error.toString()}');
}
rethrow;
}
}