Player Performans Serisi Madde 5 / 8

HLS Instance Reuse

Spotify/YouTube tarzı havuz yönetimi ile şarkı geçişlerinde sıfır gecikme

Tek dosya değişikliği ~20 satır azalma 8 adım Düşük risk

Basit Anlatım (Herkes İçin)

Problem: Şu an her şarkı değiştiğinde player, HLS oynatıcısını (ses akışını yöneten parça) tamamen yıkıp sıfırdan yenisini oluşturuyor. Bu tıpkı her yeni şarkı için araba motorunu kapatıp yeniden çalıştırmak gibi — gereksiz zaman ve enerji kaybı.

Çözüm: Spotify ve YouTube'un yaptığı gibi, 2 tane HLS oynatıcısı baştan hazır tutulacak. Şarkı değiştiğinde mevcut oynatıcı "temizlenip" havuza geri konacak, yeni şarkı için havuzdan hazır bir oynatıcı alınacak. Motor hiç kapanmayacak, sadece vites değişecek.

Neden önemli? Şarkı geçişleri daha hızlı olacak, tarayıcı daha az bellek harcayacak ve özellikle uzun dinleme seanslarında donma/takılma riski azalacak.

Mevcut Durum

3 noktada new Hls()
Her seferinde ~70 satır config tekrarlanıyor
7+ noktada hls.destroy()
Instance tamamen yıkılıp bellekten siliniyor
GC baskısı
Her destroy/create döngüsü garbage collector'ı tetikliyor
Geçiş gecikmesi
Yeni instance oluşturma ~50-100ms sürüyor

Hedef Durum

Tek HlsPool yöneticisi
2 instance baştan hazır, havuzda bekliyor
acquire() / release()
Yıkmak yerine temizle + geri koy
Sıfır GC baskısı
Instance'lar yaşamaya devam ediyor, sadece state temizleniyor
Config tekrarı yok
HLS_SHARED_CONFIG tek yerde tanımlı

Teknik Detaylar (Geliştiriciler İçin)

Değişecek Dosya: public/themes/muzibu/js/player/core/player-core.js
1

HlsPool Manager + Paylaşılan Config Ekle

~satır 260 civarı, utility fonksiyonların altına

HlsPool Yapısı:
init(config) → 2 instance oluştur
acquire() → Boş instance al
release(hls) → Temizle + havuza geri koy
taint(hls) → Kirli işaretle
destroyAll() → Sayfa kapanışı temizlik
HLS_SHARED_CONFIG:
20sn buffer, 30MB limit, retry policy, xhrSetup — tek yerde tanımlı
2

init() İçinde Pool Başlat

~satır 795, Hls.isSupported() kontrolü içinde

if (Hls.isSupported()) { HlsPool.init(HLS_SHARED_CONFIG); }
window.addEventListener('beforeunload', () => HlsPool.destroyAll());
3-5

new Hls()HlsPool.acquire()

3 noktada değişiklik, ~90 satır inline config kaldırılır

Fonksiyon Satır Kaldırılan Yeni Kod
playHlsStream() ~4596 70 satır config this.hls = HlsPool.acquire()
preloadNextSong() ~6928 10 satır config hlsPreload = HlsPool.acquire()
createNextHlsPlayer() ~2209 Config bloğu this.hlsNext = HlsPool.acquire()
6

destroy()HlsPool.release()

7 noktada destroy çağrısı release ile değiştirilir

Fonksiyon Açıklama
createNextHlsPlayer error Crossfade hata → release(hlsNext)
completeCrossfade Fade bitti → eski release(this.hls)
stopCurrentPlayback (hls) Durdur → release(this.hls)
stopCurrentPlayback (hlsNext) Next durdur → release(this.hlsNext)
Gapless old HLS cleanup Eski HLS → release(oldHls)
_cleanupPreloadedNext Preload temizle → release(preloadInfo.hls)
7

Fatal Hata → taint() + release()

Kurtarılamaz hatalarda instance kirli işaretlenip havuza geri verilir, release sırasında destroy + yenisi oluşturulur

401 retry tükendi (~satır 4896)
Token yenilemesi başarısız
Fatal HLS error (~satır 4999)
HLS kütüphanesi kurtarılamaz hata
Retry path (~satır 5480)
Yeniden deneme mekanizması
MP3 fallback (~satır 5509)
HLS başarısız → MP3'e geçiş
8

Event Listener Güvenliği

Reuse edilen instance'ta eski listener'ların kalmaması garantilenir

release() her zaman removeAllListeners() çağırır
Her playHlsStream() yeni playSessionId closure oluşturur
Stale event'ler playSessionId karşılaştırmasıyla filtrelenir

Dokunulmayacaklar

Safari native HLS path (Hls.isSupported() = false)
Audio element lifecycle (safeAudioCleanup, DOM)
Blob URL wrapping (her şarkıda yeni blob)
refreshHlsUrlForCurrentSong (mevcut instance üzerinde)
Pause/Resume (destroy yapmıyor, audio.pause())

Havuz Akış Diyagramı

┌─────────────────────────────────────────────────┐
│                  HlsPool (2 slot)               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐      │
│  │ Instance  │  │ Instance  │  │ Overflow  │     │
│  │    #1     │  │    #2     │  │ (gerekirse│     │
│  │  ● idle   │  │  ● idle   │  │  oluşur)  │     │
│  └────┬─────┘  └────┬─────┘  └───────────┘      │
│       │              │                           │
└───────┼──────────────┼───────────────────────────┘
        │              │
   acquire()      acquire()
        │              │
        ▼              ▼
  ┌──────────┐  ┌──────────┐
  │  Ana      │  │ Preload / │
  │  Player   │  │ Crossfade │
  │ (this.hls)│  │           │
  └────┬─────┘  └────┬─────┘
       │              │
  release()      release()
  ┌────┘              └────┐
  │  removeAllListeners()  │
  │  stopLoad()            │
  │  detachMedia()         │
  └────────┬───────────────┘
           │
     Havuza geri koy
           │
     ┌─────┴─────┐
     │  tainted?  │
     ├─ Hayır ────→ Direkt geri koy
     └─ Evet ─────→ destroy() + new Hls() → havuza koy
                

Değişiklik Özeti

~80
Satır eklenen
HlsPool + Config
~90
Satır kaldırılan
3x inline config
~30
Satır değişen
destroy → release
-20
Net fark
Daha az kod

Test Planı

1
Temel çalma
Şarkı çal, pool'dan instance alındığını doğrula
2
Şarkı geçişi
Next → eski release, yeni acquire doğrula
3
Gapless preload
İkinci instance preload, geçişte release
4
Crossfade
2 instance aktif, fade sonrası eski release
5
Hızlı skip
10+ şarkı hızla geç, pool leak olmasın
6
Pause/Resume
Pause'da release olmasın
7
Hata kurtarma
Fatal → taint + release → yeni instance
8
Debug panel + Bellek
Audio Elements max 2, 30+ şarkı bellek stabil
İmplementasyon sonrası ABA test promptu hazırlanacak, mztest.muzibu.com üzerinde test edilecek.
18 Şubat 2026 • Muzibu.com.tr