ExoPlayer یک کتابخانه پخشکننده رسانه متنباز برای اندروید است که توسط گوگل به عنوان جایگزینی برای MediaPlayer داخلی توسعه یافته است. ExoPlayer پخش صوتی و تصویری را در فرمتهای مختلف از جمله DASH، HLS، SmoothStreaming و فایلهای رسانه معمولی از طریق یک API واحد با پشتیبانی از پخش تطبیقی فراهم میکند. به گفته Google I/O (2024)، ExoPlayer در بیش از 60٬000 اپلیکیشن اندروید از جمله YouTube، Google TV و Netflix استفاده میشود.
نکات کلیدی
ExoPlayer یک کتابخانه پخش چندرسانهای برای اندروید با کد متنباز (Apache 2.0) است که اولین نسخه آن توسط گوگل در سال 2014 منتشر شد. برخلاف MediaPlayer داخلی که یک لایه نازک بر روی کدک رسانه سیستمی (MediaCodec) است، ExoPlayer کاملاً در سطح Java/Kotlin پیادهسازی شده است که به توسعهدهندگان کنترل کامل بر هر مرحله از پخش میدهد.
از نظر معماری، ExoPlayer بر اصل ماژولار ساخته شده است: هر جنبه از پخش توسط یک مؤلفه جداگانه پیادهسازی میشود. ماژول اصلی (exoplayer-core) شامل پخشکننده، رندرکنندهها، انتخابگرهای مسیر و مدیریت بافر است. ماژولهای اضافی (exoplayer-dash، exoplayer-hls، exoplayer-rtsp، exoplayer-smoothstreaming) پشتیبانی از پروتکلهای پخش مربوطه را اضافه میکنند. این معماری به اپلیکیشنها اجازه میدهد فقط مؤلفههای لازم را متصل کرده و اندازه APK را به حداقل برسانند.
ExoPlayer 2 (نسخه اصلی فعلی) در سال 2018 منتشر شد و بازنگری اساسی API را به ارمغان آورد: معرفی Player Interface، پشتیبانی از Compose از طریق AndroidX Media3، مدیریت خطای بهبود یافته و الگوریتمهای تطبیقی انتخاب مسیر. از نسخه 2.19 (2024)، ExoPlayer بخشی از کتابخانه AndroidX Media شده است که ادغام و بهروزرسانی را از طریق مدیر وابستگی استاندارد اندروید سادهتر کرده است.
در هسته ExoPlayer مؤلفه ExoPlayerImpl قرار دارد که چرخه حیات پخش را مدیریت میکند. این مؤلفه شامل MediaSource (منبع رسانه)، TrackSelector (انتخاب مسیر)، LoadControl (مدیریت بافر) و فهرستی از Renderer (رندرکنندههای ویدئو، صدا، زیرنویس و فراداده) است. هر مؤلفه میتواند از طریق Builder یا روشهای کارخانهای با پیادهسازی شخصی جایگزین شود.
برای رندر ویدئو، ExoPlayer از SurfaceView، TextureView یا SphericalSurfaceView (برای ویدئوی 360 درجه) استفاده میکند. گزینه توصیهشده SurfaceView است زیرا شتاب سختافزاری و حداقل مصرف انرژی را فراهم میکند. برای Jetpack Compose، کتابخانه AndroidX Media3 مؤلفه `AndroidView` را ارائه میدهد که SurfaceView را میپیچد و همچنین `Media3Compose` آزمایشی با ادغام بومی Compose.
ExoPlayer مجموعه گستردهای از قابلیتهای فراتر از یک پخشکننده رسانه معمولی را فراهم میکند. قابلیتهای اصلی شامل پشتیبانی از تمام پروتکلهای محبوب پخش، سیستم DRM انعطافپذیر، تغییر نرخ بیت تطبیقی (ABR) و ابزارهای تحلیل پخش است.
| قابلیت | توضیحات | ماژول |
|---|---|---|
| DASH | پخش تطبیقی بر اساس استاندارد MPEG | exoplayer-dash |
| HLS | HTTP Live Streaming از اپل | exoplayer-hls |
| SmoothStreaming | پخش تطبیقی از مایکروسافت | exoplayer-smoothstreaming |
| RTSP | پروتکل پخش بلادرنگ برای پخش زنده | exoplayer-rtsp |
| Widevine | حفاظت از محتوای DRM | exoplayer-drm |
| Concatenation | الحاق چند فایل رسانه | exoplayer-core |
| Ads | ادغام IMA SDK برای تبلیغات | exoplayer-ima |
ABR (Adaptive Bitrate) در ExoPlayer از طریق رابط AdaptiveTrackSelection پیادهسازی شده است. به طور پیشفرض از AdaptiveTrackSelectionFactory استفاده میشود که DefaultAdaptiveTrackSelection را ایجاد میکند — یک الگوریتم متعادل که پهنای باند شبکه و اندازه بافر را در نظر میگیرد. برای سناریوهای خاص، میتوان پیادهسازیهای جایگزین را متصل کرد: BOLA (به حداقل رساندن تغییرات)، RandomAdaptiveTrackSelection (تست) یا پیادهسازی شخصی از طریق رابط TrackSelection.
BandwidthMeter یکی دیگر از مؤلفههای کلیدی است که مسئول اندازهگیری پهنای باند شبکه است. به طور پیشفرض از DefaultBandwidthMeter استفاده میشود که آمار تمام درخواستهای HTTP پخشکننده را جمعآوری میکند. توسعهدهنده میتواند آن را برای در نظر گرفتن عوامل اضافی گسترش دهد: نوع شبکه (Wi-Fi، 4G، 5G)، سیگنال دکل مخابراتی یا هزینه ترافیک برای کاربر.
ExoPlayer از Widevine (L1، L3)، PlayReady و ClearKey DRM پشتیبانی میکند. دریافت مجوز از طریق DrmSessionManager که با سرور مجوز تعامل دارد، پیکربندی میشود. برای ویدئوی پریمیوم (4K HDR) پشتیبانی سختافزاری Widevine L1 مورد نیاز است که حفاظت در سطح تراشه را فراهم کرده و از ضبط صفحه جلوگیری میکند. انتخاب سیستم DRM به پلتفرم هدف بستگی دارد: Widevine در اندروید و Chromecast، PlayReady در Xbox و Windows، FairPlay در iOS و Apple TV استفاده میشود. ExoPlayer به طور خودکار سیستم DRM موجود را بر اساس فایل MPD تعیین میکند و برای سناریوهای پایه به پیکربندی دستی نیاز ندارد.
اتصال ExoPlayer به پروژه اندروید از طریق وابستگیهای Gradle انجام میشود. از نسخه 2.19، ExoPlayer بخشی از AndroidX Media (androidx.media3) است که سازگاری با Jetpack Compose و سایر مؤلفههای AndroidX را تضمین میکند. بیایید ادغام گامبهگام در Kotlin را بررسی کنیم.
ماژولهای ExoPlayer را به فایل build.gradle (Module) اضافه کنید. مجموعه حداقلی شامل core، ui و ماژول برای پروتکل پخش مورد نیاز است. برای پخش محتوای DASH به exoplayer-dash و برای HLS به exoplayer-hls نیاز است.
dependencies {
implementation "androidx.media3:media3-exoplayer:1.5.0"
implementation "androidx.media3:media3-ui:1.5.0"
implementation "androidx.media3:media3-exoplayer-dash:1.5.0"
implementation "androidx.media3:media3-exoplayer-hls:1.5.0"
}
ایجاد و پیکربندی پخشکننده در Activity یا Fragment. ExoPlayer از PlayerView (یا StyledPlayerView برای شخصیسازی) برای نمایش ویدئو و کنترلهای داخلی استفاده میکند. حداقل پیکربندی شامل ایجاد پخشکننده از طریق ExoPlayer.Builder و ارسال MediaItem با URI منبع است.
class PlayerActivity : AppCompatActivity() {
private var player: ExoPlayer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_player)
player = ExoPlayer.Builder(this).build()
val playerView = findViewById<StyledPlayerView>(R.id.playerView)
playerView.player = player
val mediaItem = MediaItem
.Builder()
.setUri("https://example.com/video.mp4")
.build()
player?.setMediaItem(mediaItem)
player?.prepare()
}
override fun onDestroy() {
player?.release()
super.onDestroy()
}
}
برای اپلیکیشنهای تولیدی، مدیریت خطاهای احتمالی پخش ضروری است: خرابی شبکه، فرمتهای پشتیبانینشده، خطاهای مجوز DRM. ExoPlayer رابط Player.Listener را با متدهای onPlayerError، onPlaybackStateChanged و onPlayWhenReadyChanged ارائه میدهد. توصیه میشود پیامهای خطای آموزنده با امکان تکرار به کاربر نشان داده شود.
انتخاب بین ExoPlayer و MediaPlayer داخلی یک سوال رایج در توسعه اپلیکیشنهای اندروید است. MediaPlayer از نسخه 1.0 بخشی از Android SDK است، در حالی که ExoPlayer کتابخانهای است که نیاز به اتصال از طریق Gradle دارد. تفاوتهای آنها را بر اساس معیارهای کلیدی بررسی کنیم.
| معیار | ExoPlayer | MediaPlayer |
|---|---|---|
| معماری | ماژولار، کاملاً در Java/Kotlin | لایهای بر مؤلفههای C++ سیستمی |
| پخش | DASH، HLS، SmoothStreaming، RTSP | فقط فایلهای محلی و HLS (اندروید 9+) |
| شخصیسازی | کامل (هر مؤلفه قابل جایگزینی) | حداقل (فقط پارامترها) |
| بهروزرسانیها | از طریق Google Play یا APK (مستقل از OS) | فقط از طریق بهروزرسانی اندروید (OTA) |
| اندازه APK | +1-3 مگابایت (بسته به ماژولها) | 0 (بخشی از سیستم) |
| حداقل SDK | API 16+ (اندروید 4.1) | API 1+ |
| DRM | Widevine، PlayReady، ClearKey | Widevine (محدود) |
ExoPlayer برتر است در سناریوهایی که نیاز به پخش (DASH، HLS)، شخصیسازی UI، پشتیبانی DRM و استقلال از نسخه اندروید دارند. MediaPlayer برای اپلیکیشنهای سادهای که فایلهای رسانه محلی را پخش میکنند، مناسب است جایی که اندازه APK حیاتی است و الزامی برای پخش تطبیقی وجود ندارد. برای اپلیکیشنهای مدرن با محتوای شبکه، ExoPlayer انتخاب قطعی است.
استثنا — اپلیکیشنهایی با حداقل SDK کمتر از API 16 (اندروید 4.1) که عملاً در بازار باقی نماندهاند. برای تمام اپلیکیشنهای با targetSdk 33+ و حداقل SDK 21+، ExoPlayer نه تنها ترجیح داده میشود، بلکه برای پشتیبانی از فرمتهای مدرن مانند AV1 و Dolby Vision از طریق افزونههای مربوطه ضروری است.
برای اپلیکیشنهای تولیدی، ادغام پایه ExoPlayer اغلب به تنظیمات اضافی نیاز دارد: مدیریت حافظه نهان، بهینهسازی بافر برای شبکههای موبایل، ادغام با تحلیل و شخصیسازی انتخاب مسیرهای صوتی. بیایید سناریوهای استفاده پیشرفته را بررسی کنیم.
CacheDataSourceFactory امکان ذخیرهسازی بخشهای بارگیریشده در حافظه محلی را فراهم میکند که باعث صرفهجویی در ترافیک در هنگام تماشای مجدد و پخش آفلاین میشود. ExoPlayer از SimpleCache از کتابخانه exoplayer-cas استفاده میکند — ذخیرهسازی فایلی با پشتیبانی از تخلیه LRU و محدودیت اندازه.
val cache = SimpleCache(
cacheDir,
LeastRecentlyUsedCacheEvictor(50 * 1024 * 1024),
AppDatabaseProvider(this)
)
val cacheDataSourceFactory = CacheDataSource
.Factory()
.setCache(cache)
val player = ExoPlayer.Builder(this)
.setMediaSourceFactory(
DefaultMediaSourceFactory(cacheDataSourceFactory)
)
.build()
در اپلیکیشنهای موبایل، مدیریت تغییر بین Wi-Fi و شبکه سلولی حیاتی است. ExoPlayer ConnectivityManager را برای ردیابی وضعیت شبکه فراهم میکند. هنگام قطع اتصال، توصیه میشود پخشکننده را متوقف نکنید، بلکه با حفظ موقعیت به حالت PAUSED منتقل کنید. پس از بازیابی اتصال، پخش را با بارگیری مجدد بخشها از سر بگیرید.
با انتشار AndroidX Media3، کتابخانه پشتیبانی آزمایشی از Jetpack Compose دریافت کرد. مؤلفه `AndroidView` SurfaceView یا PlayerView را میپیچد و سازگاری با سلسلهمراتب Compose را تضمین میکند. برای ادغام عمیقتر، از کتابخانه `androidx.media3:media3-ui-compose` استفاده میشود که کنترلهای سازگار با Compose را برای پخشکننده فراهم میکند.
@Composable
fun VideoPlayer(uri: String) {
val context = LocalContext.current
val player = remember {
ExoPlayer.Builder(context).build()
.also { it.setMediaItem(MediaItem.fromUri(uri)) }
}
DisposableEffect(key = null) {
player.prepare()
onDispose { player.release() }
}
AndroidView(
factory = { StyledPlayerView(context).also { it.player = player } }
)
}
سوالات متداول
ExoPlayer از Android API 16+ (اندروید 4.1 Jelly Bean) پشتیبانی میکند. با این حال، برای DASH و HLS با بخشهای fMP4، API 21+ (اندروید 5.0 Lollipop) توصیه میشود. ماژولهای DRM (Widevine) به API 19+ نیاز دارند و رمزگشایی سختافزاری HEVC از API 21 در دسترس است.
بله، ExoPlayer برای صدا عالی است. برای پخش فقط صدا به SurfaceView یا PlayerView نیازی نیست. ExoPlayer به طور خودکار رندرکننده صدا را انتخاب کرده و در پسزمینه کار میکند. برای پخش پسزمینه، توصیه میشود از MediaSessionService برای ادغام با کنترلهای سیستمی استفاده کنید.
TrackSelector در ExoPlayer انتخاب مسیرهای صوتی را مدیریت میکند. برای جابجایی از player.getCurrentTracks().groups و player.setTrackSelectionParameters() با指定 زبان صوتی ترجیحی استفاده کنید. برای جریانهای DASH و HLS با چندین مسیر صوتی، جابجایی بدون قطع پخش انجام میشود.
بله، ExoPlayer از زیرنویسهای داخلی (در کانتینر MP4، WebM) و خارجی در فرمتهای TTML، SRT، VTT و CEA-608 پشتیبانی میکند. برای زیرنویسهای خارجی از SingleSampleMediaSource یا MergingMediaSource برای ترکیب با جریان ویدئو استفاده میشود. نمایش زیرنویسهای سبکدار از طریق CaptionStyleCompat پیکربندی میشود.
برای پخش کمتأخیر، LoadControl را با مقادیر هدف بافر کوچکتر پیکربندی کنید: برای HLS LL و DASH LL از DefaultLoadControl.Builder().setTargetBufferBytes(1024 * 512).setBufferDurationsMs(500, 2000, 500, 1000) استفاده کنید. همچنین minPlaybackSpeed = 1.02 را برای پر کردن سریعتر بافر هنگام عقبماندن از پخش زنده تنظیم کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید