المدونة

استخدام ExoPlayer لتشغيل الوسائط و قوائم التشغيل والمزيد من المزايا

Music player app on smartphone

ما هو ExoPlayer?

هي مكتبة مشغل وسائط مفتوحة المصدر بديل ل MediaPlayer, يوفر بديل لتشغل ملفات الفيديو والصوتيات المحلية والمتوفرة عبر الانترنت .

على عكس الMediaPlayer الذي هو مكتبة على مستوى النظام الامر الذي يجعل التحديثات الجديدة تتطلب تحديث كامل لنسخة النظام, فان ExoPlayer هو مكتبة منفصلة يمكن تحميل التحديثات عن طريق المتجر.

وامر اخر يجعلك تريد ان تستخدم ExoPlayer هو انه يدعم مجموعة كبيرة الاجهزة بمختلف النسخ على عكس MediaPlayer حيث يمكن لاي شخص تعديل السورس كود واضافتها للهاتف مما يزيد من مشاكل التطبيق المستقبلية وصعوبة حلها

يوفر ExoPlayer خواص اضافة ايضا ليست موجود في MediaPlayer مثل:

  • قوائم التشغيل playlist
  • دعم الكثير من الهواتف
  • دعم ادارة الحقوق الرقمية DRM
  • DASH
  • RTSP
  • استرجاع معلومات عن ملف الوسائط Metadata
  • SmoothStreaming
  • اضافة ملف ترجمة
  • HLS
  • اضافة اعلانات , مثل اعلانات يوتيوب في نسخة الهواتف
  • تحويل الوسائط مثل:

    • تغير صيغة ملف الوسائط مثل من mp3 الى wav
    • مسح المسارات: مثل مسح الصوت من فيديو او العكس

بعد هذه المقدمة البسيط يمكن ان نبدا استخدام المكتبة في مثال.

كيف اضيف المكتبة الى مشروعي؟

يمكن اضافة المكتبة بطريقتين:

  1. اضافة المكتبة كاملة بجميع الخواص كمكتبة كاملة
  2. اضافة المكتبة التى الدوال الاساسية core ثم بعد ذلك اضافة الخواص كل على حدة

لتبسيط الامر سوف نستخدم الطريق ١ , يمكنك قراءة المزيد من هنا

قم باضافة هذا السطر الى build.gradle

implementation 'com.google.android.exoplayer:exoplayer:2٫+'

قم بالتاكد من استخدام اخر نسخة.

مثال

سوف اقوم ببناء تطبيق صغير يعمل على تشغيل عدة سور من القران

البيانات موجودة على وسور القران موجودة على

لن اقوم باظهار اي كود ليس له علاقة ب exoplayer, الكود متوفر على github اذا اردت المزيد من التفاصيل

نبدا بتعريف متغيرالمشغل

private lateinit var player: ExoPlayer

بعدها نقوم بتعريف المتغير

player = createExoPlayerInstance()
private fun createExoPlayerInstance(): SimpleExoPlayer {
    return SimpleExoPlayer.Builder(this)
        .build()
}

باستخدام SimpleExoPlayer فاننا لن نحتاج الى تعريف عدة خواص لانه هذا الكلاس مصمم لاغلب انواع الاستخدامات وكل الخواص تاتي بشكل افتراضي

الان سوف نقوم باضافة قائمة التشغيل

    private fun createPlaylist() {
        val playlist = surahList.map { surah ->
            MediaItem.Builder()
                .setUri(surah.audio)
                .setTag(surah)
                .build()
        }
        player.addMediaItems(playlist)
        player.prepare()
    }

سوف اشرح هذا الجزء بالتفصيل:

اول نقوم بعمل map للبيانات وتحويلها الى كائن من نوع MediaItem

 val playlist = surahList.map { surah ->
        MediaItem.Builder()
            .setUri(surah.audio)
            .setTag(surah)
            .build()
    }

نقوم باضافتها الى المشغل

player.addMediaItems(playlist)

بعدها ننادي الدالة

player.prepare()

هذه الدالة تقوم بتجهز وقائمة التشغيل والبدء في معالجة الصوتيات

لمعرفة حالة المشغل ما اذا كان حصل خطأ او انتهى من التحميل او انتهى من الملف الاول وسوف ينتقل الى الثاني او غيره نحتاج الى الاستماع الى عده احداث

player.addListener(listener)

نقوم بمنادة Player.Listener الدالة ونمرر المتغير وهو Interface يتيح لنا عدة دوال :

مثل

  • onIsPlayingChanged يتم منادتها اذا توقف او بدء التشغيل
  • onMediaItemTransition يتم المنادة اذا انتهى المسار الصوتي وانتقل الى المسار التالي onPlaybackStateChanged تتم المناداة اذا تغير حالة المشغل وهي واحد من اربع حالات:

    • Player.STATE_BUFFERINGتحدث هذه الحالة عادةً عند الحاجة إلى تحميل المزيد من البيانات.
    • Player.STATE_ENDED انتهى من تشغيل الوسائط
    • Player.STATE_IDLE المشغل ليس لديه أي وسائط
    • Player.STATE_READYالمشغل جاهز للبدء
  • وغيرها الكثير

البدء في التشغيل وباقي التحكمات

يمكن بدء التشغيل بطريقتين

الاولى:

منادة الدالة

player.playWhenReady = true

التي بدورها تعطي امرا للمشغل بالبدء من تلقاء من نفسه اذا توفرت البيانات

player.release()

يستخدم لايقاف المشغل وتحرير اي كائن له علاقة بالمشغل

player.pause()

يستخدم لايقاف التشغيل ويمكن استئناف التشغل بمنادة الامر play

player.stop()

يوقف التشغيل بدون إعادة ضبط المشغل. استخدم pause() بدلاً من هذه الطريقة إذا كانت النية هي إيقاف التشغيل مؤقتًا.

seekTo(int windowIndex, long positionMs)

تستخدم للانتقال بين المسارات مع تحديد الزمن, يجب استخدامها بحذر لان المشغل سوف يرسل خطأ اذا تم تمرير رقم مسار خاطئ او غير موجود

seekTo(long positionMs)

تستخدم للانتقال الى زمن معين في نفس المسار الحالي

كانت هذه هي التحكمات الاساسية

نقوم الان بشتغيل المثال:

كانت هذه مقدمة بسيطة للمكتبة , في مواضيع مستقبلية سوف اقوم بشرح مواضيع اضافة. الكود متوفر على github اذا اردت المزيد من التفاصيل