ExoPlayer hỗ trợ nhiều nhu cầu phân tích quá trình phát. Cuối cùng, hoạt động phân tích phục vụ 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 sử 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ị.
Trước tiên, hệ thống phân tích thường cần thu thập các sự kiện, sau đó xử lý thêm các sự kiện đó để 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ý
AnalyticsListener
trên một thực thểExoPlayer
. Các trình nghe phân tích đã đăng ký sẽ nhận được sự kiện khi sự kiện đó 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ư siêu dữ liệu về vị trí phát và dấu thời gian. - Xử lý sự kiện: Một số hệ thống phân tích tải các sự kiện thô lên máy chủ, trong đó toàn bộ quá trình xử lý sự kiện đượ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 ngữ cảnh của một lần phát. Ví dụ: sự kiện thô của một thay đổi trạng thái trình phát thành
STATE_BUFFERING
có thể tương ứng với việc lưu vào bộ đệm ban đầu, lưu vào bộ đệm lại hoặc lưu vào bộ đệm xảy ra sau khi tìm kiếm. - Theo dõi trạng thái: Bước này chuyển đổi 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ác giá trị dữ liệu phân tích cơ bản 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 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. Hệ thống có thể tính 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 ngữ cảnh của một lần phát. Ví dụ: sự kiện thô của một thay đổi trạng thái trình phát 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 hoạt động triển khai AnalyticsListener
. Bạn có thể dễ dàng thêm trình nghe của riêng mình và chỉ ghi đè những 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 đa phương tiện trong danh sách phát, cũng như với siêu dữ liệu về vị trí phát và dấu thời gian:
realtimeMs
: Thời gian theo đồng hồ treo tường của sự kiện.timeline
,windowIndex
vàmediaPeriodId
: Xác định danh sách phát và mục trong danh sách phát chứa sự kiện.mediaPeriodId
chứa thông tin bổ sung không bắt buộc, ví dụ: cho biết liệu sự kiện có thuộc về một quảng cáo trong mặt hàng hay không.eventPlaybackPositionMs
: Vị trí phát trong mục khi sự kiện xảy ra.currentTimeline
,currentWindowIndex
,currentMediaPeriodId
vàcurrentPlaybackPositionMs
: Tương tự như 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 thuộc sự kiện, ví dụ: nếu sự kiện tương ứng với việc lưu vào bộ đệm trước 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 quá trình xử lý sự kiện trên thiết bị. Phương thức này tính toán PlaybackStats
, với các bộ đếm và chỉ số phái sinh bao gồm:
- Các chỉ số tóm tắt, ví dụ như tổng thời gian phát.
- Các chỉ số về chất lượng phát thích ứng, chẳng hạn như độ phân giải video trung bình.
- Chỉ số chất lượng kết xuất, ví dụ: tỷ lệ khung hình bị bỏ qua.
- Chỉ số sử dụng tài nguyên, ví dụ như số byte đọc qua mạng.
Bạn sẽ 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 cho từng mục nội dung đa phương tiện trong danh sách phát và cả quảng cáo phía máy khách được chèn trong 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ần phát đã kết thúc và sử dụng EventTime
được truyền đến lệnh gọi lại để xác định lần phát nào đã kết thúc. Bạn có thể tổng hợp dữ liệu phân tích cho nhiều lần 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 phát sinh 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ý 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 phát của người dùng 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 |
Phát chủ động | PLAYING |
|
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 phát của người dùng 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 ở trạng thái JOINING_FOREGROUND
, BUFFERING
và SEEKING
, nhưng không phải thời gian tạm dừng phát. Tương tự, PlaybackStats.getTotalPlayAndWaitTimeMs
sẽ trả về tổng thời gian người dùng có ý định chơi, tức là tổng thời gian chờ đang 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 vớiEventTime
mà các trạng thái này 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 đồng hồ thực tế nhất định.mediaTimeHistory
: Nhật ký về các cặp thời gian đồng hồ và thời gian phát nội dung nghe nhìn cho phép bạn tái tạo những phần nội dung nghe nhìn đã phát tại 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 gian nhất định theo đồng hồ.videoFormatHistory
vàaudioFormatHistory
: Danh sách thứ tự các định dạng video và âm thanh được sử dụng trong quá trình phát vớiEventTime
tại thời điểm bắt đầu sử dụng.fatalErrorHistory
vànonFatalErrorHistory
: Danh sách theo thứ tự các lỗi nghiêm trọng và lỗi không nghiêm trọng cùng vớiEventTime
nơi các lỗi đó xảy ra. Lỗi nghiêm trọng là những lỗi đã kết thúc quá trình phát, 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ần phát
Dữ liệu này được thu thập tự động nếu bạn sử dụng PlaybackStatsListener
, ngay cả với 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ẽ 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);
Tổng hợp dữ liệu phân tích 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 được hợp nhất. Xin lưu ý rằng nhật ký này sẽ không chứa nhật ký của từng sự kiện phát, vì các sự kiện này không thể được tổng hợp.
Bạn có thể sử dụng PlaybackStatsListener.getCombinedPlaybackStats
để xem tổng hợp tất cả dữ liệu phân tích được thu thập trong vòng đời của 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 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ể dễ dàng 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 các sự kiện này với PlaybackStats
được báo cáo sau. Nếu hữu ích, 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
private interface ExtendedListener : AnalyticsListener { fun onCustomEvent(eventTime: EventTime) } private class ExtendedCollector : DefaultAnalyticsCollector(Clock.DEFAULT) { fun customEvent() { val eventTime = generateCurrentPlayerMediaPeriodEventTime() sendEvent(eventTime, CUSTOM_EVENT_ID) { listener: AnalyticsListener -> if (listener is ExtendedListener) { listener.onCustomEvent(eventTime) } } } } // 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
private interface ExtendedListener extends AnalyticsListener { void onCustomEvent(EventTime eventTime); } 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); } }); } } // 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();