HLS Sistemi, Adaptive Bitrate, Soft Mode, Crossfade ve Tam Mimari Analiz
Muzibu'nun müzik çalar sistemi. Spotify veya Apple Music'teki çalar gibi düşünün. Şarkı seçersiniz, çalar, sonraki şarkıya geçer, ses ayarlarsınız.
HLS (HTTP Live Streaming) = Şarkıyı küçük parçalara bölüp gönderme yöntemi. Netflix videoları nasıl parça parça yükleniyorsa, şarkılar da öyle. Bant genişliğiniz düşerse kalite otomatik düşer, yükselirse kalite artar. Neden önemli? Hem korsan indirmeyi zorlaştırır, hem de internet hızına göre en iyi deneyimi sunar.
İnterneti hızlı olan kişiye yüksek kaliteli ses, yavaş olan kişiye düşük kaliteli ses gönderme. Otomatik. 4 seviye var: Ultra düşük (32k), Düşük (64k), Orta (128k), Yüksek (~250k). Neden önemli? Mobil verideyken az veri harcar, WiFi'deyken en iyi kaliteyi verir.
Bazı kullanıcılara (kurumsal, çok kullanıcılı hesaplar) düşük kaliteli ses sunma modu. Sunucu yükünü ve bant genişliği maliyetini azaltır. Neden önemli? 50+ kullanıcılı kurumsal hesaplarda sunucu maliyetini %60-70 düşürebilir.
Toplamda 26 sorun tespit edildi. Bunlardan 5'i kritik (acil düzeltilmeli), 9'u orta seviye, 12'si düşük seviye iyileştirme. Kritik sorunlar: şifreleme dosya adı çakışması, segment süresi tutarsızlığı ve kalite filtresi hatası.
public/themes/muzibu/js/player/ ├── core/ │ ├── player-core.js # Ana Alpine.js bileşeni (8.514 satır) │ └── safe-storage.js # localStorage güvenli wrapper ├── features/ │ ├── api.js # Kimlikli fetch helper (401 handling) │ ├── auth.js # Giriş/kayıt sistemi │ ├── buffer-monitor.js # Buffer sağlık takibi │ ├── device-profiler.js # Cihaz profilleme (RAM, CPU) │ ├── favorites.js # Favori şarkı/playlist │ ├── old-device-checker.js # Eski cihaz tespiti │ ├── performance-debug.js # Performans izleme │ ├── play-helpers.js # Çalma yardımcıları │ ├── session.js # Oturum yönetimi │ ├── spa-router.js # SPA sayfa geçişleri │ ├── speed-tester.js # Ağ hız testi │ └── spot-player.js # Kurumsal reklam oynatıcı └── lib/ └── hls.min.js # HLS.js v1.4.12
isLoggedIn — Giriş durumucurrentUser — Kullanıcı bilgilerishowAuthModal — Giriş modaliisPlaying — Çalıyor mucurrentTime / duration — Zamanvolume / isMuted — SesprogressPercent — İlerlemeisHlsStream — HLS aktif mihlsCurrentLevel — Kalite (0-3)isSlowConnection — Yavaş bağlantıcurrentStreamType — "hls" / "mp3"HLS_SHARED_CONFIG = {
enableWorker: true, // Web Worker ile ayrı thread
lowLatencyMode: false, // VOD, canlı değil
autoStartLoad: false, // Manuel başlatma (ABR lock için KRİTİK)
startLevel: 3, // Yüksek kaliteden başla
abrEwmaDefaultEstimate: 250000, // 250kbps başlangıç tahmini
abrBandWidthUpFactor: 0.5, // Muhafazakar yükseltme (0.7→0.5)
abrBandWidthFactor: 0.8, // Muhafazakar düşürme (0.95→0.8)
maxBufferLength: 12, // 12sn buffer (GC dostu)
keyLoadPolicy: {
default: {
maxTimeToFirstByteMs: 10000, // Key yükleme timeout: 10sn
maxLoadTimeMs: 20000, // Key toplam timeout: 20sn
timeoutRetry: { maxNumRetry: 3, retryDelayMs: 1000 }
}
}
}
Problem: HLS.js v1.4.12'de key-loader race condition — aynı key URI için birden fazla fragment yüklenmesi keyUriToKeyInfo map'ini eziyor.
Çözüm: 3 katmanlı key önbellekleme sistemi:
_hlsKeyCache[]'e kaydetCachingKeyLoader — HLS.js XHR'ı intercept et, cache'ten senkron döndüracquire() — Havuzdan alrelease() — Havuza geri verhls.stopLoad()hls.detachMedia()hls.removeAllListeners()hls.destroy()audio.load() — MediaSource flushTetikleyiciler: HLS init hatası, Fatal error, bufferAppendError, 60sn timeout
triggerMp3Fallback(reason):
1. HLS taint + release (pool'a geri ver)
2. Blob URL cleanup
3. safeAudioCleanup() — Event handler temizleme
4. fallback_url varsa → playWithHowler()
5. Toast: "HLS başarısız, MP3 ile çalınıyor..."
ffmpeg -i input.mp3 \
-c:a aac -b:a {bitrate}k \
-af "loudnorm + stereotools + eq + lowpass" \
-hls_key_info_file enc.keyinfo \
-hls_time 6 -hls_list_size 0 \
-hls_segment_filename "segment-%03d.ts" \
playlist.m3u8
| Seviye | Bitrate | Kanal | Sample Rate | Segment |
|---|---|---|---|---|
| ultralow | 32 kbps | Mono | 22.05 kHz | 4 sn |
| low | 64 kbps | Mono | 22.05 kHz | 4 sn |
| mid | 128 kbps | Stereo | 44.1 kHz | 4 sn |
| high | ~180-280 kbps | Stereo | 44.1 kHz | 6 sn |
GET /hls-key/muzibu/songs/{id}?token=...&sig=...&expires=...storage/tenant{id}/app/public/muzibu/hls/{songId}/enc.bin| Endpoint | Yetki | Açıklama |
|---|---|---|
/api/muzibu/songs/{id}/stream | Auth | Şifreli HLS/MP3 URL döndürür |
/hls/muzibu/songs/{id}/master.m3u8 | Signed | Master playlist (variant listesi) |
/hls/muzibu/songs/{id}/segment-*.ts | Public | AES-128 şifreli segment (auth yok) |
/hls-key/muzibu/songs/{id} | Signed+Rate | 16-byte AES-128 key (60req/dk) |
/audio/songs/{id}/{exp}/{sig} | Signed | CDN MP3 URL (path-based) |
/songs/{id}/track-start | Sanctum | Dinleme başlangıcı (play_id döner) |
/songs/{id}/track-hit | Sanctum | 30sn milestone (play_count++) |
/songs/{id}/track-end | Sanctum | Bitiriş/atlama (sendBeacon) |
startLevel: 3 — Yüksek kaliteden başlar, gerekirse düşürürabrEwmaDefaultEstimate: 250kbps — EWMA algoritması ile ölçümabrBandWidthUpFactor: 0.5 — 2x bant genişliği gerekli (muhafazakar)abrBandWidthFactor: 0.8 — %80 altına düşerse kalite indirilirloadSource() öncesi → _abrStartupLocked = true
MANIFEST_PARSED → currentLevel = startLevel (sabit)
FRAG_BUFFERED → unlockABR() → currentLevel = -1 (oto)
user.audio_preference — Admin panelden atananMUZIBU_DEFAULT_AUDIO_FORMAT=autoNe yapar? Master playlist'ten yüksek kalite variant'ları çıkarır.
// SongStreamController::serveHls() if (soft=1) { allowed = ['ultralow', 'low'] // config'den // high ve mid kaldırılır master.m3u8 → sadece ultralow + low }
Backend şifreli URL döndürür: response._ + response.__
Frontend XOR ile çözer → stream_url, fallback_url, stream_type
Kod hazır ancak kapalı. HLS keyLoadError sorunu çözüldü, artık açılabilir.
hlsAudio — Aktif çalan elementhlsAudioNext — Preload / crossfade element_nextTrackInProgress eşzamanlılık kilidifromNaturalEnd: true → gapless geçiş_safePlayFromQueue(): max 3 deneme + token yenileme_refillQueue()_fetchUniqueGenreSongs)
/songs/popular)
Algoritma: HMAC-SHA256
Base: "{path}|{user_id}|{expires}"
Key: config('app.key')
Doğrulama: sig === expected_sig && now < expires
Playlist ve key endpoint'lerinde zorunlu. Segment'ler AES-128 şifreli olduğu için imzasız sunulur (CDN uyumlu).
| Optimizasyon | Konum | Etki |
|---|---|---|
| G1 Lazy HLS.js yükleme | Satır 14-36 | JS bundle küçülür, sayfa hızlanır |
| Progress 250ms interval | Satır 6235 | Ana thread yükü %60 azalır |
| HLS Instance havuzu | Satır 548-678 | Instance oluşturma/yok etme maliyeti sıfır |
| Key pre-cache | Satır 352-454 | Key yükleme gecikmesi sıfır |
| DOM cache (hlsAudio lookup) | Satır 1044-1060 | DOM sorguları ~0 |
| Stream LRU cache | Satır 7289-7299 | Tekrar çalma: ağ isteği yok |
| Segment'ler session'sız | Route middleware | Paralel 30+ istek → session kilidi yok |
| M3U8 disk cache (3600sn) | Controller | Dosya okuma maliyeti azalır |
| CDN uyumlu path-based URL | SignedUrlService | Cloudflare cache kullanılabilir |
| Buffer 12sn (GC dostu) | HLS config | Bellek baskısı azalır |
HLSService.php:125$targetBitrate değişkeni generateMasterPlaylist() çağırıldığında tanımsız. calculateTargetBitrate() sonucu dış scope'a taşınmıyor.// calculateTargetBitrate() sonucunu sakla
$targetBitrate = $this->calculateTargetBitrate($originalBitrate);
// ... FFmpeg komutunu oluştur ...
$highBitrate = (int) str_replace('k', '', $targetBitrate) * 1000;
$this->generateMasterPlaylist($storagePath, $highBitrate);
ConvertToHLSJob.php:138 vs HLSService.php:20-hls_time 6 → HLSService: CHUNK_DURATION = 4SongStreamController.php:754-777playlist.m3u8 satırını kaldırıyor, #EXT-X-STREAM-INF header satırını bırakıyor. Kalan header → HLS.js'de "playlist not found" hatası.
enc.bin, HLSService → enc.key, SongStreamController → enc.bin arıyorenc.key, ama serveKey() enc.bin arıyor.enc.key) belirlenip tüm dosyalarda uygulanmalı.
?q=mp3_128 gönderiliyor ama backend'de bu parametreyi alan endpoint belirsiz.| Bileşen | Dosya Yolu | Satır |
|---|---|---|
| Ana Player | public/themes/muzibu/js/player/core/player-core.js | 8.514 |
| Stream Controller | Modules/Muzibu/App/Http/Controllers/Api/SongStreamController.php | ~800 |
| HLS Servisi | app/Services/Muzibu/HLSService.php | ~650 |
| Dönüştürme Job | Modules/Muzibu/App/Jobs/ConvertToHLSJob.php | ~250 |
| Signed URL | app/Services/SignedUrlService.php | ~180 |
| Variant Command | Modules/Muzibu/App/Console/Commands/AddHlsVariantsCommand.php | ~280 |
| Muzibu Config | Modules/Muzibu/config/config.php | ~80 |
| API Routes | Modules/Muzibu/routes/api.php | ~100 |
| Player Blade | resources/views/themes/muzibu/components/player.blade.php | ~500 |
| HLS.js Kütüphane | public/themes/muzibu/js/player/lib/hls.min.js | v1.4.12 |