Repository navigation
Releases: akamusti/CastMane
Release list
CastMane v0.9.11
Bu sürümde ne oldu
Wayland (portal) backend'inde ses iki ayrı yönden bozuktu. İkisi de aynı
boru hattında, ses dalının nasıl kurulduğuyla ilgiliydi.
1. Kayıtlar AAC yerine sıkıştırmasız PCM saklıyordu
Issue #10'da bildirildi: Wayland'de ses açıkken alınan kayıtların ses
track'i pcm_s16le olarak yazılıyor, aac değil. Ses düzgün
çaldığı için kimse fark etmiyordu; sadece dosya aynı süre için yaklaşık
üç kat büyük oluyordu. 32 saniyelik bir çekim yaklaşık 10 MB'a
çıkıyordu.
Nedeni şuydu: AAC encoder (avenc_aac ! aacparse) ses dalının sonundaki
hedefe bakılarak ekleniyordu — sadece doğrudan kayıt muxer'ına
giden dallarda. Replay buffer açıldığında ses hedefi bir tee oluyor
(kayıt + replay ring'i aynı akıştan ayırmak için), encoder o durumda
hiç pipeline'a girmiyordu. Yani encoder "bypass" olmuyordu, tamamen
eksikti; pulsesrc'ten gelen ham PCM doğrudan tee üzerinden
matroskamux'a ve splitmuxsink'e akıyordu. Ham PCM Matroska'da
geçerli bir format olduğu için GStreamer bunu bir hata saymıyor,
sessizce yazıyordu.
Değişiklik: encoder'ın ait olduğu yer dallardır, hedef değil. Tek
kaynak modunda ses artık avenc_aac ! aacparse sonrası AAC olarak hem
kayıt dosyasına hem de replay ring'ine gider. both modunda değişiklik
yok — orada zaten tek encoder mixer'ın altında.
Bunu canlı portal diyaloğu açmadan, aynı pipeline şeklini
kullanan gerçek gst-launch çalıştırmalarıyla doğruladım
(pipewiresrc/pulsesrc yerine test kaynakları): replay açık/kapalı ×
mic/desktop/both, yani 6 kombinasyonun hepsinde kayıt ve replay
ring'i h264 + aac içeriyor. Düzeltme öncesi aynı tabloda replay
kapalı senaryolar hiç başlamıyor, replay açık senaryolar ise
pcm_s16le veriyordu. MP4 remux (ffmpeg -c copy) AAC'i olduğu gibi
taşıyor.
2. Replay buffer kapalıyken sesli kayıt hiç başlamıyordu
Bunu issue'daki cümleden yola çıkarakpipeline'ı çalıştırırken
gördüm: ses açık, replay kapalı olduğunda boru hattı kurulmuyor.
Video dalı filesink ile bitiyor, ses dalı ise "!" ile ona
zincirleniyordu. filesink'in output pad'i yok, bu yüzden GStreamer
tüm pipeline'ı reddediyor:
UYARI: hatalı boru hattı: filesink0, pulsesrc0'a bağlanamadı
CastMane bunu kayıt başlatma sırasındaki erken ölüm kontrolünde
yakalayıp "GStreamer pipeline failed to start" hatası veriyordu. Yani
Wayland'da ses açık, replay kapalıyken kayda hiç başlanamıyordu. Aynı
sebeple both modundaki mixer de filesink'in arkasına zincirleniyordu.
Bu, ses özelliği eklendiğinden beri böyleydi; sorun ses "bozuk"
olduğu için değil, hiç var olmadığı için görünmemiş.
Düzeltme: ses kaynakları her zaman kendi pipeline dalını açıyor. Replay
buffer'ın splitmuxsink'i de bir sink olduğu için zaten gerekliydi,
şimdi bu kural dosink için de geçerli.
Bu iki hata neden aynı yerdeydi?
Sesin nereye bağlandığı, pipeline'ın hangi dalda bittiğine bağlıydı.
Replay buffer eklenirken (PR #9) bu dallar yeniden düzenlendi ve
"!" zincirlemesi yalnızca replay senaryosu için düzeltildi; replay'siz
yol kendi halinde kaldı. İkisini de aynı kuralla birleştirdim: ses
dalı daima bağımsız bir dal, encoder daima dalın parçası.
Bilinen sorunlar
bothmodunda mixer çıkışının örnekleme hızıaudioresample
caps'ine sabitlenmiyor. 48 kHz dışı bir kaynak gelirseavenc_aac
başarısız olur — ama bu durumda pipeline sessizce bozulmaz, açık bir
hata verir. Ayrı bir iş olarak ele alınabilir.- Portal diyaloğu gerçek bir ekran ve kullanıcı seçimi gerektirdiği
için bu sürümde canlı kayıtla uçtan uca test yapılamadı; doğrulama
aynı pipeline yapısını kullanan GStreamer çalıştırmalarıyla yapıldı.
CastMane v0.9.10
CastMane 0.9.10
Bu sürümde uygulamayı baştan sona tarayıp üç ciddi hata buldum ve düzelttim. Hepsini gerçek
ortamda çalıştırarak doğruladım — X11 ve Wayland (portal) backend'lerinin ikisinde de.
Önce uygulamayı gerçekten çalıştırdım
Kodu okumakla yetinmedim. Uygulamayı offscreen modda açtım, kayıt komutlarını gerçekten
ürettim, ffmpeg'i çalıştırdım, çıkan dosyaları ffprobe ile açtım. i18n sözlüğünü,
AppConfig'i ve her iki backend'in komut üretimini statik olarak taradım. Temiz çıkan şeyler:
173 i18n anahtarı en/tr arasında birebir aynı, shell=True/os.system hiç yok,
finalize_part() boş dosyayı promote etmiyor. Sonra üç gerçek hata çıktı.
1. X11 backend hiç kayıt üretmiyordu (#4)
recorder.py kayıt dosyasını ...mp4.part ismiyle ffmpeg'e veriyordu ama hangi konteynere
yazılacağını söylemiyordu. .part uzantısı ffmpeg'in uzantıdan muxer tahminini bozuyor, encoder
ilk kareyi yazmadan rc=234 ile ölüyordu. Yani X11 altında hiçbir kayıt oluşmuyordu.
Aynı komutu iki kez çalıştırdım: -f mp4 eklenince 0 byte → 8.5 KB'ya çıktı. Tek satırlık
düzeltme, ama etkisi kritik.
Bunu neden kimse fark etmemiş diye düşündüm: sen Wayland kullanıyorsun ve portal backend'i
GStreamer'da muxer'ı açıkça belirttiği için etkilenmiyor. Hata sadece X11'li makinelerde
görünüyordu.
2. Stop'a basınca pencere donuyordu (#6)
_stop_recording() encoder'ı kapatmayı ve crash-safe MKV→MP4 remux işlemini doğrudan Qt UI
thread'inde yapıyordu. Remux'un timeout=180'i vardı, yani pencere üç dakika boyunca
kaydedilemiyor, tıklanamıyor, boyutlandırılamıyor oluyordu. Replay save'da da 120 saniyelik
concat vardı, ve pencereyi kapatmak da aynı yolu kullanıyordu.
Artık bu işler bir worker thread'e taşındı. Stop'a basınca "Tamamlanıyor…" durumu çıkıyor,
kayıt/replay butonları kilitleniyor, sonuç bir signal ile UI thread'ine geri dönüyor. Gerçek
portal oturumunda ölçtüm: Stop 21 ms'de devredildi, finalize 0.31 saniye sürdü ve bu sırada UI
384 tick işledi. Finalize bittikten sonra ikinci bir kayıt da sorunsuz başlıyor.
3. Replay buffer tamamen ölüydü (#5)
Bu, en sevdiğim bulgu. replay.py içinde segment üreten komut hazırdı ama hiçbir yerden
çağrılmıyordu — build_replay_cmd() sıfır çağrıya sahipti. Yani hiçbir zaman .replay
dizini dolmuyordu ve Replay Save butonu ile T kısayolu her zaman "replay tamponu boş" diyordu.
Ama arayüzde özellik açıkça vaat ediliyordu.
Altında aslında üç ayrı hata yatıyordu, üçünü de buldum:
- Kimse segment'i yazmıyordu. Artık
ReplayRecordervar, kayıtla birlikte başlıyor ve
kayıtla birlikte duruyor. - ffmpeg segment'leri bozuktu. Segment muxer'ı sadece keyframe'de kesebiliyor, ama
openh264'ün varsayılan GOP'u bir segmentten çok uzun — bu yüzden dosyalar 48 byte'lık boş
kabuklar olarak kalıyordu. Artık her segment için keyframe isteniyor. save_replay()hiçbir zaman birleştiremiyordu. Concat listesini-i pipe:0ile
veriyordum, bu yüzden concat demuxerpipe:/tmp/.../replay_000.mp4arıyor ve her seferinde
başarısız oluyordu. Artık gerçek bir liste dosyası yazıyor.
Portal tarafında bir ara çıkmaza girdim: ikinci bir gst-launch süreci aynı PipeWire fd'ini
kullanamıyor — sürece temiz başlıyor, log boş, dosya 0 byte. Senin onayınla ring'i ana
pipeline'ın içine tee ile ekledim: aynı kodlanmış akış splitmuxsink ile ikinci bir halka
dosyasına yazılıyor. Yani ikinci encoder yok, ikinci izin penceresi yok, hatta daha az
kaynak tüketimi var.
Bu arada iki GStreamer tuzağı çıktı ve ikisini de testle kapattım: her tee dalı kendi
queue'sunu istiyor (yoksa "tee, mux'a bağlanamadı"), ve splitmuxsink'tan sonra gelen bir
kaynak ! ile bağlanamıyor.
Doğrulama
| Backend | Kayıt | Replay sonucu |
|---|---|---|
| X11 | 25 sn | 3 segment → h264,1920,1080, süre 25.03 sn |
| Portal (sesli) | 32 sn | 5 segment → h264,video + audio, 10.6 MB |
X11'de replay süresinin kayıt süresiyle birebir tutması tam da istenen davranıştı.
Bilinen bir sorun
Portal kayıtları sesi AAC yerine pcm_s16le (sıkıştırmasız) olarak yazıyor, bu da dosyayı
şişiriyor. Playback normal, sadece dosya boyutu etkileniyor. Bunu ayrı bir issue olarak açtım
(#10) — bu sürümde dokunmadım, çünkü replay işinden bağımsız ve kök nedeni ayrı araştırma
gerektiriyor.
Testler
104 test geçiyor, ruff check temiz. Eklenen ana testler:
test_x11_recording_produces_a_playable_file— gerçek bir saniyelik kayıt alıp
finalize_part()sonrasıffprobeile doğruluyor.test_stop_nonblocking.py— yavaş birstop()stub'ı ile UI thread'inin bloklanmadığını ve
sonucun farklı thread'de uygulandığını ölçüyor.test_replay_buffer.py(16 test) — GOP, keyframe, halka budama, liste dosyasıyla birleştirme,
her iki backend'in pipeline yapısı ve UI bağlantıları.
Gereksinimler
AppImage içinde Python, PySide6 ve dbus-next geliyor. Sistemde bulunması gerekenler:
ffmpeg(X11 backend ve son MKV→MP4 remux)gst-launch-1.0+pipewiresrc,openh264enc,matroskamux,splitmuxsink(Wayland)xdg-desktop-portal(Wayland)
Fedora:
sudo dnf install ffmpeg gstreamer1 gstreamer1-plugin-pipewire gstreamer1-plugin-openh264 \
gstreamer1-plugins-good xdg-desktop-portalKurulum
chmod +x CastMane-0.9.10-x86_64.AppImage
./CastMane-0.9.10-x86_64.AppImageTeşekkürler, umarım işine yarar. Bir sorun çıkarsa issue açmakten çekinme.
CastMane v0.9.6
Studio layout fix: the preview no longer swallows the window, Sources/Camera/Controls cards fit without clipping, sources list shows all four channels, and the camera card uses full-width rows.
CastMane v0.9.5
OBS-style studio: live screen preview while recording, camera picture-in-picture (preview + optional burn-in), Sources panel (Display/Camera/Mic/Desktop), Camera card with device picker, and Controls mirroring the transport bar. Camera burn-in uses an ffmpeg overlay on X11 and a GStreamer compositor branch on Wayland.
CastMane v0.9.4
UI layout fixes: the READY/RECORDING pill and the digital timer no longer stretch to the full header height, the sidebar active rail no longer collides with the nav card border, the theme selector no longer clips its labels at the 780px minimum window width, and the mixer readouts hug their text. Region preset buttons are now translated.
CastMane v0.9.3
Modernized studio UI with cards and refined styling, polished output page and transport layout. Fixed countdown timer rendering for all choices (incl. 10s).
CastMane v0.9.0
Studio UI redesign: card-grouped settings, header state pill, mixer with channel faders, taller transport dock. Plus per-source mixer gain, replay buffer, configurable shortcuts.
CastMane v0.8.7
Per-source audio mixer (mic/desktop gain), replay buffer (rolling segments + lossless save), configurable shortcuts + headless --record/--replay-save CLI.
CastMane v0.8.3
New in v0.8.3
- Header logo stays visible on dark themes (Midnight, Dark, Forest, Dracula, Nord) with a white mark tile
- Also since v0.8.0: interrupted-recording recovery dialog, MP4/MKV choice, Custom quality preset, recent-recordings list
Install
chmod +x CastMane-0.8.3-x86_64.AppImage
./CastMane-0.8.3-x86_64.AppImageCastMane v0.8.0
New in v0.8.0
- 5 new themes: Ocean, Midnight, Forest, Dracula, Nord (7 total)
- Theme-aware toggle switch: readable on/off knob on every theme, hairline knob edge, themed disabled state
Install
chmod +x CastMane-0.8.0-x86_64.AppImage
./CastMane-0.8.0-x86_64.AppImageHost requirements: ffmpeg, gst-launch-1.0 (+ pipewiresrc/openh264enc/matroskamux), xdg-desktop-portal ScreenCast backend.