Müzik Oynatıcısında "Audio Element Not Found" Hatasının Çözümü
Kullanıcılar şarkı değiştirirken bazen konsolda hata mesajları görüyordu:
HLS audio element not found
Bu hata görünürde bir sorun yaratmıyordu ama sistemde bir şeylerin yolunda gitmediğini gösteriyordu. Özellikle hızlı şarkı değişimlerinde (skip) daha sık ortaya çıkıyordu.
Müzik oynatıcı, şarkılar arası geçişi hızlandırmak için iki ayrı ses oynatıcı elementi kullanıyor. Bir şarkı çalarken diğeri arka planda hazırlanıyor (preload). Bu sayede şarkı değişimi anında oluyor.
Sorun şuydu: Kod, kullanılmayan oynatıcıyı "temizlerken" onu bellekten tamamen siliyordu. Ama hemen ardından başka bir kod parçası aynı oynatıcıyı kullanmaya çalışıyordu. Bu iki işlem aynı anda gerçekleşince "yarış durumu" (race condition) oluşuyordu.
Örnek: İki kişi aynı anda bir kapıyı kullanmaya çalışıyor. Biri kapıyı sökmeye çalışırken diğeri açmaya çalışıyor. Sonuç: Kaos!
Audio Pool Pattern adı verilen bir tasarım deseni uygulandı.
Artık iki ses oynatıcı elementi sürekli hazır durumda tutuluyor. Kullanılmadıklarında tamamen silinmiyorlar, sadece içleri temizlenip boşaltılıyor. Böylece her an kullanıma hazırlar ve "bulunamadı" hatası ortadan kalkıyor.
Benzetme: İki tane havuz var. Kullanılmayan havuzun suyunu boşaltıyoruz ama havuzu yıkmıyoruz. Gerektiğinde hemen doldurup kullanabiliyoruz. Hızlı ve güvenli!
hlsAudio - Birincil audio elementihlsAudioNext - İkincil audio elementi (preload için)activeHlsAudioId - Şu an aktif olan element ID'sihlsAudio ↔ hlsAudioNextSorunlu Kod (player-core.js:4544-4566):
// Satır 4544: "otherAudio"yu temizle
const currentActiveId = this.activeHlsAudioId || 'hlsAudio';
const otherAudioId = currentActiveId === 'hlsAudio' ? 'hlsAudioNext' : 'hlsAudio';
const otherAudio = document.getElementById(otherAudioId);
if (otherAudio && otherAudio.paused) {
safeAudioCleanup(otherAudio, true); // ← DOM'dan SİLİYOR!
}
// Satır 4558: Hemen ardından SABİT ID ile arıyor
const audio = document.getElementById('hlsAudio'); // ← Az önce silinmiş olabilir!
if (!audio) {
console.error('HLS audio element not found'); // ← HATA!
}
Senaryo:
activeHlsAudioId = 'hlsAudioNext' olsunotherAudioId = 'hlsAudio' hesaplanırhlsAudio DOM'dan silinir (removeChild)getElementById('hlsAudio') → nullHLS audio element not foundAudio elementleri hemen silmek yerine 100ms delay ile silmek
Neden reddedildi:
Sorunun sebebini çözmüyor, sadece semptomları gizliyor. Gerçek race condition devam eder.
_audioCleanupInProgress flag'i ile işlemleri senkronize etmek
Neden reddedildi:
Fazla karmaşık, kod bakımını zorlaştırır. Bir işlemi engellemek yerine sorunu kökten çözmeli.
Her getElementById sonrası null kontrolü eklemek
Neden reddedildi:
Kök sebebi çözmüyor, sadece hataları gizliyor. Gerçek sorun (cleanup timing) devam eder.
İki audio elementi sürekli DOM'da tutmak, sadece içeriklerini temizlemek
Avantajları:
Dosya: player-core.js:129-164
Yeni Kod:
function safeAudioCleanup(audio, removeFromDom = false) {
if (!audio) return;
try {
// Event handler'ları temizle
audio.onerror = null;
audio.onended = null;
// ... (diğer handler'lar)
audio.pause();
audio.removeAttribute('src');
audio.load(); // MediaSource buffer'ı serbest bırak
// Pool elementlerini (hlsAudio/hlsAudioNext) DOM'dan ASLA silme!
const isPoolElement = audio.id === 'hlsAudio' || audio.id === 'hlsAudioNext';
if (removeFromDom && audio.parentNode && !isPoolElement) {
// Sadece geçici elementleri sil (spotAudio gibi)
audio.parentNode.removeChild(audio);
console.log('🧹 Geçici audio element DOM\'dan kaldırıldı:', audio.id);
} else if (isPoolElement) {
console.log('🧹 Pool audio element temizlendi (DOM\'da kalıyor):', audio.id);
}
} catch (e) {
console.warn('safeAudioCleanup error:', e);
}
}
Değişiklik: Pool elementleri (hlsAudio/hlsAudioNext) artık DOM'dan silinmiyor. Sadece içerikleri temizlenip boşaltılıyor. spotAudio gibi geçici elementler eski gibi siliniyor.
Dosya: player-core.js:4544-4569
Eski Kod (Hatalı):
const audio = document.getElementById('hlsAudio'); // ← SABİT ID!
Yeni Kod (Doğru):
// Aktif element ID'sini kullan (dinamik)
const currentActiveId = this.activeHlsAudioId || 'hlsAudio';
const audio = document.getElementById(currentActiveId); // ← DİNAMİK ID!
Değişiklik: Sabit 'hlsAudio' ID'si yerine aktif element ID'si kullanılıyor. Bu sayede cleanup ile çakışma olmuyor.
| Dosya | Değişiklik | Satırlar |
|---|---|---|
player-core.js |
safeAudioCleanup güncellendi | 129-164 |
player-core.js |
playHlsStream düzeltildi | 4544-4569 |
Not: app.blade.php zaten iki audio elementi içeriyordu.
HTML tarafında değişiklik gerekmedi.
Checkpoint (Geri dönüş noktası)
079f778cc
🔧 CHECKPOINT (PRODUCTION): Before HLS audio element race condition fix
Çözüm Uygulaması
9ad69a52a
✅ ÇÖZÜM A: Audio Pool Pattern - HLS race condition fix (PRODUCTION)
Geri dönüş: Sorun olursa git reset --hard 079f778cc komutu ile checkpoint'e dönülebilir.
HLS audio element not found artık görünmeyecek?debug=1)✅ Doğrulama:
Debug panelde şöyle bir çıktı göreceksiniz:
[1] ✅ AKTİF - ID: hlsAudio
Src: blob:https://...
Time: 42.3s / 180.0s
State: Playing, Ready: 4, Network: 2
[2] 🧹 Pool audio element temizlendi (DOM'da kalıyor): hlsAudioNext
Src: (temiz)
Time: 0.0s / 0.0s
State: Paused, Ready: 0, Network: 0
Race condition nedeniyle audio elementleri DOM'dan silinip hemen ardından aranıyordu. Sonuç: "HLS audio element not found" hatası.
Audio Pool Pattern uygulandı. Elementler artık DOM'dan silinmiyor, sadece içerikleri temizleniyor. Race condition imkansız hale geldi.
1 dosya: player-core.js
2 fonksiyon güncellendi, ~18 satır değişti
✅ Production'da aktif
✅ Geri dönüş mevcut (git checkpoint)
✅ Test edilmeye hazır