ExoPlayer hỗ trợ nhiều nhu cầu phân tích hoạt động phát. Tóm lại, phân tích là việc thu thập, diễn giải, tổng hợp và tóm tắt dữ liệu từ các lượt phát. Dữ liệu này có thể được dùng trên thiết bị (ví dụ: để ghi nhật ký, gỡ lỗi hoặc thông báo các quyết định phát trong tương lai) hoặc được báo cáo cho máy chủ để theo dõi các lượt phát trên tất cả thiết bị.
Hệ thống phân tích thường cần thu thập các sự kiện trước, sau đó xử lý thêm để các sự kiện đó có ý nghĩa:
- Thu thập sự kiện: Bạn có thể thực hiện việc này bằng cách đăng ký
AnalyticsListenertrên một thực thểExoPlayer. Trình nghe phân tích đã đăng ký sẽ nhận được các sự kiện khi chúng xảy ra trong quá trình sử dụng trình phát. Mỗi sự kiện được liên kết với mục nội dung nghe nhìn tương ứng trong danh sách phát, cũng như vị trí phát và siêu dữ liệu dấu thời gian. - Xử lý sự kiện:
Một số hệ thống phân tích tải sự kiện thô lên máy chủ, trong đó tất cả quá trình xử lý sự kiện đều được thực hiện phía máy chủ. Bạn cũng có thể xử lý các sự kiện trên thiết bị. Việc này có thể đơn giản hơn hoặc giảm lượng thông tin cần tải lên. ExoPlayer cung cấp
PlaybackStatsListener, cho phép bạn thực hiện các bước xử lý sau:- Diễn giải sự kiện: Để hữu ích cho mục đích phân tích, các sự kiện cần được diễn giải trong bối cảnh của một lần phát. Ví dụ: sự kiện thô của trạng thái trình phát thay đổi thành
STATE_BUFFERINGcó thể tương ứng với quá trình lưu vào vùng đệm ban đầu, lưu lại vào vùng đệm hoặc lưu vào vùng đệm sau khi tua. - Theo dõi trạng thái: Bước này chuyển đổi các sự kiện thành bộ đếm. Ví dụ: bạn có thể chuyển đổi các sự kiện thay đổi trạng thái thành bộ đếm theo dõi thời gian đã dành cho mỗi trạng thái phát. Kết quả là một tập hợp cơ bản gồm các giá trị dữ liệu phân tích cho một lượt phát.
- Tổng hợp: Bước này kết hợp dữ liệu phân tích trên nhiều lượt phát, thường là bằng cách cộng dồn các bộ đếm.
- Tính toán chỉ số tóm tắt: Nhiều chỉ số hữu ích nhất là những chỉ số tính toán giá trị trung bình hoặc kết hợp các giá trị dữ liệu phân tích cơ bản theo những cách khác. Bạn có thể tính toán các chỉ số tóm tắt cho một hoặc nhiều lượt phát.
- Diễn giải sự kiện: Để hữu ích cho mục đích phân tích, các sự kiện cần được diễn giải trong bối cảnh của một lần phát. Ví dụ: sự kiện thô của trạng thái trình phát thay đổi thành
Thu thập sự kiện bằng AnalyticsListener
Các sự kiện phát thô từ trình phát được báo cáo cho các phương thức triển khai AnalyticsListener. Bạn có thể thêm trình nghe của riêng mình và chỉ ghi đè các phương thức mà bạn quan tâm:
Kotlin
exoPlayer.addAnalyticsListener( object : AnalyticsListener { override fun onPlaybackStateChanged(eventTime: EventTime, @Player.State state: Int) {} override fun onDroppedVideoFrames( eventTime: EventTime, droppedFrames: Int, elapsedMs: Long, ) {} } )
Java
exoPlayer.addAnalyticsListener( new AnalyticsListener() { @Override public void onPlaybackStateChanged(EventTime eventTime, @Player.State int state) {} @Override public void onDroppedVideoFrames( EventTime eventTime, int droppedFrames, long elapsedMs) {} });
EventTime được truyền đến mỗi lệnh gọi lại sẽ liên kết sự kiện với một mục nội dung nghe nhìn trong danh sách phát, cũng như siêu dữ liệu về vị trí phát và dấu thời gian:
realtimeMs: Thời gian thực của sự kiện.timeline,windowIndexvàmediaPeriodId: Xác định danh sách phát và mục trong danh sách phát có sự kiện.mediaPeriodIdchứa thông tin bổ sung không bắt buộc, chẳng hạn như cho biết liệu sự kiện có thuộc về một quảng cáo trong mục hay không.eventPlaybackPositionMs: Vị trí phát trong mục khi sự kiện xảy ra.currentTimeline,currentWindowIndex,currentMediaPeriodIdvàcurrentPlaybackPositionMs: Như đã mô tả ở trên, nhưng dành cho mục đang phát. Mục đang phát có thể khác với mục có sự kiện, ví dụ: nếu sự kiện tương ứng với việc lưu trước vào vùng đệm của mục tiếp theo sẽ phát.
Xử lý sự kiện bằng PlaybackStatsListener
PlaybackStatsListener là một AnalyticsListener triển khai quy trình xử lý sự kiện trên thiết bị. Hàm này tính PlaybackStats, với các bộ đếm và chỉ số phái sinh bao gồm:
- Chỉ số tóm tắt, ví dụ: tổng thời gian phát.
- Chỉ số về chất lượng phát thích ứng, ví dụ: độ phân giải trung bình của video.
- Chỉ số về chất lượng kết xuất, chẳng hạn như tỷ lệ khung hình bị rớt.
- Chỉ số sử dụng tài nguyên, ví dụ: số byte được đọc qua mạng.
Bạn sẽ tìm thấy danh sách đầy đủ các số lượng và chỉ số phái sinh có sẵn trong PlaybackStats Javadoc.
PlaybackStatsListener tính toán PlaybackStats riêng biệt cho từng mục nội dung nghe nhìn trong danh sách phát, cũng như từng quảng cáo phía máy khách được chèn vào các mục này. Bạn có thể cung cấp lệnh gọi lại cho PlaybackStatsListener để được thông báo về các lượt phát đã hoàn tất và sử dụng EventTime được truyền đến lệnh gọi lại để xác định lượt phát nào đã hoàn tất. Bạn có thể tổng hợp dữ liệu phân tích cho nhiều lượt phát. Bạn cũng có thể truy vấn PlaybackStats cho phiên phát hiện tại bất cứ lúc nào bằng cách sử dụng PlaybackStatsListener.getPlaybackStats().
Kotlin
exoPlayer.addAnalyticsListener( PlaybackStatsListener(/* keepHistory= */ true) { eventTime: EventTime?, playbackStats: PlaybackStats? -> // Analytics data for the session started at `eventTime` is ready. } )
Java
exoPlayer.addAnalyticsListener( new PlaybackStatsListener( /* keepHistory= */ true, (eventTime, playbackStats) -> { // Analytics data for the session started at `eventTime` is ready. }));
Hàm khởi tạo của PlaybackStatsListener cung cấp tuỳ chọn để giữ lại toàn bộ nhật ký của các sự kiện đã xử lý. Xin lưu ý rằng việc này có thể làm tăng mức hao tổn bộ nhớ không xác định, tuỳ thuộc vào thời lượng phát và số lượng sự kiện. Do đó, bạn chỉ nên bật tính năng này nếu cần truy cập vào toàn bộ nhật ký của các sự kiện đã xử lý, thay vì chỉ truy cập vào dữ liệu phân tích cuối cùng.
Xin lưu ý rằng PlaybackStats sử dụng một tập hợp trạng thái mở rộng để không chỉ cho biết trạng thái của nội dung nghe nhìn mà còn cho biết ý định của người dùng để phát và thông tin chi tiết hơn, chẳng hạn như lý do quá trình phát bị gián đoạn hoặc kết thúc:
| Trạng thái phát | Ý định chơi của người dùng | Không có ý định chơi |
|---|---|---|
| Trước khi phát | JOINING_FOREGROUND |
NOT_STARTED, JOINING_BACKGROUND |
| Đang phát | PLAYING |
|
| Quá trình phát bị gián đoạn | BUFFERING, SEEKING |
PAUSED, PAUSED_BUFFERING, SUPPRESSED, SUPPRESSED_BUFFERING, INTERRUPTED_BY_AD |
| Trạng thái kết thúc | ENDED, STOPPED, FAILED, ABANDONED |
Ý định của người dùng để phát là yếu tố quan trọng để phân biệt thời điểm người dùng chủ động chờ tiếp tục phát với thời gian chờ thụ động. Ví dụ: PlaybackStats.getTotalWaitTimeMs trả về tổng thời gian ở các trạng thái JOINING_FOREGROUND, BUFFERING và SEEKING, nhưng không trả về thời gian khi quá trình phát bị tạm dừng. Tương tự, PlaybackStats.getTotalPlayAndWaitTimeMs sẽ trả về tổng thời gian mà người dùng có ý định chơi, tức là tổng thời gian chờ hoạt động và tổng thời gian ở trạng thái PLAYING.
Sự kiện đã xử lý và diễn giải
Bạn có thể ghi lại các sự kiện đã xử lý và diễn giải bằng cách sử dụng PlaybackStatsListener với keepHistory=true. PlaybackStats thu được sẽ chứa các danh sách sự kiện sau:
playbackStateHistory: Danh sách theo thứ tự các trạng thái phát mở rộng cùng vớiEventTimemà các trạng thái đó bắt đầu áp dụng. Bạn cũng có thể sử dụngPlaybackStats.getPlaybackStateAtTimeđể tra cứu trạng thái tại một thời điểm nhất định.mediaTimeHistory: Nhật ký về các cặp thời gian đồng hồ treo tường và thời gian nội dung nghe nhìn cho phép bạn tái tạo phần nào của nội dung nghe nhìn đã được phát vào thời điểm nào. Bạn cũng có thể sử dụngPlaybackStats.getMediaTimeMsAtRealtimeMsđể tra cứu vị trí phát tại một thời điểm nhất định trên đồng hồ treo tường.videoFormatHistoryvàaudioFormatHistory: Danh sách theo thứ tự của các định dạng video và âm thanh được dùng trong quá trình phát, cùng vớiEventTimemà các định dạng đó bắt đầu được dùng.fatalErrorHistoryvànonFatalErrorHistory: Danh sách theo thứ tự về các lỗi nghiêm trọng và không nghiêm trọng kèm theoEventTimexảy ra lỗi. Lỗi nghiêm trọng là những lỗi khiến quá trình phát bị kết thúc, trong khi lỗi không nghiêm trọng có thể khôi phục được.
Dữ liệu phân tích về một lượt phát
Dữ liệu này được thu thập tự động nếu bạn sử dụng PlaybackStatsListener, ngay cả khi bạn dùng keepHistory=false. Giá trị cuối cùng là các trường công khai mà bạn có thể tìm thấy trong PlaybackStats Javadoc và thời lượng trạng thái phát do getPlaybackStateDurationMs trả về. Để thuận tiện, bạn cũng sẽ tìm thấy các phương thức như getTotalPlayTimeMs và getTotalWaitTimeMs trả về thời lượng của các tổ hợp trạng thái phát cụ thể.
Kotlin
Log.d( "DEBUG", "Playback summary: " + "play time = " + playbackStats.totalPlayTimeMs + ", rebuffers = " + playbackStats.totalRebufferCount, )
Java
Log.d( "DEBUG", "Playback summary: " + "play time = " + playbackStats.getTotalPlayTimeMs() + ", rebuffers = " + playbackStats.totalRebufferCount);
Dữ liệu phân tích tổng hợp của nhiều lượt phát
Bạn có thể kết hợp nhiều PlaybackStats với nhau bằng cách gọi PlaybackStats.merge. PlaybackStats thu được sẽ chứa dữ liệu tổng hợp của tất cả các lượt phát đã hợp nhất. Xin lưu ý rằng báo cáo này sẽ không chứa nhật ký của từng sự kiện phát riêng lẻ vì không thể tổng hợp các sự kiện này.
Bạn có thể sử dụng PlaybackStatsListener.getCombinedPlaybackStats để xem thông tin tổng hợp về tất cả dữ liệu phân tích được thu thập trong suốt thời gian hoạt động của một PlaybackStatsListener.
Chỉ số tóm tắt được tính toán
Ngoài dữ liệu phân tích cơ bản, PlaybackStats còn cung cấp nhiều phương thức để tính toán các chỉ số tóm tắt.
Kotlin
Log.d( "DEBUG", "Additional calculated summary metrics: " + "average video bitrate = " + playbackStats.meanVideoFormatBitrate + ", mean time between rebuffers = " + playbackStats.meanTimeBetweenRebuffers, )
Java
Log.d( "DEBUG", "Additional calculated summary metrics: " + "average video bitrate = " + playbackStats.getMeanVideoFormatBitrate() + ", mean time between rebuffers = " + playbackStats.getMeanTimeBetweenRebuffers());
Chủ đề nâng cao
Liên kết dữ liệu phân tích với siêu dữ liệu phát
Khi thu thập dữ liệu phân tích cho từng lượt phát, bạn nên liên kết dữ liệu phân tích lượt phát với siêu dữ liệu về nội dung nghe nhìn đang được phát.
Bạn nên đặt siêu dữ liệu dành riêng cho nội dung nghe nhìn bằng MediaItem.Builder.setTag.
Thẻ nội dung nghe nhìn là một phần của EventTime được báo cáo cho các sự kiện thô và khi PlaybackStats kết thúc, vì vậy, bạn có thể truy xuất thẻ này khi xử lý dữ liệu phân tích tương ứng:
Kotlin
PlaybackStatsListener(/* keepHistory= */ false) { eventTime: EventTime, playbackStats: PlaybackStats -> val mediaTag = eventTime.timeline .getWindow(eventTime.windowIndex, Timeline.Window()) .mediaItem .localConfiguration ?.tag // Report playbackStats with mediaTag metadata. }
Java
new PlaybackStatsListener( /* keepHistory= */ false, (eventTime, playbackStats) -> { Object mediaTag = eventTime.timeline.getWindow(eventTime.windowIndex, new Timeline.Window()) .mediaItem .localConfiguration .tag; // Report playbackStats with mediaTag metadata. });
Báo cáo sự kiện phân tích tuỳ chỉnh
Trong trường hợp cần thêm sự kiện tuỳ chỉnh vào dữ liệu phân tích, bạn cần lưu các sự kiện này trong cấu trúc dữ liệu của riêng mình và kết hợp chúng với PlaybackStats được báo cáo sau này. Nếu cần, bạn có thể mở rộng DefaultAnalyticsCollector để có thể tạo các thực thể EventTime cho sự kiện tuỳ chỉnh và gửi các thực thể đó đến trình nghe đã đăng ký như trong ví dụ sau.
Kotlin
@OptIn(UnstableApi::class) private interface ExtendedListener : AnalyticsListener { fun onCustomEvent(eventTime: EventTime) } @OptIn(UnstableApi::class) private class ExtendedCollector : DefaultAnalyticsCollector(Clock.DEFAULT) { fun customEvent() { val eventTime = super.generateCurrentPlayerMediaPeriodEventTime() super.sendEvent(eventTime, CUSTOM_EVENT_ID) { listener: AnalyticsListener -> if (listener is ExtendedListener) { listener.onCustomEvent(eventTime) } } } } @OptIn(UnstableApi::class) fun useExtendedAnalyticsCollector(context: Context) { // Usage - Setup and listener registration. val player = ExoPlayer.Builder(context).setAnalyticsCollector(ExtendedCollector()).build() player.addAnalyticsListener( object : ExtendedListener { override fun onCustomEvent(eventTime: EventTime) { // Save custom event for analytics data. } } ) // Usage - Triggering the custom event. (player.analyticsCollector as ExtendedCollector).customEvent() }
Java
@OptIn(markerClass = UnstableApi.class) private interface ExtendedListener extends AnalyticsListener { void onCustomEvent(EventTime eventTime); } @OptIn(markerClass = UnstableApi.class) private static class ExtendedCollector extends DefaultAnalyticsCollector { public ExtendedCollector() { super(Clock.DEFAULT); } public void customEvent() { AnalyticsListener.EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime(); sendEvent( eventTime, CUSTOM_EVENT_ID, listener -> { if (listener instanceof ExtendedListener) { ((ExtendedListener) listener).onCustomEvent(eventTime); } }); } } @OptIn(markerClass = UnstableApi.class) public static void useExtendedAnalyticsCollector(Context context) { // Usage - Setup and listener registration. ExoPlayer player = new ExoPlayer.Builder(context).setAnalyticsCollector(new ExtendedCollector()).build(); player.addAnalyticsListener( (ExtendedListener) eventTime -> { // Save custom event for analytics data. }); // Usage - Triggering the custom event. ((ExtendedCollector) player.getAnalyticsCollector()).customEvent(); }
Theo dõi cờ tính năng và chế độ Canary
Khi tiến hành thử nghiệm A/B hoặc đánh giá tác động của các tính năng tối ưu hoá mới của Media3, bạn có thể liên kết dữ liệu phân tích hoạt động phát với cờ tính năng đang hoạt động và chế độ Canary.
Bạn có thể truy vấn Flags.getLogString hoặc kiểm tra các cơ chế ghi đè cờ cụ thể bằng cách sử dụng Flags.getEnabledOverrides và Flags.getDisabledOverrides để đưa trạng thái cờ vào tải trọng phân tích tuỳ chỉnh hoặc siêu dữ liệu phiên.