ExoPlayer รองรับความต้องการด้านการวิเคราะห์การเล่นได้อย่างหลากหลาย สุดท้ายแล้ว Analytics เกี่ยวข้องกับการรวบรวม ตีความ การรวบรวม และการสรุปข้อมูล จากการเล่น ข้อมูลนี้สามารถใช้บนอุปกรณ์อย่างใดอย่างหนึ่ง เช่น การบันทึก การแก้ไขข้อบกพร่อง หรือเพื่อแจ้งการตัดสินใจเกี่ยวกับการเล่นในอนาคต หรือรายงานไปยัง เซิร์ฟเวอร์ในการตรวจสอบการเล่นบนอุปกรณ์ทั้งหมด
โดยปกติแล้วระบบข้อมูลวิเคราะห์จะต้องรวบรวมเหตุการณ์ก่อน แล้วค่อยประมวลผล เพื่อทำให้มีความหมาย:
- คอลเล็กชันกิจกรรม:
ซึ่งทำได้โดยการลงทะเบียน
AnalyticsListener
ในExoPlayer
อินสแตนซ์ Listener ข้อมูลวิเคราะห์ที่ลงทะเบียนไว้จะได้รับเหตุการณ์ตามที่เกิดขึ้นระหว่าง การใช้งานโปรแกรมเล่น แต่ละเหตุการณ์จะเชื่อมโยงกับสื่อที่เกี่ยวข้อง รายการในเพลย์ลิสต์ รวมถึงตำแหน่งการเล่นและข้อมูลเมตาการประทับเวลา - การประมวลผลเหตุการณ์
ระบบข้อมูลวิเคราะห์บางระบบอัปโหลดเหตุการณ์ดิบไปยังเซิร์ฟเวอร์พร้อมกับเหตุการณ์ทั้งหมด
ได้ดำเนินการจากฝั่งเซิร์ฟเวอร์แล้ว ยังสามารถประมวลผลเหตุการณ์ใน
อุปกรณ์ และวิธีนี้อาจง่ายกว่า หรือลดจำนวนข้อมูลที่
จะต้องอัปโหลด ExoPlayer จะให้
PlaybackStatsListener
ซึ่ง ทำให้คุณสามารถดำเนินการขั้นตอนการประมวลผลต่อไปนี้- การตีความเหตุการณ์: เหตุการณ์จําเป็นต้องมี
สามารถตีความได้ในบริบทของการเล่นครั้งเดียว เช่น ไฟล์ RAW
เหตุการณ์การเปลี่ยนแปลงสถานะผู้เล่นเป็น
STATE_BUFFERING
อาจสอดคล้องกับ การบัฟเฟอร์ครั้งแรก การบัฟเฟอร์ซ้ำ หรือการบัฟเฟอร์ที่เกิดขึ้นหลังจากการค้นหา - การติดตามสถานะ: ขั้นตอนนี้จะแปลงเหตุการณ์เป็นตัวนับ ตัวอย่างเช่น เหตุการณ์การเปลี่ยนแปลงสถานะสามารถแปลงเป็นตัวนับที่ติดตามระยะเวลาได้ ที่ใช้ในการเล่นแต่ละสถานะ ผลลัพธ์ที่ได้คือชุดข้อมูลการวิเคราะห์พื้นฐาน สำหรับการเล่นครั้งเดียว
- การรวมข้อมูล: ขั้นตอนนี้จะรวมข้อมูลวิเคราะห์จาก โดยทั่วไปคือการเพิ่มตัวนับ
- การคำนวณเมตริกสรุป: เมตริกที่เป็นประโยชน์หลายเมตริกคือ โฆษณาที่คำนวณค่าเฉลี่ย หรือรวมค่าข้อมูลการวิเคราะห์พื้นฐานใน วิธีอื่นๆ คำนวณเมตริกสรุปได้ทีละรายการหรือหลายรายการ การเล่น
- การตีความเหตุการณ์: เหตุการณ์จําเป็นต้องมี
สามารถตีความได้ในบริบทของการเล่นครั้งเดียว เช่น ไฟล์ RAW
เหตุการณ์การเปลี่ยนแปลงสถานะผู้เล่นเป็น
การรวบรวมเหตุการณ์ด้วย 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
ที่ส่งไปยัง Callback แต่ละรายการจะเชื่อมโยงเหตุการณ์กับสื่อ
รายการในเพลย์ลิสต์ รวมถึงตำแหน่งการเล่นและข้อมูลเมตาการประทับเวลา
realtimeMs
: เวลาแขวนผนังของเหตุการณ์timeline
,windowIndex
และmediaPeriodId
: กำหนดเพลย์ลิสต์และ รายการในเพลย์ลิสต์ที่มีกิจกรรมนั้นอยู่mediaPeriodId
จะมีข้อมูลเพิ่มเติมที่ไม่บังคับ เช่น ระบุว่า เป็นของโฆษณาภายในรายการeventPlaybackPositionMs
: ตำแหน่งการเล่นในรายการเมื่อเกิดเหตุการณ์ เกิดขึ้นcurrentTimeline
,currentWindowIndex
,currentMediaPeriodId
และcurrentPlaybackPositionMs
: ตามข้างต้น แต่สำหรับรายการที่กำลังเล่นอยู่ รายการที่กำลังเล่นอยู่อาจแตกต่างจากรายการที่กิจกรรม เช่น หากเหตุการณ์สอดคล้องกับการบัฟเฟอร์ล่วงหน้า รายการที่จะเล่น
การประมวลผลเหตุการณ์ด้วย PlaybackStatsListener
PlaybackStatsListener
เป็นAnalyticsListener
ที่ใช้งานในอุปกรณ์
การประมวลผลเหตุการณ์ คำนวณ PlaybackStats
ด้วยตัวนับและคำนวณ
ได้แก่
- เมตริกสรุป เช่น เวลาการเล่นทั้งหมด
- เมตริกคุณภาพการเล่นแบบปรับอัตโนมัติ เช่น ความละเอียดโดยเฉลี่ยของวิดีโอ
- เมตริกคุณภาพการแสดงผล เช่น อัตราของเฟรมที่ลดลง
- เมตริกการใช้งานทรัพยากร เช่น จำนวนไบต์ที่อ่านผ่านเครือข่าย
คุณจะเห็นรายการจํานวนทั้งหมดที่ใช้ได้และเมตริกที่ได้มาใน
PlaybackStats
Javadoc
PlaybackStatsListener
คำนวณ PlaybackStats
แยกกันสำหรับสื่อแต่ละรายการ
ในเพลย์ลิสต์ รวมถึงโฆษณาฝั่งไคลเอ็นต์แต่ละรายการที่แทรกอยู่ภายในรายการเหล่านี้ คุณ
สามารถให้การติดต่อกลับไปยัง PlaybackStatsListener
เพื่อแจ้งให้ทราบว่าสิ้นสุดการดำเนินการได้
และใช้ EventTime
ที่ส่งไปยัง Callback เพื่อระบุว่าเป็น
เล่นเสร็จแล้ว คุณสามารถรวบรวมข้อมูล Analytics เพื่อ
การเล่นซ้ำหลายครั้ง หรือค้นหา 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
อินสแตนซ์สำหรับเหตุการณ์ที่กำหนดเองและส่ง
ใหม่ให้กับ Listener ที่ลงทะเบียนแล้ว ดังที่แสดงในตัวอย่างต่อไปนี้
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();