ExoPlayer รองรับความต้องการด้านข้อมูลวิเคราะห์การเล่นที่หลากหลาย ท้ายที่สุดแล้ว ข้อมูลวิเคราะห์คือการรวบรวม ตีความ รวบรวม และสรุปข้อมูล จากการเล่น ข้อมูลนี้สามารถใช้ในอุปกรณ์ได้ เช่น เพื่อ การบันทึก การแก้ไขข้อบกพร่อง หรือเพื่อแจ้งการตัดสินใจเกี่ยวกับการเล่นในอนาคต หรือจะรายงานไปยัง เซิร์ฟเวอร์เพื่อตรวจสอบการเล่นในอุปกรณ์ทั้งหมดก็ได้
โดยปกติแล้ว ระบบวิเคราะห์จะต้องเก็บรวบรวมเหตุการณ์ก่อน แล้วจึงประมวลผลเหตุการณ์เหล่านั้น เพิ่มเติมเพื่อให้มีความหมาย
- การรวบรวมเหตุการณ์:
ทำได้โดยการลงทะเบียน
AnalyticsListenerในอินสแตนซ์ExoPlayerListener การวิเคราะห์ที่ลงทะเบียนจะได้รับเหตุการณ์เมื่อเกิดขึ้นในระหว่าง การใช้งานเพลเยอร์ แต่ละเหตุการณ์จะเชื่อมโยงกับรายการสื่อที่เกี่ยวข้องในเพลย์ลิสต์ รวมถึงข้อมูลเมตาของตำแหน่งการเล่นและการประทับเวลา - การประมวลผลเหตุการณ์
ระบบวิเคราะห์บางระบบจะอัปโหลดเหตุการณ์ดิบไปยังเซิร์ฟเวอร์ โดยมีการประมวลผลเหตุการณ์ทั้งหมด
ที่ฝั่งเซิร์ฟเวอร์ นอกจากนี้ คุณยังประมวลผลเหตุการณ์ในอุปกรณ์ได้ด้วย ซึ่งอาจทำได้ง่ายกว่าหรือลดปริมาณข้อมูลที่ต้องอัปโหลด ExoPlayer มี
PlaybackStatsListenerซึ่ง ช่วยให้คุณทำตามขั้นตอนการประมวลผลต่อไปนี้ได้- การตีความเหตุการณ์: เหตุการณ์ต้องได้รับการตีความในบริบทของการเล่นครั้งเดียวจึงจะมีประโยชน์สําหรับวัตถุประสงค์ในการวิเคราะห์ เช่น เหตุการณ์ดิบ
ของการเปลี่ยนสถานะเพลเยอร์เป็น
STATE_BUFFERINGอาจสอดคล้องกับ การบัฟเฟอร์ครั้งแรก การบัฟเฟอร์ซ้ำ หรือการบัฟเฟอร์ที่เกิดขึ้นหลังจากการกรอ - การติดตามสถานะ: ขั้นตอนนี้จะแปลงเหตุการณ์เป็นตัวนับ ตัวอย่างเช่น เหตุการณ์การเปลี่ยนสถานะสามารถแปลงเป็นตัวนับที่ติดตามระยะเวลาที่ใช้ในสถานะการเล่นแต่ละสถานะได้ ผลลัพธ์คือชุดค่าข้อมูลวิเคราะห์พื้นฐาน สำหรับการเล่นครั้งเดียว
- การรวม: ขั้นตอนนี้จะรวมข้อมูลวิเคราะห์จากการเล่นหลายครั้ง โดยปกติจะเพิ่มตัวนับ
- การคำนวณเมตริกสรุป: เมตริกที่มีประโยชน์มากที่สุดหลายรายการคือเมตริกที่คำนวณค่าเฉลี่ยหรือรวมค่าข้อมูล Analytics พื้นฐานด้วยวิธีอื่นๆ คุณคำนวณเมตริกสรุปสำหรับการเล่นครั้งเดียวหรือหลายครั้งได้
- การตีความเหตุการณ์: เหตุการณ์ต้องได้รับการตีความในบริบทของการเล่นครั้งเดียวจึงจะมีประโยชน์สําหรับวัตถุประสงค์ในการวิเคราะห์ เช่น เหตุการณ์ดิบ
ของการเปลี่ยนสถานะเพลเยอร์เป็น
การรวบรวมเหตุการณ์ด้วย AnalyticsListener
ระบบจะรายงานเหตุการณ์การเล่นดิบจากเพลเยอร์ไปยังAnalyticsListener
การติดตั้งใช้งาน คุณเพิ่ม Listener ของตัวเองและลบล้างได้เฉพาะ
เมธอดที่คุณสนใจเท่านั้น
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 ที่ส่งไปยังแต่ละการเรียกกลับจะเชื่อมโยงเหตุการณ์กับรายการสื่อ
ในเพลย์ลิสต์ รวมถึงข้อมูลเมตาของตำแหน่งการเล่นและการประทับเวลา
realtimeMs: เวลาของเหตุการณ์ตามนาฬิกาแขวนtimeline,windowIndexและmediaPeriodId: กำหนดเพลย์ลิสต์และรายการในเพลย์ลิสต์ที่กิจกรรมเป็นของmediaPeriodIdมีข้อมูลเพิ่มเติมที่ไม่บังคับ เช่น ระบุว่า เหตุการณ์เป็นของโฆษณาภายในรายการหรือไม่eventPlaybackPositionMs: ตำแหน่งการเล่นในรายการเมื่อเกิดเหตุการณ์currentTimeline,currentWindowIndex,currentMediaPeriodIdและcurrentPlaybackPositionMs: เหมือนกับด้านบน แต่ใช้กับรายการที่กำลังเล่นอยู่ รายการที่กำลังเล่นอาจแตกต่างจากรายการที่เหตุการณ์ เป็นของอยู่ เช่น หากเหตุการณ์สอดคล้องกับการบัฟเฟอร์ล่วงหน้าของรายการถัดไป ที่จะเล่น
การประมวลผลเหตุการณ์ด้วย PlaybackStatsListener
PlaybackStatsListener คือ AnalyticsListener ที่ใช้การประมวลผลเหตุการณ์ในอุปกรณ์
โดยจะคำนวณ PlaybackStats ด้วยตัวนับและเมตริกที่ได้มา
ซึ่งรวมถึง
- เมตริกสรุป เช่น เวลาในการเล่นทั้งหมด
- เมตริกคุณภาพการเล่นแบบปรับอัตโนมัติ เช่น ความละเอียดวิดีโอเฉลี่ย
- เมตริกคุณภาพการแสดงผล เช่น อัตราเฟรมที่ขาดหายไป
- เมตริกการใช้ทรัพยากร เช่น จำนวนไบต์ที่อ่านผ่านเครือข่าย
คุณจะเห็นรายการจำนวนและเมตริกที่ได้ทั้งหมดที่พร้อมใช้งานใน
PlaybackStats Javadoc
PlaybackStatsListener จะคำนวณ PlaybackStats แยกต่างหากสำหรับรายการสื่อแต่ละรายการ
ในเพลย์ลิสต์ รวมถึงโฆษณาฝั่งไคลเอ็นต์แต่ละรายการที่แทรกภายในรายการเหล่านี้ คุณ
สามารถระบุการเรียกกลับไปยัง PlaybackStatsListener เพื่อรับทราบเกี่ยวกับการเล่นที่เสร็จสมบูรณ์
และใช้ EventTime ที่ส่งไปยังการเรียกกลับเพื่อระบุว่าการเล่นใด
เสร็จสมบูรณ์แล้ว คุณสามารถรวบรวมข้อมูลวิเคราะห์สำหรับการเล่นหลายครั้งได้ นอกจากนี้ คุณยังค้นหา PlaybackStats สำหรับ
เซสชันการเล่นปัจจุบันได้ทุกเมื่อโดยใช้
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. }));
ตัวสร้างของ PlaybackStatsListener มีตัวเลือกในการเก็บประวัติแบบเต็มของเหตุการณ์ที่ประมวลผลแล้ว โปรดทราบว่าการดำเนินการนี้อาจทำให้เกิดค่าใช้จ่ายด้านหน่วยความจำที่ไม่รู้จัก
ขึ้นอยู่กับระยะเวลาการเล่นและจำนวนเหตุการณ์ ดังนั้น คุณ
ควรเปิดใช้เฉพาะในกรณีที่ต้องการเข้าถึงประวัติทั้งหมดของเหตุการณ์ที่ประมวลผลแล้ว
แทนที่จะเข้าถึงเฉพาะข้อมูลวิเคราะห์สุดท้าย
โปรดทราบว่า PlaybackStats ใช้ชุดสถานะแบบขยายเพื่อระบุไม่เพียงแต่
สถานะของสื่อ แต่ยังรวมถึงความตั้งใจของผู้ใช้ที่จะเล่นและข้อมูล
โดยละเอียดเพิ่มเติม เช่น สาเหตุที่การเล่นถูกขัดจังหวะหรือสิ้นสุด
| สถานะการเล่น | ความตั้งใจของผู้ใช้ที่จะเล่น | ไม่มีเจตนาที่จะเล่น |
|---|---|---|
| ก่อนเล่น | JOINING_FOREGROUND |
NOT_STARTED, JOINING_BACKGROUND |
| การเล่นที่ใช้งานอยู่ | PLAYING |
|
| การเล่นถูกขัดจังหวะ | BUFFERING, SEEKING |
PAUSED, PAUSED_BUFFERING, SUPPRESSED, SUPPRESSED_BUFFERING, INTERRUPTED_BY_AD |
| สถานะสิ้นสุด | ENDED, STOPPED, FAILED, ABANDONED |
ความตั้งใจของผู้ใช้ที่จะเล่นเป็นสิ่งสำคัญในการแยกแยะเวลาที่ผู้ใช้
รออย่างตั้งใจให้การเล่นดำเนินต่อจากเวลารอแบบพาสซีฟ เช่น PlaybackStats.getTotalWaitTimeMs จะแสดงเวลาทั้งหมดที่ใช้ในสถานะ JOINING_FOREGROUND, BUFFERING และ SEEKING แต่จะไม่แสดงเวลาที่หยุดเล่นชั่วคราว ในทํานองเดียวกัน PlaybackStats.getTotalPlayAndWaitTimeMs จะ
แสดงเวลาทั้งหมดที่ผู้ใช้ตั้งใจจะเล่น ซึ่งก็คือเวลารอที่ใช้งานอยู่ทั้งหมด
และเวลาทั้งหมดที่ใช้ในสถานะ PLAYING
เหตุการณ์ที่ประมวลผลและตีความแล้ว
คุณสามารถบันทึกเหตุการณ์ที่ประมวลผลและตีความได้โดยใช้ PlaybackStatsListener
กับ keepHistory=true PlaybackStatsที่ได้จะมีรายการเหตุการณ์ต่อไปนี้
playbackStateHistory: รายการสถานะการเล่นที่ขยายเวลาตามลำดับพร้อมEventTimeที่เริ่มใช้ นอกจากนี้ คุณยังใช้PlaybackStats.getPlaybackStateAtTimeเพื่อค้นหาสถานะ ณ เวลาที่ระบุได้ด้วยmediaTimeHistory: ประวัติเวลาของนาฬิกาแขวนผนังและเวลาของสื่อที่จับคู่กัน ซึ่งช่วยให้คุณสร้างใหม่ได้ว่าส่วนใดของสื่อเล่นในเวลาใด นอกจากนี้ คุณยังใช้PlaybackStats.getMediaTimeMsAtRealtimeMsเพื่อค้นหาตำแหน่งการเล่น ณ เวลาที่ระบุได้ด้วยvideoFormatHistoryและaudioFormatHistory: รายการรูปแบบวิดีโอและ เสียงที่ใช้ระหว่างการเล่นพร้อมกับEventTimeที่เริ่มใช้fatalErrorHistoryและnonFatalErrorHistory: รายการข้อผิดพลาดร้ายแรงและ ไม่ร้ายแรงที่เรียงตามลำดับพร้อมด้วยEventTimeที่เกิดข้อผิดพลาด ข้อผิดพลาดร้ายแรงคือข้อผิดพลาดที่ทำให้การเล่นสิ้นสุดลง ในขณะที่ข้อผิดพลาดที่ไม่ร้ายแรงอาจกู้คืนได้
ข้อมูลวิเคราะห์การเล่นรอบเดียว
ระบบจะรวบรวมข้อมูลนี้โดยอัตโนมัติหากคุณใช้ PlaybackStatsListener แม้จะใช้ keepHistory=false ด้วยก็ตาม ค่าสุดท้ายคือฟิลด์สาธารณะที่คุณดูได้ใน PlaybackStats Javadoc และระยะเวลาสถานะการเล่นที่ getPlaybackStateDurationMs แสดงผล เพื่อความสะดวก คุณจะเห็นเมธอดต่างๆ เช่น getTotalPlayTimeMs และ getTotalWaitTimeMs ซึ่งจะแสดงระยะเวลาของสถานะการเล่นที่เฉพาะเจาะจง
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);
รวบรวมข้อมูลวิเคราะห์ของการเล่นหลายครั้ง
คุณรวม PlaybackStats หลายรายการเข้าด้วยกันได้โดยเรียกใช้
PlaybackStats.merge PlaybackStats ที่ได้จะมีข้อมูลรวม
ของการเล่นทั้งหมดที่ผสานรวม โปรดทราบว่ารายงานนี้จะไม่มีประวัติของ
เหตุการณ์การเล่นแต่ละรายการ เนื่องจากระบบรวบรวมเหตุการณ์เหล่านี้ไม่ได้
PlaybackStatsListener.getCombinedPlaybackStats ใช้เพื่อดูภาพรวมของข้อมูลวิเคราะห์ทั้งหมดที่รวบรวมไว้ตลอดอายุการใช้งานของPlaybackStatsListener ได้
เมตริกสรุปที่คำนวณแล้ว
นอกเหนือจากข้อมูลวิเคราะห์พื้นฐานแล้ว PlaybackStats ยังมีหลายวิธี
ในการคํานวณเมตริกสรุป
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());
หัวข้อขั้นสูง
การเชื่อมโยงข้อมูลวิเคราะห์กับข้อมูลเมตาการเล่น
เมื่อรวบรวมข้อมูลวิเคราะห์สำหรับการเล่นแต่ละครั้ง คุณอาจต้องการเชื่อมโยงข้อมูลวิเคราะห์การเล่นกับข้อมูลเมตาเกี่ยวกับสื่อที่กำลังเล่น
เราขอแนะนำให้ตั้งค่าข้อมูลเมตาเฉพาะสื่อด้วย MediaItem.Builder.setTag
แท็กสื่อเป็นส่วนหนึ่งของEventTimeที่รายงานสําหรับเหตุการณ์ดิบและเมื่อPlaybackStatsเสร็จสิ้น คุณจึงเรียกข้อมูลแท็กสื่อได้อย่างง่ายดายเมื่อจัดการข้อมูลวิเคราะห์ที่เกี่ยวข้อง
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. });
การรายงานเหตุการณ์ข้อมูลวิเคราะห์ที่กําหนดเอง
ในกรณีที่ต้องการเพิ่มเหตุการณ์ที่กําหนดเองลงในข้อมูลวิเคราะห์ คุณต้องบันทึก
เหตุการณ์เหล่านี้ในโครงสร้างข้อมูลของคุณเอง และรวมเข้ากับข้อมูลที่รายงาน
PlaybackStatsในภายหลัง หากต้องการความช่วยเหลือ คุณสามารถขยาย DefaultAnalyticsCollector เพื่อสร้างอินสแตนซ์ EventTime สำหรับเหตุการณ์ที่กำหนดเองและส่งไปยังผู้ฟังที่ลงทะเบียนไว้แล้วได้ตามตัวอย่างต่อไปนี้
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(); }