เราจะเพิ่ม Visualizer ใน ExoPlayer ยังไงดีนะ?

Android Oct 22, 2019

มันไม่ได้ใช้ง่ายเท่าตอนใส่ใน MediaPlayer อ่ะดิ

อันนี้เราลองเขียนขึ้นมาเล่นๆ ว่าถ้าเราเล่นไฟล์เสียงใน ExoPlayer แล้ว มีเจ้า Visualizer มาด้วย เอ้อออ ว่าแต่ ทำยังไงนะ

ก่อนอื่นมาลองอ่านมาลองทำตามบล็อกนี้ก่อนนะ เดี๋ยวจะอธิบายให้ฟัง

Create audio Visualizer for MediaPlayer
Android developer blog: learn programming for Android

ส่วนประกอบหลักๆมี 2 ส่วน คือ Visualizer View และ Player บน Activity/Fragment

Visualizer View ขอเล่าคร่าวๆว่ามันเป็น View Class ตัวนึง ที่แสดง Visualizer ของไฟล์เสียงของเรา ซึ่งอาจจะเขียนเองแบบในบล็อกอ้างอิงด้านบน จะเป็นแบบเส้นๆ หรือใช้ library ก็ได้นะ เลือกได้ว่าอยากออกมาแบบไหน ไม่ต้องวาดเอง เช่น

gauravk95/audio-visualizer-android
🎵 [Android Library] A light-weight and easy-to-use Audio Visualizer for Android. - gauravk95/audio-visualizer-android

ส่วน Player ในหน้า Activity/Fragment ที่เราต้องการ ก็ต้องมีเจ้า ExoPlayer อยู่ในนี้ก่อนเนอะ ซึ่งเจ้า ExoPlayer จะแยกเป็น 2 ส่วน คือ View และ Player

ก่อนอื่นแจ้งกันก่อน เราใช้ ExoPlayer version นี้นะ

implementation 'com.google.android.exoplayer:exoplayer:2.10.4'

ซึ่งส่วนของ ExoPlayer View นั้นเราใส่ลงไปใน layout ซึ่งใส่แบบ basic ก่อนค่อยมา custom ทีหลังแล้วกัน โดยเราจะให้เจ้า Visualizer View ไว้ด้านบน Player เพื่อ UX ที่ดี เป็นธรรมชาติ

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.gauravk.audiovisualizer.visualizer.BlastVisualizer
        android:id="@+id/playerVisualizer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:avDensity="0.8"
        app:avType="fill"
        app:avColor="@color/av_dark_blue"
        app:avSpeed="normal"/>

    <com.google.android.exoplayer2.ui.PlayerView
        android:id="@+id/playerView"
        android:layout_width="match_parent"
        android:layout_height="100dp" />

</LinearLayout>

เรามาสร้างเจ้า player ของ ExoPlayer กันเถอะ พร้อมกำหนดค่าต่างๆใน player ของเรา

และก็สร้าง Visualizer ขึ้นมา และนำมาเล่น

ใน listener ของ Visualizer.OnDataCaptureListener เราจะต้อง override 2 functions ด้วยกัน

  • onWaveFormDataCapture อันนี้เราจะได้เจ้า waveform ออกมา
  • onFftDataCapture อันนี้เราจะได้ fft (ใน doc บอกว่า frequency capture) ออกมา

ทั้ง waveform และ fft นั้น จะเป็น ByteArray ทั้งคู่

Visualizer.OnDataCaptureListener | Android Developers
AccessibilityService.MagnificationController.OnMagnificationChangedListenerdeveloper.android.com

จริงๆเจ้า visualizer.setDataCaptureListener นั้น parameter แรกนั้นใส่เจ้า object ของ Visualizer.OnDataCaptureListener เพื่อ implement data capture ว่าเอาไปทำอะไรต่อ ถ้าให้แสดงแบบ waveform หรือ fft จากนั้น parameter ต่อมาเป็นค่า rate ส่วนสอง parameter หลังนั้น เป็นการ enable ว่าจะใช้แบบ waveform หรือ fft ดี ซึ่งเราขอแนะนำควรใส่ค่า true แค่อันไหนอันนึงพอจ้า ถ้า false ทั้งคู่มันจะไม่ขึ้นนะเตง ถ้าใส่ true สองอันเราจะเห็น fft เป็นหลักอ่ะ การฟมันใหญ่บัง waveform มิดเชียว

waveform
fft

แต่แล้วความแตกต่างจาก MediaPlayer คือ exoPlayer.audioSessionId ดันเป็น 0 ซะได้ และ crash ตลอดเลย

ลองมา google กันหน่อย ทำยังไงให้ได้ค่านี้มามากกว่า 0 จนมาเจออันนี้ เราต้อง get audioSessionId จาก AnalyticsListener

How can I get an audiosessionId from Exoplayer?
I’m trying to use Exoplayer in my project (instead of the MediaPlayer of Android). However, I have a problem: getting the id of current audio session. With traditional MediaPlayer, it’s easy by cal...
exoPlayer.addAnalyticsListener(object : AnalyticsListener {
    override fun onAudioSessionId(
        eventTime: AnalyticsListener.EventTime?,
        audioSessionId: Int
    ) {
        startPlayerVisualizer(audioSessionId)
    }
})

เรารับ audioSessionId จากในนี้ ค่ามันก็มากกว่า 0 แล้วหล่ะถ้าลอง debug ดูอะนะ และพอเอาไปรันสุดท้ายได้ผลเหมือน MediaPlayer แล้ว เย้ๆๆๆๆ

สรุปโค้ดทั้งหมดเลยดีกว่า

แต่อัดวิดีโอเดโม่ลำบากมาก เพราะอัดจากโทรศัพท์ก็ไม่ได้ เหมือนอัดเสียงในอัดเสียงอีกที โอ้ยยยย สับสน

อันนี้ใช้ Visualizer ตามบล็อกตัวอย่างเน้อ มันจะเป็นเส้นๆ

สุดท้ายเราปรับให้เจ้า ExoPlayer ของเรา เป็นเนื้อเดียวกับ Visualizer ให้มากกว่านี้หน่อย ซึ่งเราก็ custom player มาอีกทีนึง

เดี๋ยวหาว่าจบไวไป ขอเล่าเรื่อง custom player สั้นๆ จ้า

ก่อนอื่นเพิ่มเจ้า ExoPlayer เข้าไปใน layout ของเราก่อน

<com.google.android.exoplayer2.ui.SimpleExoPlayerView
    android:id="@+id/playerView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:controller_layout_id="@layout/layout_player"
    app:use_controller="true"
    app:auto_show="true"
    app:show_timeout="0"
    app:hide_on_touch="false" />
  • เราใส่ layout player ที่เรา custom ลงไปใน app:controller_layout_id
  • ส่วนอันนี้เราใส่ไปเพื่อไม่ให้ player มัน hide ตัวเอง
app:use_controller="true"
app:auto_show="true"
app:show_timeout="0"
  • และใส่อันนี้ไปอีกที เพื่อบอกว่า ถ้ามือเราไปโดน player แล้วไม่ต้อง hide เน้อ
app:hide_on_touch="false"

จากนั้นเราก็สร้าง layout custom player ขึ้นมา นามว่า layout_player.xml

ซึ่งเราต้อง override ปุ่ม โดยเรา override id ของปุ่มต่างๆ เช่น ปุ่มเล่น override @+id/exo_play ปุ่มหยุด override @+id/exo_pause ประมาณนี้

หรืออ่านเพิ่มเติมที่นี่

มาเล่นวิดีโอด้วย ExoPlayer กันเถอะ
เมื่อมีท่านนึงบอกว่าอยากอ่านบล็อก ExoPlayer ที่เป็นภาษาไทย และน้องบอกว่า แฟนอยากอ่านมาก แต่เป็นภาษาอังกฤษเลยกดปิดไป เอออออ แปลไทยให้ก็ได้ค่ะ เราร่างบล็อกนี้ระหว่างทำสไลด์เพื่อนำไปพูดในงาน Android…

สุดท้ายฝากร้านกันสักนิด ฝากเพจด้วยนะจ๊ะ

อย่าลืมกด like กด share บทความกันด้วยนะคะ :)

โพสต์โดย MikkiPastel เมื่อ วันอาทิตย์ที่ 10 ธันวาคม 2017

Tags

Minseo Chayabanjonglerd

I am a full-time Android Developer and part-time contributor with developer community and web3 world, who believe people have hard skills and soft skills to up-skill to da moon.