Skip to content

v2.1.0

Choose a tag to compare

@releasecreator releasecreator released this 17 Dec 00:41
· 1 commit to main since this release
f79d005

New in 2.1.0

Introducing a new improved stats reporting API for the Viewer/Subscriber.

Statistics are now easier to query. The viewer now has an event that contains
statistics and diagnostic information necessary to debug streams. As opposed to the
earlier stats report API, this stats report is easier to extract the information from
and is convertible to a json string. It contains information that is related to the viewer
as a whole, but also about all the different tracks that are currently enabled. Furthermore,
each enabled track now receives its own stats object as an event that can be subscribed to.

  viewer->enable_stats(true);

  viewer->add_event_handler(
      [](const millicast::Viewer::RtsStatsEvent& evt) {
        using Level = millicast::RtsViewerStats::Level;
        std::cout << "[Stats]" << evt.viewer_stats->to_json(Level::SIMPLIFIED) << '\n';
        std::cout << "round trip time: " << evt.viewer_stats->current_round_trip_time.value_or(0.0f) << '\n';

        // Query stats related to all enabled tracks on this viewer:
        for(const auto& track_stats: evt.viewer_stats->track_stats) {
            std::cout << "bitrate: " << track_stats->bitrate_bps.value_or(0) << '\n';           
        }
      });

 // Each RtsRemoteTrack contains its own RtsTrackStats object, which is the same object
 // contained within the above viewer report.
 // track is an RtsRemoteVideoTrack* or RtsRemoteAudioTrack*
 track->add_event_handler(
     [](const millicast::RtsRemoteTrack::RtsStatsEvent& evt) {
        std::cout << "source id: " << evt.track_stats->source_id.value_or("null") << '\n';
        std::cout << "bitrate: " << evt.track_stats->bitrate_bps.value_or(0) << '\n';
     });
await subscriber.enableStats(true)
Task {
  for await statistics in subscriber.stats() {
    print(statistics.toJSON(.simplified))
    print(statistics.currentRoundTripTime?.intValue ?? "N/A")

    // Query stats related to all enabled tracks on this viewer:
    statistics.trackStats.forEach { trackStats in
      print(trackStats.bitrateBps?.intValue ?? "N/A")
    }
  }
}

// Each MCRTSRemoteTrack also emits MCTrackStats in its `stats()` AsyncStream, contains the same stats
// contained in the subscriber stats.
// Track can be an MCRTSRemoteVideoTrack or MCRTSRemoteAudioTrack
Task {
  for await trackStats in track.stats() {
    print(trackStats.sourceId ?? "N/A")
    print(trackStats.bitrateBps?.intValue ?? "N/A")
  }
}
subscriber?.enableStats(true)

launch {
    subscriber?.stats?.collect { stats ->
        Log.d("[Stats]", stats?.toJson(SubscriberStats.Level.SIMPLIFIED) ?: "No stats")
        Log.d("round trip time: ", stats?.totalRoundTripTime?.toString() ?: "0.0")

        // Query stats related to all enabled tracks on this viewer:
        stats?.trackStats()?.forEach { trackStats ->
            Log.d("bitrate: ", trackStats.bitrateBps?.toString() ?: "0")
        }
    }
}

// Each RemoteTrack contains its own TrackStats object, which is the same object
// contained within the above viewer report.
// track is an RemoteVideoTrack or RemoteAudioTrack
launch {
    track.onState.collect { state ->
        Log.d("source id: ", state.stats?.sourceId ?: "null")
        Log.d("bitrate: ", state.stats?.bitrateBps?.toString() ?: "0")
    }
}

Fixes and improvements

  • Android: Improvements to the WebRTC Android video decoder implementation.
  • Android: Introducing H265 decoding for devices that have hardware support for it.
  • Introduce handling the "updated" event from the media server which is necessary for receiving delayed audio/video tracks that are part of the same source ID.
  • Minimum supported iOS and tvOS version to 13.0