onActiveSpeakerLoop method

void onActiveSpeakerLoop()

Implementation

void onActiveSpeakerLoop() async {
  String? nextActiveSpeaker;
  // idc about screen sharing atm.
  final userMediaStreamsCopyList = List.from(userMediaStreams);
  for (final stream in userMediaStreamsCopyList) {
    if (stream.userId == client.userID && stream.pc == null) {
      continue;
    }

    final List<StatsReport> statsReport = await stream.pc!.getStats();
    statsReport
        .removeWhere((element) => !element.values.containsKey('audioLevel'));

    // https://www.w3.org/TR/webrtc-stats/#summary
    final otherPartyAudioLevel = statsReport
        .singleWhereOrNull((element) =>
            element.type == 'inbound-rtp' &&
            element.values['kind'] == 'audio')
        ?.values['audioLevel'];
    if (otherPartyAudioLevel != null) {
      audioLevelsMap[stream.userId] = otherPartyAudioLevel;
    }

    // https://www.w3.org/TR/webrtc-stats/#dom-rtcstatstype-media-source
    // firefox does not seem to have this though. Works on chrome and android
    final ownAudioLevel = statsReport
        .singleWhereOrNull((element) =>
            element.type == 'media-source' &&
            element.values['kind'] == 'audio')
        ?.values['audioLevel'];
    if (ownAudioLevel != null &&
        audioLevelsMap[client.userID] != ownAudioLevel) {
      audioLevelsMap[client.userID!] = ownAudioLevel;
    }
  }

  double maxAudioLevel = double.negativeInfinity;
  // TODO: we probably want a threshold here?
  audioLevelsMap.forEach((key, value) {
    if (value > maxAudioLevel) {
      nextActiveSpeaker = key;
      maxAudioLevel = value;
    }
  });

  if (nextActiveSpeaker != null && activeSpeaker != nextActiveSpeaker) {
    activeSpeaker = nextActiveSpeaker;
    onGroupCallEvent.add(GroupCallEvent.ActiveSpeakerChanged);
  }
  activeSpeakerLoopTimeout?.cancel();
  activeSpeakerLoopTimeout =
      Timer(activeSpeakerInterval, onActiveSpeakerLoop);
}