ExoPlayer รองรับความต้องการด้านการวิเคราะห์การเล่นที่หลากหลาย สุดท้ายแล้ว Analytics คือการรวบรวม ตีความ การรวบรวม และการสรุปข้อมูลจากการเล่น ข้อมูลนี้ใช้ในอุปกรณ์ก็ได้ เช่น การบันทึก การแก้ไขข้อบกพร่อง หรือเพื่อใช้ประกอบการตัดสินใจเกี่ยวกับการเล่นในอนาคต หรือจะรายงานไปยังเซิร์ฟเวอร์เพื่อตรวจสอบการเล่นในอุปกรณ์ทั้งหมดก็ได้
โดยปกติแล้ว ระบบวิเคราะห์จะต้องรวบรวมเหตุการณ์ก่อน แล้วจึงประมวลผลเพิ่มเติมเพื่อให้เหตุการณ์มีความหมาย
- การเก็บรวบรวมเหตุการณ์:
ทำได้โดยการลงทะเบียน
AnalyticsListener
ในอินสแตนซ์ExoPlayer
Listener ข้อมูลวิเคราะห์ที่ลงทะเบียนไว้จะรับเหตุการณ์ที่เกิดขึ้นระหว่างการใช้งานเพลเยอร์ แต่ละเหตุการณ์จะเชื่อมโยงกับรายการสื่อที่เกี่ยวข้องในเพลย์ลิสต์ รวมถึงข้อมูลเมตาตำแหน่งการเล่นและการประทับเวลา - การประมวลผลเหตุการณ์: ระบบวิเคราะห์บางระบบจะอัปโหลดเหตุการณ์ดิบไปยังเซิร์ฟเวอร์ โดยทำการประมวลผลเหตุการณ์ทั้งหมดฝั่งเซิร์ฟเวอร์ นอกจากนี้ คุณยังประมวลผลเหตุการณ์ในอุปกรณ์ได้ด้วย ซึ่งอาจทําได้ง่ายขึ้นหรือลดปริมาณข้อมูลที่จําเป็นต้องอัปโหลด ExoPlayer มี
PlaybackStatsListener
ซึ่งจะช่วยให้คุณทำตามขั้นตอนการประมวลผลต่อไปนี้ได้- การตีความเหตุการณ์: เหตุการณ์ต้องได้รับการตีความในบริบทของการเล่นครั้งเดียวจึงจะมีประโยชน์สําหรับวัตถุประสงค์ด้านการวิเคราะห์ เช่น เหตุการณ์ดิบของสถานะโปรแกรมเล่นที่เปลี่ยนเป็น
STATE_BUFFERING
อาจสอดคล้องกับการบัฟเฟอร์ครั้งแรก การบัฟเฟอร์อีกครั้ง หรือการบัฟเฟอร์ที่เกิดขึ้นหลังจากการกรอ - การติดตามสถานะ: ขั้นตอนนี้จะแปลงเหตุการณ์เป็นตัวนับ เช่น เหตุการณ์การเปลี่ยนแปลงสถานะสามารถแปลงเป็นเคาน์เตอร์ที่ติดตามระยะเวลาที่ใช้ในแต่ละสถานะการเล่น ผลที่ได้คือชุดค่าข้อมูลการวิเคราะห์พื้นฐาน สำหรับการเล่นครั้งเดียว
- การรวมข้อมูล: ขั้นตอนนี้จะรวบรวมข้อมูลการวิเคราะห์จากการเล่นหลายๆ ช่วง ซึ่งโดยปกติแล้วจะเป็นการรวมตัวนับเข้าด้วยกัน
- การคํานวณเมตริกสรุป: เมตริกที่มีประโยชน์มากที่สุดหลายรายการคือเมตริกที่คํานวณค่าเฉลี่ยหรือรวมค่าข้อมูลวิเคราะห์พื้นฐานเข้าด้วยกันด้วยวิธีอื่นๆ ระบบจะคํานวณเมตริกสรุปสําหรับการเล่นรายการเดียวหรือหลายรายการ
- การตีความเหตุการณ์: เหตุการณ์ต้องได้รับการตีความในบริบทของการเล่นครั้งเดียวจึงจะมีประโยชน์สําหรับวัตถุประสงค์ด้านการวิเคราะห์ เช่น เหตุการณ์ดิบของสถานะโปรแกรมเล่นที่เปลี่ยนเป็น
การเก็บรวบรวมเหตุการณ์ด้วย AnalyticsListener
ระบบจะรายงานเหตุการณ์การเล่นแบบดิบจากโปรแกรมเล่นไปยังAnalyticsListener
การใช้งาน คุณเพิ่มตัวรับฟังของคุณเองและลบล้างเฉพาะเมธอดที่สนใจได้โดยง่าย ดังนี้
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
สําหรับเหตุการณ์ที่กําหนดเองและส่งไปยัง Listeners ที่ลงทะเบียนไว้แล้วได้ ดังที่แสดงในตัวอย่างต่อไปนี้
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();