diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 5ef759d6..e4173896 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -802,7 +802,7 @@ repositoryURL = "https://github.com/edde746/MPVKit"; requirement = { kind = exactVersion; - version = 1.0.13; + version = 1.0.14; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e1e0ee96..5e47687f 100644 --- a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/edde746/MPVKit", "state" : { - "revision" : "93101dc1d0903c48fa3054652805acacbb75e856", - "version" : "1.0.13" + "revision" : "3309e7c158e64adc9a5666df5e7aa474f2d3aaec", + "version" : "1.0.14" } }, { diff --git a/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved index e1e0ee96..cc3d2f80 100644 --- a/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,77 +1,77 @@ { - "pins" : [ + "pins": [ { - "identity" : "dkcamera", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKCamera", - "state" : { - "branch" : "master", - "revision" : "5c691d11014b910aff69f960475d70e65d9dcc96" + "identity": "dkcamera", + "kind": "remoteSourceControl", + "location": "https://github.com/zhangao0086/DKCamera", + "state": { + "branch": "master", + "revision": "5c691d11014b910aff69f960475d70e65d9dcc96" } }, { - "identity" : "dkimagepickercontroller", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKImagePickerController", - "state" : { - "branch" : "4.3.9", - "revision" : "0bdfeacefa308545adde07bef86e349186335915" + "identity": "dkimagepickercontroller", + "kind": "remoteSourceControl", + "location": "https://github.com/zhangao0086/DKImagePickerController", + "state": { + "branch": "4.3.9", + "revision": "0bdfeacefa308545adde07bef86e349186335915" } }, { - "identity" : "dkphotogallery", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKPhotoGallery", - "state" : { - "branch" : "master", - "revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d" + "identity": "dkphotogallery", + "kind": "remoteSourceControl", + "location": "https://github.com/zhangao0086/DKPhotoGallery", + "state": { + "branch": "master", + "revision": "311c1bc7a94f1538f82773a79c84374b12a2ef3d" } }, { - "identity" : "mpvkit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/edde746/MPVKit", - "state" : { - "revision" : "93101dc1d0903c48fa3054652805acacbb75e856", - "version" : "1.0.13" + "identity": "mpvkit", + "kind": "remoteSourceControl", + "location": "https://github.com/edde746/MPVKit", + "state": { + "revision": "3309e7c158e64adc9a5666df5e7aa474f2d3aaec", + "version": "1.0.14" } }, { - "identity" : "sdwebimage", - "kind" : "remoteSourceControl", - "location" : "https://github.com/SDWebImage/SDWebImage", - "state" : { - "revision" : "2de3a496eaf6df9a1312862adcfd54acd73c39c0", - "version" : "5.21.7" + "identity": "sdwebimage", + "kind": "remoteSourceControl", + "location": "https://github.com/SDWebImage/SDWebImage", + "state": { + "revision": "2de3a496eaf6df9a1312862adcfd54acd73c39c0", + "version": "5.21.7" } }, { - "identity" : "sentry-cocoa", - "kind" : "remoteSourceControl", - "location" : "https://github.com/getsentry/sentry-cocoa", - "state" : { - "revision" : "f196cbb98e0388381d57908f2f5a9bdc385cde68", - "version" : "8.58.4" + "identity": "sentry-cocoa", + "kind": "remoteSourceControl", + "location": "https://github.com/getsentry/sentry-cocoa", + "state": { + "revision": "f196cbb98e0388381d57908f2f5a9bdc385cde68", + "version": "8.58.4" } }, { - "identity" : "swiftygif", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kirualex/SwiftyGif.git", - "state" : { - "revision" : "4430cbc148baa3907651d40562d96325426f409a", - "version" : "5.4.5" + "identity": "swiftygif", + "kind": "remoteSourceControl", + "location": "https://github.com/kirualex/SwiftyGif.git", + "state": { + "revision": "4430cbc148baa3907651d40562d96325426f409a", + "version": "5.4.5" } }, { - "identity" : "tocropviewcontroller", - "kind" : "remoteSourceControl", - "location" : "https://github.com/TimOliver/TOCropViewController", - "state" : { - "revision" : "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e", - "version" : "2.8.0" + "identity": "tocropviewcontroller", + "kind": "remoteSourceControl", + "location": "https://github.com/TimOliver/TOCropViewController", + "state": { + "revision": "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e", + "version": "2.8.0" } } ], - "version" : 2 + "version": 2 } diff --git a/ios/Runner/MpvPlayer/MpvPlayerPlugin.swift b/ios/Runner/MpvPlayer/MpvPlayerPlugin.swift index 78b70563..58e05aac 100644 --- a/ios/Runner/MpvPlayer/MpvPlayerPlugin.swift +++ b/ios/Runner/MpvPlayer/MpvPlayerPlugin.swift @@ -97,11 +97,44 @@ class MpvPlayerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, MpvPluginS handleUpdateFrame(result: result) case "setLogLevel": handleSetLogLevel(call: call, result: result) + case "getAudioRenderingMode": + result(Self.audioRenderingMode()) default: result(FlutterMethodNotImplemented) } } + /// The system's resolved audio rendering mode, for the Dolby-prescribed + /// playback badge. `AVAudioSession.renderingMode` is tvOS/iOS 17.2+ and is + /// documented as populated for CarPlay and AirPlay routes, so an HDMI route + /// is expected to report `notApplicable`; callers must treat that as + /// "unknown", never as "not Dolby". + private static func audioRenderingMode() -> [String: Any] { + var out: [String: Any] = [:] + let session = AVAudioSession.sharedInstance() + out["maxOutputChannels"] = session.maximumOutputNumberOfChannels + out["outputChannels"] = session.outputNumberOfChannels + out["route"] = session.currentRoute.outputs.first?.portType.rawValue ?? "none" + if #available(tvOS 17.2, iOS 17.2, *) { + let mode = session.renderingMode + out["rawValue"] = mode.rawValue + out["name"] = + switch mode { + case .notApplicable: "notApplicable" + case .monoStereo: "monoStereo" + case .surround: "surround" + case .spatialAudio: "spatialAudio" + case .dolbyAudio: "dolbyAudio" + case .dolbyAtmos: "dolbyAtmos" + @unknown default: "unknown" + } + } else { + out["rawValue"] = 0 + out["name"] = "unavailable" + } + return out + } + // MARK: - PiP private func ensurePipController() -> MpvPipController? { diff --git a/lib/i18n/bg.i18n.json b/lib/i18n/bg.i18n.json index 4ecc9ecd..9c79ad5e 100644 --- a/lib/i18n/bg.i18n.json +++ b/lib/i18n/bg.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Стриймва тестовия файл точно както Atmos възпроизвеждането в плейъра. Изисква URL на тестовия файл.", "atmosTestRawFile": "Суров EAC3 файл", "atmosTestRawFileDescription": "Възпроизвежда тестовия файл с известна дължина. Изисква URL на тестовия файл.", + "atmosTestAsbarNative": "Рендер със семпъл буфер (native)", + "atmosTestAsbarNativeDescription": "Подава несменения компресиран звук от файла директно към системния рендер. Изисква URL на тестовия файл.", + "atmosTestAsbarGenerated": "Рендер със семпъл буфер (възстановен)", + "atmosTestAsbarGeneratedDescription": "Същото, но с аудиоописание, изградено както при възпроизвеждане. Изисква URL на тестовия файл.", + "atmosTestSessionMode": "Използвай режим за възпроизвеждане на филми", + "atmosTestSessionModeDescription": "Изключено използва режима, документиран от Dolby. Включено използва предишния режим.", + "atmosTestShowRoutePicker": "Избери AirPlay изход", + "atmosTestHideRoutePicker": "Скрий избора на AirPlay изход", + "atmosTestRoutePickerDescription": "Изпраща теста към AirPlay приемник. Само AirPlay съобщава разрешения аудиорежим.", "atmosTestStop": "Спри теста", "atmosTestUrl": "URL на тестовия файл", "atmosTestUrlDescription": "HTTP URL на суров .ec3 Dolby Atmos файл (напр. извлечен с ffmpeg)", @@ -1347,6 +1356,11 @@ "audioOutput": "Аудио изход", "performanceOverlay": "Оверлей за производителност", "audioPassthrough": "Директно предаване на аудио", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Съраунд", + "audioOutputSpatial": "Пространствено аудио", + "audioOutputStereo": "Стерео", "audioNormalization": "Нормализиране на силата на звука", "audioDownmix": "Смесване до стерео" }, diff --git a/lib/i18n/da.i18n.json b/lib/i18n/da.i18n.json index cca6c66f..e402a96b 100644 --- a/lib/i18n/da.i18n.json +++ b/lib/i18n/da.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Streamer testfilen præcis som Atmos-afspilning i afspilleren. Kræver testfilens URL.", "atmosTestRawFile": "Rå EAC3-fil", "atmosTestRawFileDescription": "Afspiller testfilen med kendt længde. Kræver testfilens URL.", + "atmosTestAsbarNative": "Sample-buffer-renderer (native)", + "atmosTestAsbarNativeDescription": "Sender filens urørte komprimerede lyd direkte til systemets renderer. Kræver testfilens URL.", + "atmosTestAsbarGenerated": "Sample-buffer-renderer (genopbygget)", + "atmosTestAsbarGeneratedDescription": "Det samme, men med lydbeskrivelsen opbygget som ved afspilning. Kræver testfilens URL.", + "atmosTestSessionMode": "Brug filmafspilningstilstand", + "atmosTestSessionModeDescription": "Fra bruger den tilstand, Dolby dokumenterer. Til bruger den tidligere tilstand.", + "atmosTestShowRoutePicker": "Vælg AirPlay-udgang", + "atmosTestHideRoutePicker": "Skjul AirPlay-udgangsvælger", + "atmosTestRoutePickerDescription": "Sender testen til en AirPlay-modtager. Kun AirPlay rapporterer den valgte lydtilstand.", "atmosTestStop": "Stop test", "atmosTestUrl": "Testfilens URL", "atmosTestUrlDescription": "HTTP-URL til en rå .ec3 Dolby Atmos-fil (f.eks. udtrukket med ffmpeg)", @@ -1347,6 +1356,11 @@ "audioOutput": "Lydoutput", "performanceOverlay": "Ydelsesoverlay", "audioPassthrough": "Lyd-passthrough", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Surround", + "audioOutputSpatial": "Rumlig lyd", + "audioOutputStereo": "Stereo", "audioNormalization": "Normalisér lydstyrke", "audioDownmix": "Downmix til stereo" }, diff --git a/lib/i18n/de.i18n.json b/lib/i18n/de.i18n.json index 8934a362..c09075ca 100644 --- a/lib/i18n/de.i18n.json +++ b/lib/i18n/de.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Streamt die Testdatei genau wie die Atmos-Wiedergabe im Player. Benötigt die URL der Testdatei.", "atmosTestRawFile": "Rohe EAC3-Datei", "atmosTestRawFileDescription": "Spielt die Testdatei mit bekannter Länge ab. Benötigt die URL der Testdatei.", + "atmosTestAsbarNative": "Sample-Buffer-Renderer (nativ)", + "atmosTestAsbarNativeDescription": "Übergibt die unveränderte komprimierte Audiospur direkt an den System-Renderer. Benötigt die URL der Testdatei.", + "atmosTestAsbarGenerated": "Sample-Buffer-Renderer (neu erstellt)", + "atmosTestAsbarGeneratedDescription": "Dasselbe, aber mit der Audiobeschreibung wie bei der Wiedergabe erstellt. Benötigt die URL der Testdatei.", + "atmosTestSessionMode": "Filmwiedergabe-Modus verwenden", + "atmosTestSessionModeDescription": "Aus verwendet den von Dolby dokumentierten Modus. Ein verwendet den bisherigen Modus.", + "atmosTestShowRoutePicker": "AirPlay-Ausgabe wählen", + "atmosTestHideRoutePicker": "AirPlay-Auswahl ausblenden", + "atmosTestRoutePickerDescription": "Sendet den Test an einen AirPlay-Empfänger. Nur AirPlay meldet den ermittelten Audiomodus.", "atmosTestStop": "Test stoppen", "atmosTestUrl": "URL der Testdatei", "atmosTestUrlDescription": "HTTP-URL einer rohen .ec3-Dolby-Atmos-Datei (z. B. mit ffmpeg extrahiert)", @@ -1347,6 +1356,11 @@ "audioOutput": "Audioausgabe", "performanceOverlay": "Leistungsanzeige", "audioPassthrough": "Audio-Durchleitung", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Surround", + "audioOutputSpatial": "Räumliches Audio", + "audioOutputStereo": "Stereo", "audioNormalization": "Lautstärke normalisieren", "audioDownmix": "Downmix auf Stereo" }, diff --git a/lib/i18n/en.i18n.json b/lib/i18n/en.i18n.json index 2d48ad84..8c894733 100644 --- a/lib/i18n/en.i18n.json +++ b/lib/i18n/en.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Streams the test file exactly like in-player Atmos playback. Needs the test file URL.", "atmosTestRawFile": "Raw EAC3 file", "atmosTestRawFileDescription": "Plays the test file with a known length. Needs the test file URL.", + "atmosTestAsbarNative": "Sample-buffer renderer (native)", + "atmosTestAsbarNativeDescription": "Feeds the file's untouched compressed audio straight to the system renderer. Needs the test file URL.", + "atmosTestAsbarGenerated": "Sample-buffer renderer (rebuilt)", + "atmosTestAsbarGeneratedDescription": "Same, but with the audio description rebuilt the way playback builds it. Needs the test file URL.", + "atmosTestSessionMode": "Use movie playback session mode", + "atmosTestSessionModeDescription": "Off uses the mode Dolby documents. On uses the mode playback used previously.", + "atmosTestShowRoutePicker": "Choose AirPlay output", + "atmosTestHideRoutePicker": "Hide AirPlay output picker", + "atmosTestRoutePickerDescription": "Send the test to an AirPlay receiver. Only AirPlay reports the resolved audio mode.", "atmosTestStop": "Stop test", "atmosTestUrl": "Test file URL", "atmosTestUrlDescription": "HTTP URL of a raw .ec3 Dolby Atmos file (e.g. extracted with ffmpeg)", @@ -1347,6 +1356,11 @@ "audioOutput": "Audio Output", "performanceOverlay": "Performance Overlay", "audioPassthrough": "Audio Passthrough", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Surround", + "audioOutputSpatial": "Spatial Audio", + "audioOutputStereo": "Stereo", "audioNormalization": "Normalize Loudness", "audioDownmix": "Downmix to Stereo" }, diff --git a/lib/i18n/es.i18n.json b/lib/i18n/es.i18n.json index 3273139f..e80a1434 100644 --- a/lib/i18n/es.i18n.json +++ b/lib/i18n/es.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Transmite el archivo de prueba igual que durante la reproducción de Atmos. Requiere la URL del archivo de prueba.", "atmosTestRawFile": "Archivo EAC3 sin procesar", "atmosTestRawFileDescription": "Reproduce el archivo de prueba con longitud conocida. Necesita la URL del archivo de prueba.", + "atmosTestAsbarNative": "Renderizador de búfer de muestras (nativo)", + "atmosTestAsbarNativeDescription": "Envía el audio comprimido intacto del archivo directamente al renderizador del sistema. Necesita la URL del archivo de prueba.", + "atmosTestAsbarGenerated": "Renderizador de búfer de muestras (reconstruido)", + "atmosTestAsbarGeneratedDescription": "Igual, pero con la descripción de audio construida como en la reproducción. Necesita la URL del archivo de prueba.", + "atmosTestSessionMode": "Usar modo de reproducción de películas", + "atmosTestSessionModeDescription": "Desactivado usa el modo que documenta Dolby. Activado usa el modo anterior.", + "atmosTestShowRoutePicker": "Elegir salida AirPlay", + "atmosTestHideRoutePicker": "Ocultar selector de salida AirPlay", + "atmosTestRoutePickerDescription": "Envía la prueba a un receptor AirPlay. Solo AirPlay informa del modo de audio resuelto.", "atmosTestStop": "Detener prueba", "atmosTestUrl": "URL del archivo de prueba", "atmosTestUrlDescription": "URL HTTP de un archivo .ec3 Dolby Atmos sin procesar (p. ej., extraído con ffmpeg)", @@ -1347,6 +1356,11 @@ "audioOutput": "Salida de audio", "performanceOverlay": "Indicador de rendimiento", "audioPassthrough": "Transferencia directa de audio", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Envolvente", + "audioOutputSpatial": "Audio espacial", + "audioOutputStereo": "Estéreo", "audioNormalization": "Normalizar volumen", "audioDownmix": "Mezclar a estéreo" }, diff --git a/lib/i18n/fr.i18n.json b/lib/i18n/fr.i18n.json index 61b000e2..204dd8ca 100644 --- a/lib/i18n/fr.i18n.json +++ b/lib/i18n/fr.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Diffuse le fichier de test exactement comme la lecture Atmos du lecteur. Nécessite l'URL du fichier de test.", "atmosTestRawFile": "Fichier EAC3 brut", "atmosTestRawFileDescription": "Lit le fichier de test avec une longueur connue. Nécessite l'URL du fichier de test.", + "atmosTestAsbarNative": "Moteur de rendu à tampon d'échantillons (natif)", + "atmosTestAsbarNativeDescription": "Transmet l'audio compressé intact du fichier directement au moteur de rendu du système. Nécessite l'URL du fichier de test.", + "atmosTestAsbarGenerated": "Moteur de rendu à tampon d'échantillons (reconstruit)", + "atmosTestAsbarGeneratedDescription": "Identique, mais avec la description audio reconstruite comme à la lecture. Nécessite l'URL du fichier de test.", + "atmosTestSessionMode": "Utiliser le mode lecture de films", + "atmosTestSessionModeDescription": "Désactivé utilise le mode documenté par Dolby. Activé utilise le mode précédent.", + "atmosTestShowRoutePicker": "Choisir la sortie AirPlay", + "atmosTestHideRoutePicker": "Masquer le sélecteur AirPlay", + "atmosTestRoutePickerDescription": "Envoie le test vers un récepteur AirPlay. Seul AirPlay indique le mode audio retenu.", "atmosTestStop": "Arrêter le test", "atmosTestUrl": "URL du fichier de test", "atmosTestUrlDescription": "URL HTTP d'un fichier .ec3 Dolby Atmos brut (extrait par ex. avec ffmpeg)", @@ -1347,6 +1356,11 @@ "audioOutput": "Sortie audio", "performanceOverlay": "Données de performance", "audioPassthrough": "Transmission audio directe", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Surround", + "audioOutputSpatial": "Audio spatial", + "audioOutputStereo": "Stéréo", "audioNormalization": "Normaliser le volume", "audioDownmix": "Conversion en stéréo" }, diff --git a/lib/i18n/hu.i18n.json b/lib/i18n/hu.i18n.json index 0a811752..fac6a6c5 100644 --- a/lib/i18n/hu.i18n.json +++ b/lib/i18n/hu.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "A tesztfájlt pontosan úgy közvetíti, mint a lejátszón belüli Atmos lejátszás. Szükséges a tesztfájl URL-je.", "atmosTestRawFile": "Nyers EAC3 fájl", "atmosTestRawFileDescription": "Ismert hosszúságú tesztfájlt játszik le. Szükséges a tesztfájl URL-je.", + "atmosTestAsbarNative": "Mintapuffer-megjelenítő (natív)", + "atmosTestAsbarNativeDescription": "A fájl érintetlen tömörített hangját közvetlenül a rendszer megjelenítőjének adja. Szükséges a tesztfájl URL-je.", + "atmosTestAsbarGenerated": "Mintapuffer-megjelenítő (újraépített)", + "atmosTestAsbarGeneratedDescription": "Ugyanaz, de a lejátszás módján felépített hangleírással. Szükséges a tesztfájl URL-je.", + "atmosTestSessionMode": "Filmlejátszási mód használata", + "atmosTestSessionModeDescription": "Kikapcsolva a Dolby által dokumentált módot használja. Bekapcsolva a korábbi módot.", + "atmosTestShowRoutePicker": "AirPlay kimenet választása", + "atmosTestHideRoutePicker": "AirPlay kimenetválasztó elrejtése", + "atmosTestRoutePickerDescription": "Elküldi a tesztet egy AirPlay vevőnek. Csak az AirPlay jelzi a feloldott hangmódot.", "atmosTestStop": "Teszt leállítása", "atmosTestUrl": "Tesztfájl URL-je", "atmosTestUrlDescription": "Nyers .ec3 Dolby Atmos fájl HTTP URL-je (pl. ffmpeg-gel kinyerve)", @@ -1347,6 +1356,11 @@ "audioOutput": "Hangkimenet", "performanceOverlay": "Teljesítményadatok", "audioPassthrough": "Hangtovábbítás (passthrough)", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Térhatású", + "audioOutputSpatial": "Térbeli hang", + "audioOutputStereo": "Sztereó", "audioNormalization": "Hangerő normalizálása", "audioDownmix": "Lekeverés sztereóra" }, diff --git a/lib/i18n/it.i18n.json b/lib/i18n/it.i18n.json index 82f7dcd4..29810934 100644 --- a/lib/i18n/it.i18n.json +++ b/lib/i18n/it.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Trasmette il file di prova esattamente come la riproduzione Atmos del lettore. Richiede l'URL del file di prova.", "atmosTestRawFile": "File EAC3 grezzo", "atmosTestRawFileDescription": "Riproduce il file di prova con lunghezza nota. Richiede l'URL del file di prova.", + "atmosTestAsbarNative": "Renderer con buffer di campioni (nativo)", + "atmosTestAsbarNativeDescription": "Invia l'audio compresso intatto del file direttamente al renderer di sistema. Richiede l'URL del file di test.", + "atmosTestAsbarGenerated": "Renderer con buffer di campioni (ricostruito)", + "atmosTestAsbarGeneratedDescription": "Come sopra, ma con la descrizione audio costruita come nella riproduzione. Richiede l'URL del file di test.", + "atmosTestSessionMode": "Usa la modalità riproduzione film", + "atmosTestSessionModeDescription": "Disattivato usa la modalità documentata da Dolby. Attivato usa la modalità precedente.", + "atmosTestShowRoutePicker": "Scegli uscita AirPlay", + "atmosTestHideRoutePicker": "Nascondi selettore uscita AirPlay", + "atmosTestRoutePickerDescription": "Invia il test a un ricevitore AirPlay. Solo AirPlay riporta la modalità audio risolta.", "atmosTestStop": "Interrompi test", "atmosTestUrl": "URL del file di prova", "atmosTestUrlDescription": "URL HTTP di un file .ec3 Dolby Atmos grezzo (ad es. estratto con ffmpeg)", @@ -1347,6 +1356,11 @@ "audioOutput": "Uscita audio", "performanceOverlay": "Overlay prestazioni", "audioPassthrough": "Passthrough audio", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Surround", + "audioOutputSpatial": "Audio spaziale", + "audioOutputStereo": "Stereo", "audioNormalization": "Normalizza il volume", "audioDownmix": "Downmix in stereo" }, diff --git a/lib/i18n/ja.i18n.json b/lib/i18n/ja.i18n.json index 2bd5f60e..8b125730 100644 --- a/lib/i18n/ja.i18n.json +++ b/lib/i18n/ja.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "プレイヤー内のAtmos再生と同じ方式でテストファイルをストリーミングします。テストファイルのURLが必要です。", "atmosTestRawFile": "生EAC3ファイル", "atmosTestRawFileDescription": "長さが既知のテストファイルを再生します。テストファイルのURLが必要です。", + "atmosTestAsbarNative": "サンプルバッファレンダラー(ネイティブ)", + "atmosTestAsbarNativeDescription": "ファイルの圧縮音声をそのままシステムのレンダラーに渡します。テストファイルのURLが必要です。", + "atmosTestAsbarGenerated": "サンプルバッファレンダラー(再構築)", + "atmosTestAsbarGeneratedDescription": "同じですが、再生時と同じ方法で音声記述を再構築します。テストファイルのURLが必要です。", + "atmosTestSessionMode": "ムービー再生モードを使用", + "atmosTestSessionModeDescription": "オフはDolbyが文書化したモードを使用します。オンは以前のモードを使用します。", + "atmosTestShowRoutePicker": "AirPlay出力を選択", + "atmosTestHideRoutePicker": "AirPlay出力の選択を隠す", + "atmosTestRoutePickerDescription": "テストをAirPlayレシーバーに送信します。解決された音声モードを報告するのはAirPlayのみです。", "atmosTestStop": "テストを停止", "atmosTestUrl": "テストファイルのURL", "atmosTestUrlDescription": "生の.ec3 Dolby AtmosファイルのHTTP URL(例: ffmpegで抽出)", @@ -1344,6 +1353,11 @@ "audioOutput": "音声出力", "performanceOverlay": "パフォーマンスオーバーレイ", "audioPassthrough": "オーディオパススルー", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "サラウンド", + "audioOutputSpatial": "空間オーディオ", + "audioOutputStereo": "ステレオ", "audioNormalization": "ラウドネス正規化", "audioDownmix": "ステレオにダウンミックス" }, diff --git a/lib/i18n/ko.i18n.json b/lib/i18n/ko.i18n.json index 45e42e20..ba098323 100644 --- a/lib/i18n/ko.i18n.json +++ b/lib/i18n/ko.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "플레이어 내 Atmos 재생과 동일한 방식으로 테스트 파일을 스트리밍합니다. 테스트 파일 URL이 필요합니다.", "atmosTestRawFile": "원시 EAC3 파일", "atmosTestRawFileDescription": "길이가 알려진 테스트 파일을 재생합니다. 테스트 파일 URL이 필요합니다.", + "atmosTestAsbarNative": "샘플 버퍼 렌더러(네이티브)", + "atmosTestAsbarNativeDescription": "파일의 압축 오디오를 그대로 시스템 렌더러에 전달합니다. 테스트 파일 URL이 필요합니다.", + "atmosTestAsbarGenerated": "샘플 버퍼 렌더러(재구성)", + "atmosTestAsbarGeneratedDescription": "동일하지만 오디오 설명을 재생과 같은 방식으로 재구성합니다. 테스트 파일 URL이 필요합니다.", + "atmosTestSessionMode": "동영상 재생 세션 모드 사용", + "atmosTestSessionModeDescription": "끄면 Dolby가 문서화한 모드를 사용합니다. 켜면 이전 모드를 사용합니다.", + "atmosTestShowRoutePicker": "AirPlay 출력 선택", + "atmosTestHideRoutePicker": "AirPlay 출력 선택기 숨기기", + "atmosTestRoutePickerDescription": "테스트를 AirPlay 수신기로 보냅니다. 확인된 오디오 모드는 AirPlay에서만 보고됩니다.", "atmosTestStop": "테스트 중지", "atmosTestUrl": "테스트 파일 URL", "atmosTestUrlDescription": "원시 .ec3 Dolby Atmos 파일의 HTTP URL(예: ffmpeg로 추출)", @@ -1344,6 +1353,11 @@ "audioOutput": "오디오 출력", "performanceOverlay": "성능 오버레이", "audioPassthrough": "오디오 패스스루", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "서라운드", + "audioOutputSpatial": "공간 음향", + "audioOutputStereo": "스테레오", "audioNormalization": "음량 정규화", "audioDownmix": "스테레오로 다운믹스" }, diff --git a/lib/i18n/nb.i18n.json b/lib/i18n/nb.i18n.json index 465742f9..03cecb37 100644 --- a/lib/i18n/nb.i18n.json +++ b/lib/i18n/nb.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Strømmer testfilen akkurat som Atmos-avspilling i spilleren. Krever testfilens URL.", "atmosTestRawFile": "Rå EAC3-fil", "atmosTestRawFileDescription": "Spiller av testfilen med kjent lengde. Krever testfilens URL.", + "atmosTestAsbarNative": "Sample-buffer-renderer (nativ)", + "atmosTestAsbarNativeDescription": "Sender filens urørte komprimerte lyd rett til systemets renderer. Krever URL til testfilen.", + "atmosTestAsbarGenerated": "Sample-buffer-renderer (gjenoppbygd)", + "atmosTestAsbarGeneratedDescription": "Det samme, men med lydbeskrivelsen bygd slik avspilling bygger den. Krever URL til testfilen.", + "atmosTestSessionMode": "Bruk filmavspillingsmodus", + "atmosTestSessionModeDescription": "Av bruker modusen Dolby dokumenterer. På bruker den tidligere modusen.", + "atmosTestShowRoutePicker": "Velg AirPlay-utgang", + "atmosTestHideRoutePicker": "Skjul AirPlay-utgangsvelger", + "atmosTestRoutePickerDescription": "Sender testen til en AirPlay-mottaker. Bare AirPlay rapporterer den valgte lydmodusen.", "atmosTestStop": "Stopp test", "atmosTestUrl": "Testfilens URL", "atmosTestUrlDescription": "HTTP-URL til en rå .ec3 Dolby Atmos-fil (f.eks. hentet ut med ffmpeg)", @@ -1347,6 +1356,11 @@ "audioOutput": "Lydutgang", "performanceOverlay": "Ytelsesoverlegg", "audioPassthrough": "Direkte lydutgang", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Surround", + "audioOutputSpatial": "Romlig lyd", + "audioOutputStereo": "Stereo", "audioNormalization": "Normaliser lydstyrke", "audioDownmix": "Nedmiks til stereo" }, diff --git a/lib/i18n/nl.i18n.json b/lib/i18n/nl.i18n.json index 570207bf..4776af92 100644 --- a/lib/i18n/nl.i18n.json +++ b/lib/i18n/nl.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Streamt het testbestand precies zoals Atmos-weergave in de speler. Vereist de URL van het testbestand.", "atmosTestRawFile": "Ruw EAC3-bestand", "atmosTestRawFileDescription": "Speelt het testbestand met bekende lengte af. Vereist de URL van het testbestand.", + "atmosTestAsbarNative": "Sample-bufferrenderer (native)", + "atmosTestAsbarNativeDescription": "Stuurt de ongewijzigde gecomprimeerde audio van het bestand rechtstreeks naar de systeemrenderer. Vereist de URL van het testbestand.", + "atmosTestAsbarGenerated": "Sample-bufferrenderer (opnieuw opgebouwd)", + "atmosTestAsbarGeneratedDescription": "Hetzelfde, maar met de audiobeschrijving opgebouwd zoals bij afspelen. Vereist de URL van het testbestand.", + "atmosTestSessionMode": "Filmafspeelmodus gebruiken", + "atmosTestSessionModeDescription": "Uit gebruikt de modus die Dolby documenteert. Aan gebruikt de vorige modus.", + "atmosTestShowRoutePicker": "AirPlay-uitvoer kiezen", + "atmosTestHideRoutePicker": "AirPlay-uitvoerkiezer verbergen", + "atmosTestRoutePickerDescription": "Stuurt de test naar een AirPlay-ontvanger. Alleen AirPlay meldt de bepaalde audiomodus.", "atmosTestStop": "Test stoppen", "atmosTestUrl": "URL van testbestand", "atmosTestUrlDescription": "HTTP-URL van een ruw .ec3 Dolby Atmos-bestand (bijv. uitgepakt met ffmpeg)", @@ -1347,6 +1356,11 @@ "audioOutput": "Audio-uitvoer", "performanceOverlay": "Prestatie-overlay", "audioPassthrough": "Audio-doorvoer", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Surround", + "audioOutputSpatial": "Ruimtelijke audio", + "audioOutputStereo": "Stereo", "audioNormalization": "Volume normaliseren", "audioDownmix": "Downmixen naar stereo" }, diff --git a/lib/i18n/pl.i18n.json b/lib/i18n/pl.i18n.json index e8d9061c..f1cb2134 100644 --- a/lib/i18n/pl.i18n.json +++ b/lib/i18n/pl.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Przesyła strumieniowo plik testowy dokładnie tak jak podczas odtwarzania Atmos w odtwarzaczu. Wymaga adresu URL pliku testowego.", "atmosTestRawFile": "Surowy plik EAC3", "atmosTestRawFileDescription": "Odtwarza plik testowy o znanej długości. Wymaga URL pliku testowego.", + "atmosTestAsbarNative": "Renderer bufora próbek (natywny)", + "atmosTestAsbarNativeDescription": "Przekazuje nienaruszony skompresowany dźwięk pliku prosto do renderera systemu. Wymaga URL pliku testowego.", + "atmosTestAsbarGenerated": "Renderer bufora próbek (odtworzony)", + "atmosTestAsbarGeneratedDescription": "To samo, ale z opisem dźwięku budowanym tak jak przy odtwarzaniu. Wymaga URL pliku testowego.", + "atmosTestSessionMode": "Użyj trybu odtwarzania filmów", + "atmosTestSessionModeDescription": "Wyłączone używa trybu udokumentowanego przez Dolby. Włączone używa poprzedniego trybu.", + "atmosTestShowRoutePicker": "Wybierz wyjście AirPlay", + "atmosTestHideRoutePicker": "Ukryj wybór wyjścia AirPlay", + "atmosTestRoutePickerDescription": "Wysyła test do odbiornika AirPlay. Tylko AirPlay zgłasza ustalony tryb dźwięku.", "atmosTestStop": "Zatrzymaj test", "atmosTestUrl": "Adres URL pliku testowego", "atmosTestUrlDescription": "Adres URL HTTP surowego pliku Dolby Atmos w formacie .ec3 (np. wyodrębnionego za pomocą ffmpeg)", @@ -1353,6 +1362,11 @@ "audioOutput": "Wyjście audio", "performanceOverlay": "Nakładka wydajności", "audioPassthrough": "Przekazywanie dźwięku", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Przestrzenny", + "audioOutputSpatial": "Dźwięk przestrzenny", + "audioOutputStereo": "Stereo", "audioNormalization": "Normalizacja głośności", "audioDownmix": "Miksowanie do stereo" }, diff --git a/lib/i18n/pt.i18n.json b/lib/i18n/pt.i18n.json index 03384064..3a92f14e 100644 --- a/lib/i18n/pt.i18n.json +++ b/lib/i18n/pt.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Transmite o arquivo de teste exatamente como na reprodução Atmos pelo reprodutor. Requer a URL do arquivo de teste.", "atmosTestRawFile": "Arquivo EAC3 bruto", "atmosTestRawFileDescription": "Reproduz o arquivo de teste com duração conhecida. Requer a URL do arquivo de teste.", + "atmosTestAsbarNative": "Renderizador de buffer de amostras (nativo)", + "atmosTestAsbarNativeDescription": "Envia o áudio comprimido intacto do ficheiro diretamente para o renderizador do sistema. Requer o URL do ficheiro de teste.", + "atmosTestAsbarGenerated": "Renderizador de buffer de amostras (reconstruído)", + "atmosTestAsbarGeneratedDescription": "O mesmo, mas com a descrição de áudio construída como na reprodução. Requer o URL do ficheiro de teste.", + "atmosTestSessionMode": "Usar modo de reprodução de filmes", + "atmosTestSessionModeDescription": "Desativado usa o modo documentado pela Dolby. Ativado usa o modo anterior.", + "atmosTestShowRoutePicker": "Escolher saída AirPlay", + "atmosTestHideRoutePicker": "Ocultar seletor de saída AirPlay", + "atmosTestRoutePickerDescription": "Envia o teste para um recetor AirPlay. Só o AirPlay comunica o modo de áudio resolvido.", "atmosTestStop": "Parar teste", "atmosTestUrl": "URL do arquivo de teste", "atmosTestUrlDescription": "URL HTTP de um arquivo .ec3 Dolby Atmos bruto (ex.: extraído com ffmpeg)", @@ -1347,6 +1356,11 @@ "audioOutput": "Saída de áudio", "performanceOverlay": "Painel de desempenho", "audioPassthrough": "Passagem direta de áudio", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Surround", + "audioOutputSpatial": "Áudio espacial", + "audioOutputStereo": "Estéreo", "audioNormalization": "Normalizar intensidade sonora", "audioDownmix": "Conversão para estéreo" }, diff --git a/lib/i18n/ru.i18n.json b/lib/i18n/ru.i18n.json index 9c428559..b50e3011 100644 --- a/lib/i18n/ru.i18n.json +++ b/lib/i18n/ru.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Транслирует тестовый файл точно так же, как Atmos-воспроизведение в проигрывателе. Требуется URL тестового файла.", "atmosTestRawFile": "Сырой файл EAC3", "atmosTestRawFileDescription": "Воспроизводит тестовый файл с известной длиной. Требуется URL тестового файла.", + "atmosTestAsbarNative": "Рендерер сэмпл-буфера (нативный)", + "atmosTestAsbarNativeDescription": "Передаёт неизменённый сжатый звук файла прямо в системный рендерер. Требуется URL тестового файла.", + "atmosTestAsbarGenerated": "Рендерер сэмпл-буфера (пересобранный)", + "atmosTestAsbarGeneratedDescription": "То же, но с описанием звука, собранным как при воспроизведении. Требуется URL тестового файла.", + "atmosTestSessionMode": "Использовать режим воспроизведения фильмов", + "atmosTestSessionModeDescription": "Выключено — режим, описанный Dolby. Включено — прежний режим.", + "atmosTestShowRoutePicker": "Выбрать выход AirPlay", + "atmosTestHideRoutePicker": "Скрыть выбор выхода AirPlay", + "atmosTestRoutePickerDescription": "Отправляет тест на приёмник AirPlay. Только AirPlay сообщает определённый режим звука.", "atmosTestStop": "Остановить тест", "atmosTestUrl": "URL тестового файла", "atmosTestUrlDescription": "HTTP-URL сырого файла .ec3 Dolby Atmos (например, извлечённого через ffmpeg)", @@ -1353,6 +1362,11 @@ "audioOutput": "Аудиовыход", "performanceOverlay": "Оверлей производительности", "audioPassthrough": "Сквозной вывод аудио", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Объёмный звук", + "audioOutputSpatial": "Пространственное аудио", + "audioOutputStereo": "Стерео", "audioNormalization": "Нормализация громкости", "audioDownmix": "Микширование в стерео" }, diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index bde60d3e..466f8070 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,7 +4,7 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 18 -/// Strings: 26507 (1472 per locale) +/// Strings: 26759 (1486 per locale) // coverage:ignore-file // ignore_for_file: type=lint, unused_import diff --git a/lib/i18n/strings_bg.g.dart b/lib/i18n/strings_bg.g.dart index 213684e8..8f8339d9 100644 --- a/lib/i18n/strings_bg.g.dart +++ b/lib/i18n/strings_bg.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$bg extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Стриймва тестовия файл точно както Atmos възпроизвеждането в плейъра. Изисква URL на тестовия файл.'; @override String get atmosTestRawFile => 'Суров EAC3 файл'; @override String get atmosTestRawFileDescription => 'Възпроизвежда тестовия файл с известна дължина. Изисква URL на тестовия файл.'; + @override String get atmosTestAsbarNative => 'Рендер със семпъл буфер (native)'; + @override String get atmosTestAsbarNativeDescription => 'Подава несменения компресиран звук от файла директно към системния рендер. Изисква URL на тестовия файл.'; + @override String get atmosTestAsbarGenerated => 'Рендер със семпъл буфер (възстановен)'; + @override String get atmosTestAsbarGeneratedDescription => 'Същото, но с аудиоописание, изградено както при възпроизвеждане. Изисква URL на тестовия файл.'; + @override String get atmosTestSessionMode => 'Използвай режим за възпроизвеждане на филми'; + @override String get atmosTestSessionModeDescription => 'Изключено използва режима, документиран от Dolby. Включено използва предишния режим.'; + @override String get atmosTestShowRoutePicker => 'Избери AirPlay изход'; + @override String get atmosTestHideRoutePicker => 'Скрий избора на AirPlay изход'; + @override String get atmosTestRoutePickerDescription => 'Изпраща теста към AirPlay приемник. Само AirPlay съобщава разрешения аудиорежим.'; @override String get atmosTestStop => 'Спри теста'; @override String get atmosTestUrl => 'URL на тестовия файл'; @override String get atmosTestUrlDescription => 'HTTP URL на суров .ec3 Dolby Atmos файл (напр. извлечен с ffmpeg)'; @@ -1514,6 +1523,11 @@ class _Translations$videoSettings$bg extends Translations$videoSettings$en { @override String get audioOutput => 'Аудио изход'; @override String get performanceOverlay => 'Оверлей за производителност'; @override String get audioPassthrough => 'Директно предаване на аудио'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Съраунд'; + @override String get audioOutputSpatial => 'Пространствено аудио'; + @override String get audioOutputStereo => 'Стерео'; @override String get audioNormalization => 'Нормализиране на силата на звука'; @override String get audioDownmix => 'Смесване до стерео'; } @@ -2463,6 +2477,15 @@ extension on TranslationsBg { 'settings.atmosTestRawStreamDescription' => 'Стриймва тестовия файл точно както Atmos възпроизвеждането в плейъра. Изисква URL на тестовия файл.', 'settings.atmosTestRawFile' => 'Суров EAC3 файл', 'settings.atmosTestRawFileDescription' => 'Възпроизвежда тестовия файл с известна дължина. Изисква URL на тестовия файл.', + 'settings.atmosTestAsbarNative' => 'Рендер със семпъл буфер (native)', + 'settings.atmosTestAsbarNativeDescription' => 'Подава несменения компресиран звук от файла директно към системния рендер. Изисква URL на тестовия файл.', + 'settings.atmosTestAsbarGenerated' => 'Рендер със семпъл буфер (възстановен)', + 'settings.atmosTestAsbarGeneratedDescription' => 'Същото, но с аудиоописание, изградено както при възпроизвеждане. Изисква URL на тестовия файл.', + 'settings.atmosTestSessionMode' => 'Използвай режим за възпроизвеждане на филми', + 'settings.atmosTestSessionModeDescription' => 'Изключено използва режима, документиран от Dolby. Включено използва предишния режим.', + 'settings.atmosTestShowRoutePicker' => 'Избери AirPlay изход', + 'settings.atmosTestHideRoutePicker' => 'Скрий избора на AirPlay изход', + 'settings.atmosTestRoutePickerDescription' => 'Изпраща теста към AirPlay приемник. Само AirPlay съобщава разрешения аудиорежим.', 'settings.atmosTestStop' => 'Спри теста', 'settings.atmosTestUrl' => 'URL на тестовия файл', 'settings.atmosTestUrlDescription' => 'HTTP URL на суров .ec3 Dolby Atmos файл (напр. извлечен с ffmpeg)', @@ -2690,6 +2713,8 @@ extension on TranslationsBg { 'videoControls.language' => 'Език', 'videoControls.noSubtitlesFound' => 'Не са намерени субтитри', 'videoControls.noSubtitlesAvailable' => 'Няма налични субтитри', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Няма налични аудиопътечки', 'videoControls.noTracksAvailable' => 'Няма налични пътечки', 'videoControls.subtitleDownloaded' => 'Субтитърът е изтеглен', @@ -2699,8 +2724,6 @@ extension on TranslationsBg { 'messages.markedAsWatched' => 'Маркирано като гледано', 'messages.markedAsUnwatched' => 'Маркирано като негледано', 'messages.markedAsWatchedOffline' => 'Маркирано като гледано (ще се синхронизира, когато сте онлайн)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Маркирано като негледано (ще се синхронизира, когато сте онлайн)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Автоматично премахнато: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('bg'))(n, one: 'Автоматично премахнато ${n} гледано изтегляне', other: 'Автоматично премахнати ${n} гледани изтегляния', ), @@ -3204,6 +3227,8 @@ extension on TranslationsBg { 'watchTogether.codeMustBe5Chars' => 'Кодът на сесията трябва да е 5 символа', 'watchTogether.joinInstructions' => 'Въведете кода на сесията от организатора, за да се присъедините.', 'watchTogether.failedToCreate' => 'Неуспешно създаване на сесия', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Неуспешно присъединяване към сесия', 'watchTogether.sessionCodeCopied' => 'Кодът на сесията е копиран в клипборда', 'watchTogether.relayUnreachable' => 'Релейният сървър е недостъпен. Възможно е интернет доставчикът да блокира гледането заедно.', @@ -3213,8 +3238,6 @@ extension on TranslationsBg { 'watchTogether.joinCurrentPlaybackDescription' => 'Върнете се към това, което организаторът гледа в момента', 'watchTogether.failedToOpenCurrentPlayback' => 'Неуспешно отваряне на текущото възпроизвеждане', 'watchTogether.participantJoined' => ({required Object name}) => '${name} се присъедини', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} напусна', 'watchTogether.participantPaused' => ({required Object name}) => '${name} постави на пауза', 'watchTogether.participantResumed' => ({required Object name}) => '${name} продължи', @@ -3413,6 +3436,11 @@ extension on TranslationsBg { 'videoSettings.audioOutput' => 'Аудио изход', 'videoSettings.performanceOverlay' => 'Оверлей за производителност', 'videoSettings.audioPassthrough' => 'Директно предаване на аудио', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Съраунд', + 'videoSettings.audioOutputSpatial' => 'Пространствено аудио', + 'videoSettings.audioOutputStereo' => 'Стерео', 'videoSettings.audioNormalization' => 'Нормализиране на силата на звука', 'videoSettings.audioDownmix' => 'Смесване до стерео', 'performanceOverlay.color' => 'Цвят', diff --git a/lib/i18n/strings_da.g.dart b/lib/i18n/strings_da.g.dart index ad1381e1..3b711ab7 100644 --- a/lib/i18n/strings_da.g.dart +++ b/lib/i18n/strings_da.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$da extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Streamer testfilen præcis som Atmos-afspilning i afspilleren. Kræver testfilens URL.'; @override String get atmosTestRawFile => 'Rå EAC3-fil'; @override String get atmosTestRawFileDescription => 'Afspiller testfilen med kendt længde. Kræver testfilens URL.'; + @override String get atmosTestAsbarNative => 'Sample-buffer-renderer (native)'; + @override String get atmosTestAsbarNativeDescription => 'Sender filens urørte komprimerede lyd direkte til systemets renderer. Kræver testfilens URL.'; + @override String get atmosTestAsbarGenerated => 'Sample-buffer-renderer (genopbygget)'; + @override String get atmosTestAsbarGeneratedDescription => 'Det samme, men med lydbeskrivelsen opbygget som ved afspilning. Kræver testfilens URL.'; + @override String get atmosTestSessionMode => 'Brug filmafspilningstilstand'; + @override String get atmosTestSessionModeDescription => 'Fra bruger den tilstand, Dolby dokumenterer. Til bruger den tidligere tilstand.'; + @override String get atmosTestShowRoutePicker => 'Vælg AirPlay-udgang'; + @override String get atmosTestHideRoutePicker => 'Skjul AirPlay-udgangsvælger'; + @override String get atmosTestRoutePickerDescription => 'Sender testen til en AirPlay-modtager. Kun AirPlay rapporterer den valgte lydtilstand.'; @override String get atmosTestStop => 'Stop test'; @override String get atmosTestUrl => 'Testfilens URL'; @override String get atmosTestUrlDescription => 'HTTP-URL til en rå .ec3 Dolby Atmos-fil (f.eks. udtrukket med ffmpeg)'; @@ -1514,6 +1523,11 @@ class _Translations$videoSettings$da extends Translations$videoSettings$en { @override String get audioOutput => 'Lydoutput'; @override String get performanceOverlay => 'Ydelsesoverlay'; @override String get audioPassthrough => 'Lyd-passthrough'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Surround'; + @override String get audioOutputSpatial => 'Rumlig lyd'; + @override String get audioOutputStereo => 'Stereo'; @override String get audioNormalization => 'Normalisér lydstyrke'; @override String get audioDownmix => 'Downmix til stereo'; } @@ -2463,6 +2477,15 @@ extension on TranslationsDa { 'settings.atmosTestRawStreamDescription' => 'Streamer testfilen præcis som Atmos-afspilning i afspilleren. Kræver testfilens URL.', 'settings.atmosTestRawFile' => 'Rå EAC3-fil', 'settings.atmosTestRawFileDescription' => 'Afspiller testfilen med kendt længde. Kræver testfilens URL.', + 'settings.atmosTestAsbarNative' => 'Sample-buffer-renderer (native)', + 'settings.atmosTestAsbarNativeDescription' => 'Sender filens urørte komprimerede lyd direkte til systemets renderer. Kræver testfilens URL.', + 'settings.atmosTestAsbarGenerated' => 'Sample-buffer-renderer (genopbygget)', + 'settings.atmosTestAsbarGeneratedDescription' => 'Det samme, men med lydbeskrivelsen opbygget som ved afspilning. Kræver testfilens URL.', + 'settings.atmosTestSessionMode' => 'Brug filmafspilningstilstand', + 'settings.atmosTestSessionModeDescription' => 'Fra bruger den tilstand, Dolby dokumenterer. Til bruger den tidligere tilstand.', + 'settings.atmosTestShowRoutePicker' => 'Vælg AirPlay-udgang', + 'settings.atmosTestHideRoutePicker' => 'Skjul AirPlay-udgangsvælger', + 'settings.atmosTestRoutePickerDescription' => 'Sender testen til en AirPlay-modtager. Kun AirPlay rapporterer den valgte lydtilstand.', 'settings.atmosTestStop' => 'Stop test', 'settings.atmosTestUrl' => 'Testfilens URL', 'settings.atmosTestUrlDescription' => 'HTTP-URL til en rå .ec3 Dolby Atmos-fil (f.eks. udtrukket med ffmpeg)', @@ -2690,6 +2713,8 @@ extension on TranslationsDa { 'videoControls.language' => 'Sprog', 'videoControls.noSubtitlesFound' => 'Ingen undertekster fundet', 'videoControls.noSubtitlesAvailable' => 'Ingen undertekster tilgængelige', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Ingen lydspor tilgængelige', 'videoControls.noTracksAvailable' => 'Ingen spor tilgængelige', 'videoControls.subtitleDownloaded' => 'Undertekst downloadet', @@ -2699,8 +2724,6 @@ extension on TranslationsDa { 'messages.markedAsWatched' => 'Markeret som set', 'messages.markedAsUnwatched' => 'Markeret som uset', 'messages.markedAsWatchedOffline' => 'Markeret som set (synkroniseres online)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Markeret som uset (synkroniseres online)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Automatisk fjernet: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('da'))(n, one: 'Fjernede automatisk ${n} set download', other: 'Fjernede automatisk ${n} sete downloads', ), @@ -3204,6 +3227,8 @@ extension on TranslationsDa { 'watchTogether.codeMustBe5Chars' => 'Sessionskode skal være 5 tegn', 'watchTogether.joinInstructions' => 'Indtast værtens sessionskode for at deltage.', 'watchTogether.failedToCreate' => 'Kunne ikke oprette session', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Kunne ikke deltage i session', 'watchTogether.sessionCodeCopied' => 'Sessionskode kopieret til udklipsholder', 'watchTogether.relayUnreachable' => 'Relayserveren kan ikke nås. Blokering hos internetudbyderen kan forhindre Se sammen.', @@ -3213,8 +3238,6 @@ extension on TranslationsDa { 'watchTogether.joinCurrentPlaybackDescription' => 'Hop tilbage til det værten ser nu', 'watchTogether.failedToOpenCurrentPlayback' => 'Kunne ikke åbne nuværende afspilning', 'watchTogether.participantJoined' => ({required Object name}) => '${name} deltog', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} forlod', 'watchTogether.participantPaused' => ({required Object name}) => '${name} satte på pause', 'watchTogether.participantResumed' => ({required Object name}) => '${name} genoptog', @@ -3413,6 +3436,11 @@ extension on TranslationsDa { 'videoSettings.audioOutput' => 'Lydoutput', 'videoSettings.performanceOverlay' => 'Ydelsesoverlay', 'videoSettings.audioPassthrough' => 'Lyd-passthrough', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Surround', + 'videoSettings.audioOutputSpatial' => 'Rumlig lyd', + 'videoSettings.audioOutputStereo' => 'Stereo', 'videoSettings.audioNormalization' => 'Normalisér lydstyrke', 'videoSettings.audioDownmix' => 'Downmix til stereo', 'performanceOverlay.color' => 'Farve', diff --git a/lib/i18n/strings_de.g.dart b/lib/i18n/strings_de.g.dart index 3a9e9320..568f3d1f 100644 --- a/lib/i18n/strings_de.g.dart +++ b/lib/i18n/strings_de.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$de extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Streamt die Testdatei genau wie die Atmos-Wiedergabe im Player. Benötigt die URL der Testdatei.'; @override String get atmosTestRawFile => 'Rohe EAC3-Datei'; @override String get atmosTestRawFileDescription => 'Spielt die Testdatei mit bekannter Länge ab. Benötigt die URL der Testdatei.'; + @override String get atmosTestAsbarNative => 'Sample-Buffer-Renderer (nativ)'; + @override String get atmosTestAsbarNativeDescription => 'Übergibt die unveränderte komprimierte Audiospur direkt an den System-Renderer. Benötigt die URL der Testdatei.'; + @override String get atmosTestAsbarGenerated => 'Sample-Buffer-Renderer (neu erstellt)'; + @override String get atmosTestAsbarGeneratedDescription => 'Dasselbe, aber mit der Audiobeschreibung wie bei der Wiedergabe erstellt. Benötigt die URL der Testdatei.'; + @override String get atmosTestSessionMode => 'Filmwiedergabe-Modus verwenden'; + @override String get atmosTestSessionModeDescription => 'Aus verwendet den von Dolby dokumentierten Modus. Ein verwendet den bisherigen Modus.'; + @override String get atmosTestShowRoutePicker => 'AirPlay-Ausgabe wählen'; + @override String get atmosTestHideRoutePicker => 'AirPlay-Auswahl ausblenden'; + @override String get atmosTestRoutePickerDescription => 'Sendet den Test an einen AirPlay-Empfänger. Nur AirPlay meldet den ermittelten Audiomodus.'; @override String get atmosTestStop => 'Test stoppen'; @override String get atmosTestUrl => 'URL der Testdatei'; @override String get atmosTestUrlDescription => 'HTTP-URL einer rohen .ec3-Dolby-Atmos-Datei (z. B. mit ffmpeg extrahiert)'; @@ -1514,6 +1523,11 @@ class _Translations$videoSettings$de extends Translations$videoSettings$en { @override String get audioOutput => 'Audioausgabe'; @override String get performanceOverlay => 'Leistungsanzeige'; @override String get audioPassthrough => 'Audio-Durchleitung'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Surround'; + @override String get audioOutputSpatial => 'Räumliches Audio'; + @override String get audioOutputStereo => 'Stereo'; @override String get audioNormalization => 'Lautstärke normalisieren'; @override String get audioDownmix => 'Downmix auf Stereo'; } @@ -2463,6 +2477,15 @@ extension on TranslationsDe { 'settings.atmosTestRawStreamDescription' => 'Streamt die Testdatei genau wie die Atmos-Wiedergabe im Player. Benötigt die URL der Testdatei.', 'settings.atmosTestRawFile' => 'Rohe EAC3-Datei', 'settings.atmosTestRawFileDescription' => 'Spielt die Testdatei mit bekannter Länge ab. Benötigt die URL der Testdatei.', + 'settings.atmosTestAsbarNative' => 'Sample-Buffer-Renderer (nativ)', + 'settings.atmosTestAsbarNativeDescription' => 'Übergibt die unveränderte komprimierte Audiospur direkt an den System-Renderer. Benötigt die URL der Testdatei.', + 'settings.atmosTestAsbarGenerated' => 'Sample-Buffer-Renderer (neu erstellt)', + 'settings.atmosTestAsbarGeneratedDescription' => 'Dasselbe, aber mit der Audiobeschreibung wie bei der Wiedergabe erstellt. Benötigt die URL der Testdatei.', + 'settings.atmosTestSessionMode' => 'Filmwiedergabe-Modus verwenden', + 'settings.atmosTestSessionModeDescription' => 'Aus verwendet den von Dolby dokumentierten Modus. Ein verwendet den bisherigen Modus.', + 'settings.atmosTestShowRoutePicker' => 'AirPlay-Ausgabe wählen', + 'settings.atmosTestHideRoutePicker' => 'AirPlay-Auswahl ausblenden', + 'settings.atmosTestRoutePickerDescription' => 'Sendet den Test an einen AirPlay-Empfänger. Nur AirPlay meldet den ermittelten Audiomodus.', 'settings.atmosTestStop' => 'Test stoppen', 'settings.atmosTestUrl' => 'URL der Testdatei', 'settings.atmosTestUrlDescription' => 'HTTP-URL einer rohen .ec3-Dolby-Atmos-Datei (z. B. mit ffmpeg extrahiert)', @@ -2690,6 +2713,8 @@ extension on TranslationsDe { 'videoControls.language' => 'Sprache', 'videoControls.noSubtitlesFound' => 'Keine Untertitel gefunden', 'videoControls.noSubtitlesAvailable' => 'Keine Untertitel verfügbar', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Keine Audiospuren verfügbar', 'videoControls.noTracksAvailable' => 'Keine Spuren verfügbar', 'videoControls.subtitleDownloaded' => 'Untertitel heruntergeladen', @@ -2699,8 +2724,6 @@ extension on TranslationsDe { 'messages.markedAsWatched' => 'Als gesehen markiert', 'messages.markedAsUnwatched' => 'Als ungesehen markiert', 'messages.markedAsWatchedOffline' => 'Als gesehen markiert (wird synchronisiert, wenn online)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Als ungesehen markiert (wird synchronisiert, wenn online)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Automatisch entfernt: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('de'))(n, one: 'Automatisch entfernt: ${n} angesehener Download', other: 'Automatisch entfernt: ${n} angesehene Downloads', ), @@ -3204,6 +3227,8 @@ extension on TranslationsDe { 'watchTogether.codeMustBe5Chars' => 'Sitzungscode muss 5 Zeichen haben', 'watchTogether.joinInstructions' => 'Gib den Sitzungscode des Hosts ein, um beizutreten.', 'watchTogether.failedToCreate' => 'Sitzung konnte nicht erstellt werden', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Beitritt zur Sitzung fehlgeschlagen', 'watchTogether.sessionCodeCopied' => 'Sitzungscode in Zwischenablage kopiert', 'watchTogether.relayUnreachable' => 'Relay-Server nicht erreichbar. Eine Sperre durch den Internetanbieter kann gemeinsames Schauen verhindern.', @@ -3213,8 +3238,6 @@ extension on TranslationsDe { 'watchTogether.joinCurrentPlaybackDescription' => 'Zu dem Inhalt wechseln, den der Host gerade ansieht', 'watchTogether.failedToOpenCurrentPlayback' => 'Aktuelle Wiedergabe konnte nicht geöffnet werden', 'watchTogether.participantJoined' => ({required Object name}) => '${name} ist beigetreten', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} hat die Sitzung verlassen', 'watchTogether.participantPaused' => ({required Object name}) => '${name} hat pausiert', 'watchTogether.participantResumed' => ({required Object name}) => '${name} hat fortgesetzt', @@ -3413,6 +3436,11 @@ extension on TranslationsDe { 'videoSettings.audioOutput' => 'Audioausgabe', 'videoSettings.performanceOverlay' => 'Leistungsanzeige', 'videoSettings.audioPassthrough' => 'Audio-Durchleitung', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Surround', + 'videoSettings.audioOutputSpatial' => 'Räumliches Audio', + 'videoSettings.audioOutputStereo' => 'Stereo', 'videoSettings.audioNormalization' => 'Lautstärke normalisieren', 'videoSettings.audioDownmix' => 'Downmix auf Stereo', 'performanceOverlay.color' => 'Farbe', diff --git a/lib/i18n/strings_en.g.dart b/lib/i18n/strings_en.g.dart index a0342320..54c40f51 100644 --- a/lib/i18n/strings_en.g.dart +++ b/lib/i18n/strings_en.g.dart @@ -981,6 +981,33 @@ class Translations$settings$en { /// en: 'Plays the test file with a known length. Needs the test file URL.' String get atmosTestRawFileDescription => 'Plays the test file with a known length. Needs the test file URL.'; + /// en: 'Sample-buffer renderer (native)' + String get atmosTestAsbarNative => 'Sample-buffer renderer (native)'; + + /// en: 'Feeds the file's untouched compressed audio straight to the system renderer. Needs the test file URL.' + String get atmosTestAsbarNativeDescription => 'Feeds the file\'s untouched compressed audio straight to the system renderer. Needs the test file URL.'; + + /// en: 'Sample-buffer renderer (rebuilt)' + String get atmosTestAsbarGenerated => 'Sample-buffer renderer (rebuilt)'; + + /// en: 'Same, but with the audio description rebuilt the way playback builds it. Needs the test file URL.' + String get atmosTestAsbarGeneratedDescription => 'Same, but with the audio description rebuilt the way playback builds it. Needs the test file URL.'; + + /// en: 'Use movie playback session mode' + String get atmosTestSessionMode => 'Use movie playback session mode'; + + /// en: 'Off uses the mode Dolby documents. On uses the mode playback used previously.' + String get atmosTestSessionModeDescription => 'Off uses the mode Dolby documents. On uses the mode playback used previously.'; + + /// en: 'Choose AirPlay output' + String get atmosTestShowRoutePicker => 'Choose AirPlay output'; + + /// en: 'Hide AirPlay output picker' + String get atmosTestHideRoutePicker => 'Hide AirPlay output picker'; + + /// en: 'Send the test to an AirPlay receiver. Only AirPlay reports the resolved audio mode.' + String get atmosTestRoutePickerDescription => 'Send the test to an AirPlay receiver. Only AirPlay reports the resolved audio mode.'; + /// en: 'Stop test' String get atmosTestStop => 'Stop test'; @@ -3643,6 +3670,21 @@ class Translations$videoSettings$en { /// en: 'Audio Passthrough' String get audioPassthrough => 'Audio Passthrough'; + /// en: 'Dolby Atmos' + String get audioOutputDolbyAtmos => 'Dolby Atmos'; + + /// en: 'Dolby Audio' + String get audioOutputDolbyAudio => 'Dolby Audio'; + + /// en: 'Surround' + String get audioOutputSurround => 'Surround'; + + /// en: 'Spatial Audio' + String get audioOutputSpatial => 'Spatial Audio'; + + /// en: 'Stereo' + String get audioOutputStereo => 'Stereo'; + /// en: 'Normalize Loudness' String get audioNormalization => 'Normalize Loudness'; @@ -5445,6 +5487,15 @@ extension on Translations { 'settings.atmosTestRawStreamDescription' => 'Streams the test file exactly like in-player Atmos playback. Needs the test file URL.', 'settings.atmosTestRawFile' => 'Raw EAC3 file', 'settings.atmosTestRawFileDescription' => 'Plays the test file with a known length. Needs the test file URL.', + 'settings.atmosTestAsbarNative' => 'Sample-buffer renderer (native)', + 'settings.atmosTestAsbarNativeDescription' => 'Feeds the file\'s untouched compressed audio straight to the system renderer. Needs the test file URL.', + 'settings.atmosTestAsbarGenerated' => 'Sample-buffer renderer (rebuilt)', + 'settings.atmosTestAsbarGeneratedDescription' => 'Same, but with the audio description rebuilt the way playback builds it. Needs the test file URL.', + 'settings.atmosTestSessionMode' => 'Use movie playback session mode', + 'settings.atmosTestSessionModeDescription' => 'Off uses the mode Dolby documents. On uses the mode playback used previously.', + 'settings.atmosTestShowRoutePicker' => 'Choose AirPlay output', + 'settings.atmosTestHideRoutePicker' => 'Hide AirPlay output picker', + 'settings.atmosTestRoutePickerDescription' => 'Send the test to an AirPlay receiver. Only AirPlay reports the resolved audio mode.', 'settings.atmosTestStop' => 'Stop test', 'settings.atmosTestUrl' => 'Test file URL', 'settings.atmosTestUrlDescription' => 'HTTP URL of a raw .ec3 Dolby Atmos file (e.g. extracted with ffmpeg)', @@ -5669,6 +5720,8 @@ extension on Translations { 'videoControls.queue' => 'Queue', 'videoControls.noQueueItems' => 'No items in queue', 'videoControls.searchSubtitles' => 'Search Subtitles', + _ => null, + } ?? switch (path) { 'videoControls.language' => 'Language', 'videoControls.noSubtitlesFound' => 'No subtitles found', 'videoControls.noSubtitlesAvailable' => 'No subtitles available', @@ -5678,8 +5731,6 @@ extension on Translations { 'videoControls.subtitleDownloadedNotApplied' => 'Subtitle downloaded, but it could not be selected', 'videoControls.subtitleDownloadFailed' => 'Failed to download subtitle', 'videoControls.searchLanguages' => 'Search languages...', - _ => null, - } ?? switch (path) { 'messages.markedAsWatched' => 'Marked as watched', 'messages.markedAsUnwatched' => 'Marked as unwatched', 'messages.markedAsWatchedOffline' => 'Marked as watched (will sync when online)', @@ -6183,6 +6234,8 @@ extension on Translations { 'watchTogether.syncing' => 'Syncing...', 'watchTogether.joinWatchSession' => 'Join Watch Session', 'watchTogether.enterCodeHint' => 'Enter 5-character code', + _ => null, + } ?? switch (path) { 'watchTogether.pasteFromClipboard' => 'Paste from clipboard', 'watchTogether.pleaseEnterCode' => 'Please enter a session code', 'watchTogether.codeMustBe5Chars' => 'Session code must be 5 characters', @@ -6192,8 +6245,6 @@ extension on Translations { 'watchTogether.sessionCodeCopied' => 'Session code copied to clipboard', 'watchTogether.relayUnreachable' => 'Relay server unreachable. ISP blocking may prevent Watch Together.', 'watchTogether.reconnectingToHost' => 'Reconnecting to host...', - _ => null, - } ?? switch (path) { 'watchTogether.currentPlayback' => 'Current Playback', 'watchTogether.joinCurrentPlayback' => 'Join Current Playback', 'watchTogether.joinCurrentPlaybackDescription' => 'Jump back into what the host is currently watching', @@ -6403,6 +6454,11 @@ extension on Translations { 'videoSettings.audioOutput' => 'Audio Output', 'videoSettings.performanceOverlay' => 'Performance Overlay', 'videoSettings.audioPassthrough' => 'Audio Passthrough', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Surround', + 'videoSettings.audioOutputSpatial' => 'Spatial Audio', + 'videoSettings.audioOutputStereo' => 'Stereo', 'videoSettings.audioNormalization' => 'Normalize Loudness', 'videoSettings.audioDownmix' => 'Downmix to Stereo', 'performanceOverlay.color' => 'Color', diff --git a/lib/i18n/strings_es.g.dart b/lib/i18n/strings_es.g.dart index 2e2b2de2..69844281 100644 --- a/lib/i18n/strings_es.g.dart +++ b/lib/i18n/strings_es.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$es extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Transmite el archivo de prueba igual que durante la reproducción de Atmos. Requiere la URL del archivo de prueba.'; @override String get atmosTestRawFile => 'Archivo EAC3 sin procesar'; @override String get atmosTestRawFileDescription => 'Reproduce el archivo de prueba con longitud conocida. Necesita la URL del archivo de prueba.'; + @override String get atmosTestAsbarNative => 'Renderizador de búfer de muestras (nativo)'; + @override String get atmosTestAsbarNativeDescription => 'Envía el audio comprimido intacto del archivo directamente al renderizador del sistema. Necesita la URL del archivo de prueba.'; + @override String get atmosTestAsbarGenerated => 'Renderizador de búfer de muestras (reconstruido)'; + @override String get atmosTestAsbarGeneratedDescription => 'Igual, pero con la descripción de audio construida como en la reproducción. Necesita la URL del archivo de prueba.'; + @override String get atmosTestSessionMode => 'Usar modo de reproducción de películas'; + @override String get atmosTestSessionModeDescription => 'Desactivado usa el modo que documenta Dolby. Activado usa el modo anterior.'; + @override String get atmosTestShowRoutePicker => 'Elegir salida AirPlay'; + @override String get atmosTestHideRoutePicker => 'Ocultar selector de salida AirPlay'; + @override String get atmosTestRoutePickerDescription => 'Envía la prueba a un receptor AirPlay. Solo AirPlay informa del modo de audio resuelto.'; @override String get atmosTestStop => 'Detener prueba'; @override String get atmosTestUrl => 'URL del archivo de prueba'; @override String get atmosTestUrlDescription => 'URL HTTP de un archivo .ec3 Dolby Atmos sin procesar (p. ej., extraído con ffmpeg)'; @@ -1514,6 +1523,11 @@ class _Translations$videoSettings$es extends Translations$videoSettings$en { @override String get audioOutput => 'Salida de audio'; @override String get performanceOverlay => 'Indicador de rendimiento'; @override String get audioPassthrough => 'Transferencia directa de audio'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Envolvente'; + @override String get audioOutputSpatial => 'Audio espacial'; + @override String get audioOutputStereo => 'Estéreo'; @override String get audioNormalization => 'Normalizar volumen'; @override String get audioDownmix => 'Mezclar a estéreo'; } @@ -2463,6 +2477,15 @@ extension on TranslationsEs { 'settings.atmosTestRawStreamDescription' => 'Transmite el archivo de prueba igual que durante la reproducción de Atmos. Requiere la URL del archivo de prueba.', 'settings.atmosTestRawFile' => 'Archivo EAC3 sin procesar', 'settings.atmosTestRawFileDescription' => 'Reproduce el archivo de prueba con longitud conocida. Necesita la URL del archivo de prueba.', + 'settings.atmosTestAsbarNative' => 'Renderizador de búfer de muestras (nativo)', + 'settings.atmosTestAsbarNativeDescription' => 'Envía el audio comprimido intacto del archivo directamente al renderizador del sistema. Necesita la URL del archivo de prueba.', + 'settings.atmosTestAsbarGenerated' => 'Renderizador de búfer de muestras (reconstruido)', + 'settings.atmosTestAsbarGeneratedDescription' => 'Igual, pero con la descripción de audio construida como en la reproducción. Necesita la URL del archivo de prueba.', + 'settings.atmosTestSessionMode' => 'Usar modo de reproducción de películas', + 'settings.atmosTestSessionModeDescription' => 'Desactivado usa el modo que documenta Dolby. Activado usa el modo anterior.', + 'settings.atmosTestShowRoutePicker' => 'Elegir salida AirPlay', + 'settings.atmosTestHideRoutePicker' => 'Ocultar selector de salida AirPlay', + 'settings.atmosTestRoutePickerDescription' => 'Envía la prueba a un receptor AirPlay. Solo AirPlay informa del modo de audio resuelto.', 'settings.atmosTestStop' => 'Detener prueba', 'settings.atmosTestUrl' => 'URL del archivo de prueba', 'settings.atmosTestUrlDescription' => 'URL HTTP de un archivo .ec3 Dolby Atmos sin procesar (p. ej., extraído con ffmpeg)', @@ -2690,6 +2713,8 @@ extension on TranslationsEs { 'videoControls.language' => 'Idioma', 'videoControls.noSubtitlesFound' => 'No se encontraron subtítulos', 'videoControls.noSubtitlesAvailable' => 'No hay subtítulos disponibles', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'No hay pistas de audio disponibles', 'videoControls.noTracksAvailable' => 'No hay pistas disponibles', 'videoControls.subtitleDownloaded' => 'Subtítulo descargado', @@ -2699,8 +2724,6 @@ extension on TranslationsEs { 'messages.markedAsWatched' => 'Marcado como visto', 'messages.markedAsUnwatched' => 'Marcado como no visto', 'messages.markedAsWatchedOffline' => 'Marcado como visto (se sincronizará al estar en línea)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Marcado como no visto (se sincronizará al estar en línea)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Eliminado automáticamente: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('es'))(n, one: 'Se eliminó automáticamente ${n} descarga vista', other: 'Se eliminaron automáticamente ${n} descargas vistas', ), @@ -3204,6 +3227,8 @@ extension on TranslationsEs { 'watchTogether.codeMustBe5Chars' => 'El código de sesión debe tener 5 caracteres', 'watchTogether.joinInstructions' => 'Introduce el código de sesión del anfitrión para unirte.', 'watchTogether.failedToCreate' => 'Error al crear la sesión', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Error al unirse a la sesión', 'watchTogether.sessionCodeCopied' => 'Código de sesión copiado al portapapeles', 'watchTogether.relayUnreachable' => 'No se puede acceder al servidor de retransmisión. Es posible que tu proveedor de internet esté bloqueando Ver juntos.', @@ -3213,8 +3238,6 @@ extension on TranslationsEs { 'watchTogether.joinCurrentPlaybackDescription' => 'Vuelve a lo que el anfitrión está viendo ahora mismo', 'watchTogether.failedToOpenCurrentPlayback' => 'No se pudo abrir la reproducción actual', 'watchTogether.participantJoined' => ({required Object name}) => '${name} se unió', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} se fue', 'watchTogether.participantPaused' => ({required Object name}) => '${name} pausó', 'watchTogether.participantResumed' => ({required Object name}) => '${name} reanudó', @@ -3413,6 +3436,11 @@ extension on TranslationsEs { 'videoSettings.audioOutput' => 'Salida de audio', 'videoSettings.performanceOverlay' => 'Indicador de rendimiento', 'videoSettings.audioPassthrough' => 'Transferencia directa de audio', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Envolvente', + 'videoSettings.audioOutputSpatial' => 'Audio espacial', + 'videoSettings.audioOutputStereo' => 'Estéreo', 'videoSettings.audioNormalization' => 'Normalizar volumen', 'videoSettings.audioDownmix' => 'Mezclar a estéreo', 'performanceOverlay.color' => 'Color', diff --git a/lib/i18n/strings_fr.g.dart b/lib/i18n/strings_fr.g.dart index c2d30554..3b2d2506 100644 --- a/lib/i18n/strings_fr.g.dart +++ b/lib/i18n/strings_fr.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$fr extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Diffuse le fichier de test exactement comme la lecture Atmos du lecteur. Nécessite l\'URL du fichier de test.'; @override String get atmosTestRawFile => 'Fichier EAC3 brut'; @override String get atmosTestRawFileDescription => 'Lit le fichier de test avec une longueur connue. Nécessite l\'URL du fichier de test.'; + @override String get atmosTestAsbarNative => 'Moteur de rendu à tampon d\'échantillons (natif)'; + @override String get atmosTestAsbarNativeDescription => 'Transmet l\'audio compressé intact du fichier directement au moteur de rendu du système. Nécessite l\'URL du fichier de test.'; + @override String get atmosTestAsbarGenerated => 'Moteur de rendu à tampon d\'échantillons (reconstruit)'; + @override String get atmosTestAsbarGeneratedDescription => 'Identique, mais avec la description audio reconstruite comme à la lecture. Nécessite l\'URL du fichier de test.'; + @override String get atmosTestSessionMode => 'Utiliser le mode lecture de films'; + @override String get atmosTestSessionModeDescription => 'Désactivé utilise le mode documenté par Dolby. Activé utilise le mode précédent.'; + @override String get atmosTestShowRoutePicker => 'Choisir la sortie AirPlay'; + @override String get atmosTestHideRoutePicker => 'Masquer le sélecteur AirPlay'; + @override String get atmosTestRoutePickerDescription => 'Envoie le test vers un récepteur AirPlay. Seul AirPlay indique le mode audio retenu.'; @override String get atmosTestStop => 'Arrêter le test'; @override String get atmosTestUrl => 'URL du fichier de test'; @override String get atmosTestUrlDescription => 'URL HTTP d\'un fichier .ec3 Dolby Atmos brut (extrait par ex. avec ffmpeg)'; @@ -1514,6 +1523,11 @@ class _Translations$videoSettings$fr extends Translations$videoSettings$en { @override String get audioOutput => 'Sortie audio'; @override String get performanceOverlay => 'Données de performance'; @override String get audioPassthrough => 'Transmission audio directe'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Surround'; + @override String get audioOutputSpatial => 'Audio spatial'; + @override String get audioOutputStereo => 'Stéréo'; @override String get audioNormalization => 'Normaliser le volume'; @override String get audioDownmix => 'Conversion en stéréo'; } @@ -2463,6 +2477,15 @@ extension on TranslationsFr { 'settings.atmosTestRawStreamDescription' => 'Diffuse le fichier de test exactement comme la lecture Atmos du lecteur. Nécessite l\'URL du fichier de test.', 'settings.atmosTestRawFile' => 'Fichier EAC3 brut', 'settings.atmosTestRawFileDescription' => 'Lit le fichier de test avec une longueur connue. Nécessite l\'URL du fichier de test.', + 'settings.atmosTestAsbarNative' => 'Moteur de rendu à tampon d\'échantillons (natif)', + 'settings.atmosTestAsbarNativeDescription' => 'Transmet l\'audio compressé intact du fichier directement au moteur de rendu du système. Nécessite l\'URL du fichier de test.', + 'settings.atmosTestAsbarGenerated' => 'Moteur de rendu à tampon d\'échantillons (reconstruit)', + 'settings.atmosTestAsbarGeneratedDescription' => 'Identique, mais avec la description audio reconstruite comme à la lecture. Nécessite l\'URL du fichier de test.', + 'settings.atmosTestSessionMode' => 'Utiliser le mode lecture de films', + 'settings.atmosTestSessionModeDescription' => 'Désactivé utilise le mode documenté par Dolby. Activé utilise le mode précédent.', + 'settings.atmosTestShowRoutePicker' => 'Choisir la sortie AirPlay', + 'settings.atmosTestHideRoutePicker' => 'Masquer le sélecteur AirPlay', + 'settings.atmosTestRoutePickerDescription' => 'Envoie le test vers un récepteur AirPlay. Seul AirPlay indique le mode audio retenu.', 'settings.atmosTestStop' => 'Arrêter le test', 'settings.atmosTestUrl' => 'URL du fichier de test', 'settings.atmosTestUrlDescription' => 'URL HTTP d\'un fichier .ec3 Dolby Atmos brut (extrait par ex. avec ffmpeg)', @@ -2690,6 +2713,8 @@ extension on TranslationsFr { 'videoControls.language' => 'Langue', 'videoControls.noSubtitlesFound' => 'Aucun sous-titre trouvé', 'videoControls.noSubtitlesAvailable' => 'Aucun sous-titre disponible', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Aucune piste audio disponible', 'videoControls.noTracksAvailable' => 'Aucune piste disponible', 'videoControls.subtitleDownloaded' => 'Sous-titre téléchargé', @@ -2699,8 +2724,6 @@ extension on TranslationsFr { 'messages.markedAsWatched' => 'Marqué comme vu', 'messages.markedAsUnwatched' => 'Marqué comme non vu', 'messages.markedAsWatchedOffline' => 'Marqué comme vu (se synchronisera lorsque vous serez en ligne)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Marqué comme non vu (sera synchronisé lorsque vous serez en ligne)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Supprimé automatiquement : ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('fr'))(n, one: '${n} téléchargement vu supprimé automatiquement', other: '${n} téléchargements vus supprimés automatiquement', ), @@ -3204,6 +3227,8 @@ extension on TranslationsFr { 'watchTogether.codeMustBe5Chars' => 'Le code de session doit comporter 5 caractères', 'watchTogether.joinInstructions' => 'Saisissez le code de session de l\'hôte pour rejoindre.', 'watchTogether.failedToCreate' => 'Échec de la création de la session', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Échec de la connexion à la session', 'watchTogether.sessionCodeCopied' => 'Code de session copié dans le presse-papiers', 'watchTogether.relayUnreachable' => 'Serveur relais inaccessible. Un blocage par le fournisseur d’accès peut empêcher le fonctionnement de Regarder ensemble.', @@ -3213,8 +3238,6 @@ extension on TranslationsFr { 'watchTogether.joinCurrentPlaybackDescription' => 'Reprendre le contenu que l’hôte regarde actuellement', 'watchTogether.failedToOpenCurrentPlayback' => 'Impossible d\'ouvrir la lecture en cours', 'watchTogether.participantJoined' => ({required Object name}) => '${name} a rejoint', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} est parti', 'watchTogether.participantPaused' => ({required Object name}) => '${name} a mis en pause', 'watchTogether.participantResumed' => ({required Object name}) => '${name} a repris', @@ -3413,6 +3436,11 @@ extension on TranslationsFr { 'videoSettings.audioOutput' => 'Sortie audio', 'videoSettings.performanceOverlay' => 'Données de performance', 'videoSettings.audioPassthrough' => 'Transmission audio directe', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Surround', + 'videoSettings.audioOutputSpatial' => 'Audio spatial', + 'videoSettings.audioOutputStereo' => 'Stéréo', 'videoSettings.audioNormalization' => 'Normaliser le volume', 'videoSettings.audioDownmix' => 'Conversion en stéréo', 'performanceOverlay.color' => 'Couleur', diff --git a/lib/i18n/strings_hu.g.dart b/lib/i18n/strings_hu.g.dart index 71aa89b2..5dd9c398 100644 --- a/lib/i18n/strings_hu.g.dart +++ b/lib/i18n/strings_hu.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$hu extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'A tesztfájlt pontosan úgy közvetíti, mint a lejátszón belüli Atmos lejátszás. Szükséges a tesztfájl URL-je.'; @override String get atmosTestRawFile => 'Nyers EAC3 fájl'; @override String get atmosTestRawFileDescription => 'Ismert hosszúságú tesztfájlt játszik le. Szükséges a tesztfájl URL-je.'; + @override String get atmosTestAsbarNative => 'Mintapuffer-megjelenítő (natív)'; + @override String get atmosTestAsbarNativeDescription => 'A fájl érintetlen tömörített hangját közvetlenül a rendszer megjelenítőjének adja. Szükséges a tesztfájl URL-je.'; + @override String get atmosTestAsbarGenerated => 'Mintapuffer-megjelenítő (újraépített)'; + @override String get atmosTestAsbarGeneratedDescription => 'Ugyanaz, de a lejátszás módján felépített hangleírással. Szükséges a tesztfájl URL-je.'; + @override String get atmosTestSessionMode => 'Filmlejátszási mód használata'; + @override String get atmosTestSessionModeDescription => 'Kikapcsolva a Dolby által dokumentált módot használja. Bekapcsolva a korábbi módot.'; + @override String get atmosTestShowRoutePicker => 'AirPlay kimenet választása'; + @override String get atmosTestHideRoutePicker => 'AirPlay kimenetválasztó elrejtése'; + @override String get atmosTestRoutePickerDescription => 'Elküldi a tesztet egy AirPlay vevőnek. Csak az AirPlay jelzi a feloldott hangmódot.'; @override String get atmosTestStop => 'Teszt leállítása'; @override String get atmosTestUrl => 'Tesztfájl URL-je'; @override String get atmosTestUrlDescription => 'Nyers .ec3 Dolby Atmos fájl HTTP URL-je (pl. ffmpeg-gel kinyerve)'; @@ -1514,6 +1523,11 @@ class _Translations$videoSettings$hu extends Translations$videoSettings$en { @override String get audioOutput => 'Hangkimenet'; @override String get performanceOverlay => 'Teljesítményadatok'; @override String get audioPassthrough => 'Hangtovábbítás (passthrough)'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Térhatású'; + @override String get audioOutputSpatial => 'Térbeli hang'; + @override String get audioOutputStereo => 'Sztereó'; @override String get audioNormalization => 'Hangerő normalizálása'; @override String get audioDownmix => 'Lekeverés sztereóra'; } @@ -2463,6 +2477,15 @@ extension on TranslationsHu { 'settings.atmosTestRawStreamDescription' => 'A tesztfájlt pontosan úgy közvetíti, mint a lejátszón belüli Atmos lejátszás. Szükséges a tesztfájl URL-je.', 'settings.atmosTestRawFile' => 'Nyers EAC3 fájl', 'settings.atmosTestRawFileDescription' => 'Ismert hosszúságú tesztfájlt játszik le. Szükséges a tesztfájl URL-je.', + 'settings.atmosTestAsbarNative' => 'Mintapuffer-megjelenítő (natív)', + 'settings.atmosTestAsbarNativeDescription' => 'A fájl érintetlen tömörített hangját közvetlenül a rendszer megjelenítőjének adja. Szükséges a tesztfájl URL-je.', + 'settings.atmosTestAsbarGenerated' => 'Mintapuffer-megjelenítő (újraépített)', + 'settings.atmosTestAsbarGeneratedDescription' => 'Ugyanaz, de a lejátszás módján felépített hangleírással. Szükséges a tesztfájl URL-je.', + 'settings.atmosTestSessionMode' => 'Filmlejátszási mód használata', + 'settings.atmosTestSessionModeDescription' => 'Kikapcsolva a Dolby által dokumentált módot használja. Bekapcsolva a korábbi módot.', + 'settings.atmosTestShowRoutePicker' => 'AirPlay kimenet választása', + 'settings.atmosTestHideRoutePicker' => 'AirPlay kimenetválasztó elrejtése', + 'settings.atmosTestRoutePickerDescription' => 'Elküldi a tesztet egy AirPlay vevőnek. Csak az AirPlay jelzi a feloldott hangmódot.', 'settings.atmosTestStop' => 'Teszt leállítása', 'settings.atmosTestUrl' => 'Tesztfájl URL-je', 'settings.atmosTestUrlDescription' => 'Nyers .ec3 Dolby Atmos fájl HTTP URL-je (pl. ffmpeg-gel kinyerve)', @@ -2690,6 +2713,8 @@ extension on TranslationsHu { 'videoControls.language' => 'Nyelv', 'videoControls.noSubtitlesFound' => 'Nem találhatók feliratok', 'videoControls.noSubtitlesAvailable' => 'Nincsenek elérhető feliratok', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Nincsenek elérhető hangsávok', 'videoControls.noTracksAvailable' => 'Nincsenek elérhető sávok', 'videoControls.subtitleDownloaded' => 'Felirat letöltve', @@ -2699,8 +2724,6 @@ extension on TranslationsHu { 'messages.markedAsWatched' => 'Megjelölve megtekintettként', 'messages.markedAsUnwatched' => 'Megjelölve nem megtekintettként', 'messages.markedAsWatchedOffline' => 'Megjelölve megtekintettként (szinkronizálás online állapotban)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Megjelölve nem megtekintettként (szinkronizálás online állapotban)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Automatikusan eltávolítva: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('hu'))(n, one: '${n} megtekintett letöltés automatikusan eltávolítva', other: '${n} megtekintett letöltés automatikusan eltávolítva', ), @@ -3204,6 +3227,8 @@ extension on TranslationsHu { 'watchTogether.codeMustBe5Chars' => 'A munkamenetkódnak 5 karakterből kell állnia', 'watchTogether.joinInstructions' => 'Add meg a házigazda kódját a csatlakozáshoz.', 'watchTogether.failedToCreate' => 'Nem sikerült a munkamenet létrehozása', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Nem sikerült csatlakozni a munkamenethez', 'watchTogether.sessionCodeCopied' => 'A munkamenetkód a vágólapra másolva', 'watchTogether.relayUnreachable' => 'A relészerver nem érhető el. Az internetszolgáltató blokkolása megakadályozhatja a közös nézést.', @@ -3213,8 +3238,6 @@ extension on TranslationsHu { 'watchTogether.joinCurrentPlaybackDescription' => 'Visszatérés ahhoz, amit a házigazda éppen néz', 'watchTogether.failedToOpenCurrentPlayback' => 'Nem sikerült megnyitni a jelenlegi lejátszást', 'watchTogether.participantJoined' => ({required Object name}) => '${name} csatlakozott', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} kilépett', 'watchTogether.participantPaused' => ({required Object name}) => '${name} szüneteltette a lejátszást', 'watchTogether.participantResumed' => ({required Object name}) => '${name} folytatta a lejátszást', @@ -3413,6 +3436,11 @@ extension on TranslationsHu { 'videoSettings.audioOutput' => 'Hangkimenet', 'videoSettings.performanceOverlay' => 'Teljesítményadatok', 'videoSettings.audioPassthrough' => 'Hangtovábbítás (passthrough)', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Térhatású', + 'videoSettings.audioOutputSpatial' => 'Térbeli hang', + 'videoSettings.audioOutputStereo' => 'Sztereó', 'videoSettings.audioNormalization' => 'Hangerő normalizálása', 'videoSettings.audioDownmix' => 'Lekeverés sztereóra', 'performanceOverlay.color' => 'Szín', diff --git a/lib/i18n/strings_it.g.dart b/lib/i18n/strings_it.g.dart index 728e22c1..e9db915c 100644 --- a/lib/i18n/strings_it.g.dart +++ b/lib/i18n/strings_it.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$it extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Trasmette il file di prova esattamente come la riproduzione Atmos del lettore. Richiede l\'URL del file di prova.'; @override String get atmosTestRawFile => 'File EAC3 grezzo'; @override String get atmosTestRawFileDescription => 'Riproduce il file di prova con lunghezza nota. Richiede l\'URL del file di prova.'; + @override String get atmosTestAsbarNative => 'Renderer con buffer di campioni (nativo)'; + @override String get atmosTestAsbarNativeDescription => 'Invia l\'audio compresso intatto del file direttamente al renderer di sistema. Richiede l\'URL del file di test.'; + @override String get atmosTestAsbarGenerated => 'Renderer con buffer di campioni (ricostruito)'; + @override String get atmosTestAsbarGeneratedDescription => 'Come sopra, ma con la descrizione audio costruita come nella riproduzione. Richiede l\'URL del file di test.'; + @override String get atmosTestSessionMode => 'Usa la modalità riproduzione film'; + @override String get atmosTestSessionModeDescription => 'Disattivato usa la modalità documentata da Dolby. Attivato usa la modalità precedente.'; + @override String get atmosTestShowRoutePicker => 'Scegli uscita AirPlay'; + @override String get atmosTestHideRoutePicker => 'Nascondi selettore uscita AirPlay'; + @override String get atmosTestRoutePickerDescription => 'Invia il test a un ricevitore AirPlay. Solo AirPlay riporta la modalità audio risolta.'; @override String get atmosTestStop => 'Interrompi test'; @override String get atmosTestUrl => 'URL del file di prova'; @override String get atmosTestUrlDescription => 'URL HTTP di un file .ec3 Dolby Atmos grezzo (ad es. estratto con ffmpeg)'; @@ -1514,6 +1523,11 @@ class _Translations$videoSettings$it extends Translations$videoSettings$en { @override String get audioOutput => 'Uscita audio'; @override String get performanceOverlay => 'Overlay prestazioni'; @override String get audioPassthrough => 'Passthrough audio'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Surround'; + @override String get audioOutputSpatial => 'Audio spaziale'; + @override String get audioOutputStereo => 'Stereo'; @override String get audioNormalization => 'Normalizza il volume'; @override String get audioDownmix => 'Downmix in stereo'; } @@ -2463,6 +2477,15 @@ extension on TranslationsIt { 'settings.atmosTestRawStreamDescription' => 'Trasmette il file di prova esattamente come la riproduzione Atmos del lettore. Richiede l\'URL del file di prova.', 'settings.atmosTestRawFile' => 'File EAC3 grezzo', 'settings.atmosTestRawFileDescription' => 'Riproduce il file di prova con lunghezza nota. Richiede l\'URL del file di prova.', + 'settings.atmosTestAsbarNative' => 'Renderer con buffer di campioni (nativo)', + 'settings.atmosTestAsbarNativeDescription' => 'Invia l\'audio compresso intatto del file direttamente al renderer di sistema. Richiede l\'URL del file di test.', + 'settings.atmosTestAsbarGenerated' => 'Renderer con buffer di campioni (ricostruito)', + 'settings.atmosTestAsbarGeneratedDescription' => 'Come sopra, ma con la descrizione audio costruita come nella riproduzione. Richiede l\'URL del file di test.', + 'settings.atmosTestSessionMode' => 'Usa la modalità riproduzione film', + 'settings.atmosTestSessionModeDescription' => 'Disattivato usa la modalità documentata da Dolby. Attivato usa la modalità precedente.', + 'settings.atmosTestShowRoutePicker' => 'Scegli uscita AirPlay', + 'settings.atmosTestHideRoutePicker' => 'Nascondi selettore uscita AirPlay', + 'settings.atmosTestRoutePickerDescription' => 'Invia il test a un ricevitore AirPlay. Solo AirPlay riporta la modalità audio risolta.', 'settings.atmosTestStop' => 'Interrompi test', 'settings.atmosTestUrl' => 'URL del file di prova', 'settings.atmosTestUrlDescription' => 'URL HTTP di un file .ec3 Dolby Atmos grezzo (ad es. estratto con ffmpeg)', @@ -2690,6 +2713,8 @@ extension on TranslationsIt { 'videoControls.language' => 'Lingua', 'videoControls.noSubtitlesFound' => 'Nessun sottotitolo trovato', 'videoControls.noSubtitlesAvailable' => 'Nessun sottotitolo disponibile', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Nessuna traccia audio disponibile', 'videoControls.noTracksAvailable' => 'Nessuna traccia disponibile', 'videoControls.subtitleDownloaded' => 'Sottotitolo scaricato', @@ -2699,8 +2724,6 @@ extension on TranslationsIt { 'messages.markedAsWatched' => 'Segnato come visto', 'messages.markedAsUnwatched' => 'Segnato come non visto', 'messages.markedAsWatchedOffline' => 'Segnato come visto (verrà sincronizzato quando torni online)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Segnato come non visto (verrà sincronizzato quando torni online)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Rimosso automaticamente: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('it'))(n, one: 'Rimosso automaticamente ${n} download già visto', other: 'Rimossi automaticamente ${n} download già visti', ), @@ -3204,6 +3227,8 @@ extension on TranslationsIt { 'watchTogether.codeMustBe5Chars' => 'Il codice della sessione deve contenere 5 caratteri', 'watchTogether.joinInstructions' => 'Inserisci il codice della sessione dell\'host per partecipare.', 'watchTogether.failedToCreate' => 'Impossibile creare la sessione', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Impossibile unirsi alla sessione', 'watchTogether.sessionCodeCopied' => 'Codice della sessione copiato negli appunti', 'watchTogether.relayUnreachable' => 'Il server relay non è raggiungibile. Eventuali blocchi dell\'ISP potrebbero impedire l\'uso di Guarda insieme.', @@ -3213,8 +3238,6 @@ extension on TranslationsIt { 'watchTogether.joinCurrentPlaybackDescription' => 'Torna a ciò che l\'host sta guardando in questo momento', 'watchTogether.failedToOpenCurrentPlayback' => 'Impossibile aprire la riproduzione corrente', 'watchTogether.participantJoined' => ({required Object name}) => '${name} si è unito', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} se ne è andato', 'watchTogether.participantPaused' => ({required Object name}) => '${name} ha messo in pausa', 'watchTogether.participantResumed' => ({required Object name}) => '${name} ha ripreso', @@ -3413,6 +3436,11 @@ extension on TranslationsIt { 'videoSettings.audioOutput' => 'Uscita audio', 'videoSettings.performanceOverlay' => 'Overlay prestazioni', 'videoSettings.audioPassthrough' => 'Passthrough audio', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Surround', + 'videoSettings.audioOutputSpatial' => 'Audio spaziale', + 'videoSettings.audioOutputStereo' => 'Stereo', 'videoSettings.audioNormalization' => 'Normalizza il volume', 'videoSettings.audioDownmix' => 'Downmix in stereo', 'performanceOverlay.color' => 'Colore', diff --git a/lib/i18n/strings_ja.g.dart b/lib/i18n/strings_ja.g.dart index ef6a30fc..a5e2dd03 100644 --- a/lib/i18n/strings_ja.g.dart +++ b/lib/i18n/strings_ja.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$ja extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'プレイヤー内のAtmos再生と同じ方式でテストファイルをストリーミングします。テストファイルのURLが必要です。'; @override String get atmosTestRawFile => '生EAC3ファイル'; @override String get atmosTestRawFileDescription => '長さが既知のテストファイルを再生します。テストファイルのURLが必要です。'; + @override String get atmosTestAsbarNative => 'サンプルバッファレンダラー(ネイティブ)'; + @override String get atmosTestAsbarNativeDescription => 'ファイルの圧縮音声をそのままシステムのレンダラーに渡します。テストファイルのURLが必要です。'; + @override String get atmosTestAsbarGenerated => 'サンプルバッファレンダラー(再構築)'; + @override String get atmosTestAsbarGeneratedDescription => '同じですが、再生時と同じ方法で音声記述を再構築します。テストファイルのURLが必要です。'; + @override String get atmosTestSessionMode => 'ムービー再生モードを使用'; + @override String get atmosTestSessionModeDescription => 'オフはDolbyが文書化したモードを使用します。オンは以前のモードを使用します。'; + @override String get atmosTestShowRoutePicker => 'AirPlay出力を選択'; + @override String get atmosTestHideRoutePicker => 'AirPlay出力の選択を隠す'; + @override String get atmosTestRoutePickerDescription => 'テストをAirPlayレシーバーに送信します。解決された音声モードを報告するのはAirPlayのみです。'; @override String get atmosTestStop => 'テストを停止'; @override String get atmosTestUrl => 'テストファイルのURL'; @override String get atmosTestUrlDescription => '生の.ec3 Dolby AtmosファイルのHTTP URL(例: ffmpegで抽出)'; @@ -1511,6 +1520,11 @@ class _Translations$videoSettings$ja extends Translations$videoSettings$en { @override String get audioOutput => '音声出力'; @override String get performanceOverlay => 'パフォーマンスオーバーレイ'; @override String get audioPassthrough => 'オーディオパススルー'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'サラウンド'; + @override String get audioOutputSpatial => '空間オーディオ'; + @override String get audioOutputStereo => 'ステレオ'; @override String get audioNormalization => 'ラウドネス正規化'; @override String get audioDownmix => 'ステレオにダウンミックス'; } @@ -2460,6 +2474,15 @@ extension on TranslationsJa { 'settings.atmosTestRawStreamDescription' => 'プレイヤー内のAtmos再生と同じ方式でテストファイルをストリーミングします。テストファイルのURLが必要です。', 'settings.atmosTestRawFile' => '生EAC3ファイル', 'settings.atmosTestRawFileDescription' => '長さが既知のテストファイルを再生します。テストファイルのURLが必要です。', + 'settings.atmosTestAsbarNative' => 'サンプルバッファレンダラー(ネイティブ)', + 'settings.atmosTestAsbarNativeDescription' => 'ファイルの圧縮音声をそのままシステムのレンダラーに渡します。テストファイルのURLが必要です。', + 'settings.atmosTestAsbarGenerated' => 'サンプルバッファレンダラー(再構築)', + 'settings.atmosTestAsbarGeneratedDescription' => '同じですが、再生時と同じ方法で音声記述を再構築します。テストファイルのURLが必要です。', + 'settings.atmosTestSessionMode' => 'ムービー再生モードを使用', + 'settings.atmosTestSessionModeDescription' => 'オフはDolbyが文書化したモードを使用します。オンは以前のモードを使用します。', + 'settings.atmosTestShowRoutePicker' => 'AirPlay出力を選択', + 'settings.atmosTestHideRoutePicker' => 'AirPlay出力の選択を隠す', + 'settings.atmosTestRoutePickerDescription' => 'テストをAirPlayレシーバーに送信します。解決された音声モードを報告するのはAirPlayのみです。', 'settings.atmosTestStop' => 'テストを停止', 'settings.atmosTestUrl' => 'テストファイルのURL', 'settings.atmosTestUrlDescription' => '生の.ec3 Dolby AtmosファイルのHTTP URL(例: ffmpegで抽出)', @@ -2687,6 +2710,8 @@ extension on TranslationsJa { 'videoControls.language' => '言語', 'videoControls.noSubtitlesFound' => '字幕が見つかりません', 'videoControls.noSubtitlesAvailable' => '利用可能な字幕はありません', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => '利用可能な音声トラックはありません', 'videoControls.noTracksAvailable' => '利用可能なトラックはありません', 'videoControls.subtitleDownloaded' => '字幕をダウンロードしました', @@ -2696,8 +2721,6 @@ extension on TranslationsJa { 'messages.markedAsWatched' => '視聴済みにしました', 'messages.markedAsUnwatched' => '未視聴にしました', 'messages.markedAsWatchedOffline' => '視聴済みにしました(オンライン時に同期)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => '未視聴にしました(オンライン時に同期)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => '自動削除: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ja'))(n, other: '視聴済みダウンロードを${n}件自動削除しました', ), @@ -3201,6 +3224,8 @@ extension on TranslationsJa { 'watchTogether.codeMustBe5Chars' => 'セッションコードは5文字である必要があります', 'watchTogether.joinInstructions' => '参加するにはホストのセッションコードを入力してください。', 'watchTogether.failedToCreate' => 'セッションの作成に失敗しました', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'セッションへの参加に失敗しました', 'watchTogether.sessionCodeCopied' => 'セッションコードをクリップボードにコピーしました', 'watchTogether.relayUnreachable' => 'リレーサーバーに接続できません。ISPによるブロックのため「一緒に見る」を利用できない可能性があります。', @@ -3210,8 +3235,6 @@ extension on TranslationsJa { 'watchTogether.joinCurrentPlaybackDescription' => 'ホストが現在視聴中のコンテンツに戻る', 'watchTogether.failedToOpenCurrentPlayback' => '現在の再生を開けませんでした', 'watchTogether.participantJoined' => ({required Object name}) => '${name}が参加しました', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name}が退出しました', 'watchTogether.participantPaused' => ({required Object name}) => '${name}が一時停止しました', 'watchTogether.participantResumed' => ({required Object name}) => '${name}が再開しました', @@ -3410,6 +3433,11 @@ extension on TranslationsJa { 'videoSettings.audioOutput' => '音声出力', 'videoSettings.performanceOverlay' => 'パフォーマンスオーバーレイ', 'videoSettings.audioPassthrough' => 'オーディオパススルー', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'サラウンド', + 'videoSettings.audioOutputSpatial' => '空間オーディオ', + 'videoSettings.audioOutputStereo' => 'ステレオ', 'videoSettings.audioNormalization' => 'ラウドネス正規化', 'videoSettings.audioDownmix' => 'ステレオにダウンミックス', 'performanceOverlay.color' => '色', diff --git a/lib/i18n/strings_ko.g.dart b/lib/i18n/strings_ko.g.dart index 711b0f40..99072423 100644 --- a/lib/i18n/strings_ko.g.dart +++ b/lib/i18n/strings_ko.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$ko extends Translations$settings$en { @override String get atmosTestRawStreamDescription => '플레이어 내 Atmos 재생과 동일한 방식으로 테스트 파일을 스트리밍합니다. 테스트 파일 URL이 필요합니다.'; @override String get atmosTestRawFile => '원시 EAC3 파일'; @override String get atmosTestRawFileDescription => '길이가 알려진 테스트 파일을 재생합니다. 테스트 파일 URL이 필요합니다.'; + @override String get atmosTestAsbarNative => '샘플 버퍼 렌더러(네이티브)'; + @override String get atmosTestAsbarNativeDescription => '파일의 압축 오디오를 그대로 시스템 렌더러에 전달합니다. 테스트 파일 URL이 필요합니다.'; + @override String get atmosTestAsbarGenerated => '샘플 버퍼 렌더러(재구성)'; + @override String get atmosTestAsbarGeneratedDescription => '동일하지만 오디오 설명을 재생과 같은 방식으로 재구성합니다. 테스트 파일 URL이 필요합니다.'; + @override String get atmosTestSessionMode => '동영상 재생 세션 모드 사용'; + @override String get atmosTestSessionModeDescription => '끄면 Dolby가 문서화한 모드를 사용합니다. 켜면 이전 모드를 사용합니다.'; + @override String get atmosTestShowRoutePicker => 'AirPlay 출력 선택'; + @override String get atmosTestHideRoutePicker => 'AirPlay 출력 선택기 숨기기'; + @override String get atmosTestRoutePickerDescription => '테스트를 AirPlay 수신기로 보냅니다. 확인된 오디오 모드는 AirPlay에서만 보고됩니다.'; @override String get atmosTestStop => '테스트 중지'; @override String get atmosTestUrl => '테스트 파일 URL'; @override String get atmosTestUrlDescription => '원시 .ec3 Dolby Atmos 파일의 HTTP URL(예: ffmpeg로 추출)'; @@ -1511,6 +1520,11 @@ class _Translations$videoSettings$ko extends Translations$videoSettings$en { @override String get audioOutput => '오디오 출력'; @override String get performanceOverlay => '성능 오버레이'; @override String get audioPassthrough => '오디오 패스스루'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => '서라운드'; + @override String get audioOutputSpatial => '공간 음향'; + @override String get audioOutputStereo => '스테레오'; @override String get audioNormalization => '음량 정규화'; @override String get audioDownmix => '스테레오로 다운믹스'; } @@ -2460,6 +2474,15 @@ extension on TranslationsKo { 'settings.atmosTestRawStreamDescription' => '플레이어 내 Atmos 재생과 동일한 방식으로 테스트 파일을 스트리밍합니다. 테스트 파일 URL이 필요합니다.', 'settings.atmosTestRawFile' => '원시 EAC3 파일', 'settings.atmosTestRawFileDescription' => '길이가 알려진 테스트 파일을 재생합니다. 테스트 파일 URL이 필요합니다.', + 'settings.atmosTestAsbarNative' => '샘플 버퍼 렌더러(네이티브)', + 'settings.atmosTestAsbarNativeDescription' => '파일의 압축 오디오를 그대로 시스템 렌더러에 전달합니다. 테스트 파일 URL이 필요합니다.', + 'settings.atmosTestAsbarGenerated' => '샘플 버퍼 렌더러(재구성)', + 'settings.atmosTestAsbarGeneratedDescription' => '동일하지만 오디오 설명을 재생과 같은 방식으로 재구성합니다. 테스트 파일 URL이 필요합니다.', + 'settings.atmosTestSessionMode' => '동영상 재생 세션 모드 사용', + 'settings.atmosTestSessionModeDescription' => '끄면 Dolby가 문서화한 모드를 사용합니다. 켜면 이전 모드를 사용합니다.', + 'settings.atmosTestShowRoutePicker' => 'AirPlay 출력 선택', + 'settings.atmosTestHideRoutePicker' => 'AirPlay 출력 선택기 숨기기', + 'settings.atmosTestRoutePickerDescription' => '테스트를 AirPlay 수신기로 보냅니다. 확인된 오디오 모드는 AirPlay에서만 보고됩니다.', 'settings.atmosTestStop' => '테스트 중지', 'settings.atmosTestUrl' => '테스트 파일 URL', 'settings.atmosTestUrlDescription' => '원시 .ec3 Dolby Atmos 파일의 HTTP URL(예: ffmpeg로 추출)', @@ -2687,6 +2710,8 @@ extension on TranslationsKo { 'videoControls.language' => '언어', 'videoControls.noSubtitlesFound' => '자막을 찾을 수 없습니다', 'videoControls.noSubtitlesAvailable' => '사용 가능한 자막 없음', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => '사용 가능한 오디오 트랙 없음', 'videoControls.noTracksAvailable' => '사용 가능한 트랙 없음', 'videoControls.subtitleDownloaded' => '자막이 다운로드되었습니다', @@ -2696,8 +2721,6 @@ extension on TranslationsKo { 'messages.markedAsWatched' => '시청 완료로 표시됨', 'messages.markedAsUnwatched' => '미시청으로 표시됨', 'messages.markedAsWatchedOffline' => '시청 완료로 표시됨 (연결 시 동기화됨)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => '미시청으로 표시됨 (연결 시 동기화됨)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => '자동 삭제됨: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ko'))(n, other: '시청한 다운로드 ${n}개를 자동 삭제했습니다', ), @@ -3201,6 +3224,8 @@ extension on TranslationsKo { 'watchTogether.codeMustBe5Chars' => '세션 코드는 반드시 5자리여야 합니다', 'watchTogether.joinInstructions' => '참여하려면 호스트의 세션 코드를 입력하세요.', 'watchTogether.failedToCreate' => '세션 생성 실패', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => '세션 참여 실패', 'watchTogether.sessionCodeCopied' => '세션 코드가 클립보드에 복사되었습니다', 'watchTogether.relayUnreachable' => '릴레이 서버에 연결할 수 없습니다. ISP 차단으로 함께 보기를 사용하지 못할 수 있습니다.', @@ -3210,8 +3235,6 @@ extension on TranslationsKo { 'watchTogether.joinCurrentPlaybackDescription' => '호스트가 현재 시청 중인 콘텐츠로 이동합니다', 'watchTogether.failedToOpenCurrentPlayback' => '현재 재생을 열 수 없습니다', 'watchTogether.participantJoined' => ({required Object name}) => '${name}님이 참여했습니다', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name}님이 나갔습니다', 'watchTogether.participantPaused' => ({required Object name}) => '${name}님이 일시정지했습니다', 'watchTogether.participantResumed' => ({required Object name}) => '${name}님이 재생했습니다', @@ -3410,6 +3433,11 @@ extension on TranslationsKo { 'videoSettings.audioOutput' => '오디오 출력', 'videoSettings.performanceOverlay' => '성능 오버레이', 'videoSettings.audioPassthrough' => '오디오 패스스루', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => '서라운드', + 'videoSettings.audioOutputSpatial' => '공간 음향', + 'videoSettings.audioOutputStereo' => '스테레오', 'videoSettings.audioNormalization' => '음량 정규화', 'videoSettings.audioDownmix' => '스테레오로 다운믹스', 'performanceOverlay.color' => '색상', diff --git a/lib/i18n/strings_nb.g.dart b/lib/i18n/strings_nb.g.dart index fd565cf7..7a6ca5d6 100644 --- a/lib/i18n/strings_nb.g.dart +++ b/lib/i18n/strings_nb.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$nb extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Strømmer testfilen akkurat som Atmos-avspilling i spilleren. Krever testfilens URL.'; @override String get atmosTestRawFile => 'Rå EAC3-fil'; @override String get atmosTestRawFileDescription => 'Spiller av testfilen med kjent lengde. Krever testfilens URL.'; + @override String get atmosTestAsbarNative => 'Sample-buffer-renderer (nativ)'; + @override String get atmosTestAsbarNativeDescription => 'Sender filens urørte komprimerte lyd rett til systemets renderer. Krever URL til testfilen.'; + @override String get atmosTestAsbarGenerated => 'Sample-buffer-renderer (gjenoppbygd)'; + @override String get atmosTestAsbarGeneratedDescription => 'Det samme, men med lydbeskrivelsen bygd slik avspilling bygger den. Krever URL til testfilen.'; + @override String get atmosTestSessionMode => 'Bruk filmavspillingsmodus'; + @override String get atmosTestSessionModeDescription => 'Av bruker modusen Dolby dokumenterer. På bruker den tidligere modusen.'; + @override String get atmosTestShowRoutePicker => 'Velg AirPlay-utgang'; + @override String get atmosTestHideRoutePicker => 'Skjul AirPlay-utgangsvelger'; + @override String get atmosTestRoutePickerDescription => 'Sender testen til en AirPlay-mottaker. Bare AirPlay rapporterer den valgte lydmodusen.'; @override String get atmosTestStop => 'Stopp test'; @override String get atmosTestUrl => 'Testfilens URL'; @override String get atmosTestUrlDescription => 'HTTP-URL til en rå .ec3 Dolby Atmos-fil (f.eks. hentet ut med ffmpeg)'; @@ -1514,6 +1523,11 @@ class _Translations$videoSettings$nb extends Translations$videoSettings$en { @override String get audioOutput => 'Lydutgang'; @override String get performanceOverlay => 'Ytelsesoverlegg'; @override String get audioPassthrough => 'Direkte lydutgang'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Surround'; + @override String get audioOutputSpatial => 'Romlig lyd'; + @override String get audioOutputStereo => 'Stereo'; @override String get audioNormalization => 'Normaliser lydstyrke'; @override String get audioDownmix => 'Nedmiks til stereo'; } @@ -2463,6 +2477,15 @@ extension on TranslationsNb { 'settings.atmosTestRawStreamDescription' => 'Strømmer testfilen akkurat som Atmos-avspilling i spilleren. Krever testfilens URL.', 'settings.atmosTestRawFile' => 'Rå EAC3-fil', 'settings.atmosTestRawFileDescription' => 'Spiller av testfilen med kjent lengde. Krever testfilens URL.', + 'settings.atmosTestAsbarNative' => 'Sample-buffer-renderer (nativ)', + 'settings.atmosTestAsbarNativeDescription' => 'Sender filens urørte komprimerte lyd rett til systemets renderer. Krever URL til testfilen.', + 'settings.atmosTestAsbarGenerated' => 'Sample-buffer-renderer (gjenoppbygd)', + 'settings.atmosTestAsbarGeneratedDescription' => 'Det samme, men med lydbeskrivelsen bygd slik avspilling bygger den. Krever URL til testfilen.', + 'settings.atmosTestSessionMode' => 'Bruk filmavspillingsmodus', + 'settings.atmosTestSessionModeDescription' => 'Av bruker modusen Dolby dokumenterer. På bruker den tidligere modusen.', + 'settings.atmosTestShowRoutePicker' => 'Velg AirPlay-utgang', + 'settings.atmosTestHideRoutePicker' => 'Skjul AirPlay-utgangsvelger', + 'settings.atmosTestRoutePickerDescription' => 'Sender testen til en AirPlay-mottaker. Bare AirPlay rapporterer den valgte lydmodusen.', 'settings.atmosTestStop' => 'Stopp test', 'settings.atmosTestUrl' => 'Testfilens URL', 'settings.atmosTestUrlDescription' => 'HTTP-URL til en rå .ec3 Dolby Atmos-fil (f.eks. hentet ut med ffmpeg)', @@ -2690,6 +2713,8 @@ extension on TranslationsNb { 'videoControls.language' => 'Språk', 'videoControls.noSubtitlesFound' => 'Ingen undertekster funnet', 'videoControls.noSubtitlesAvailable' => 'Ingen undertekster tilgjengelig', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Ingen lydspor tilgjengelig', 'videoControls.noTracksAvailable' => 'Ingen spor tilgjengelig', 'videoControls.subtitleDownloaded' => 'Undertekst lastet ned', @@ -2699,8 +2724,6 @@ extension on TranslationsNb { 'messages.markedAsWatched' => 'Merket som sett', 'messages.markedAsUnwatched' => 'Merket som usett', 'messages.markedAsWatchedOffline' => 'Merket som sett (synkroniseres når tilkoblet)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Merket som usett (synkroniseres når tilkoblet)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Automatisk fjernet: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('nb'))(n, one: 'Fjernet automatisk ${n} avspilt nedlasting', other: 'Fjernet automatisk ${n} avspilte nedlastinger', ), @@ -3204,6 +3227,8 @@ extension on TranslationsNb { 'watchTogether.codeMustBe5Chars' => 'Øktkoden må være 5 tegn', 'watchTogether.joinInstructions' => 'Skriv inn vertens øktkode for å bli med.', 'watchTogether.failedToCreate' => 'Kunne ikke opprette økt', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Kunne ikke bli med i økt', 'watchTogether.sessionCodeCopied' => 'Øktkode kopiert til utklippstavle', 'watchTogether.relayUnreachable' => 'Reléserveren kan ikke nås. Blokkering hos internettleverandøren kan hindre Se sammen.', @@ -3213,8 +3238,6 @@ extension on TranslationsNb { 'watchTogether.joinCurrentPlaybackDescription' => 'Hopp tilbake til det verten ser på nå', 'watchTogether.failedToOpenCurrentPlayback' => 'Kunne ikke åpne gjeldende avspilling', 'watchTogether.participantJoined' => ({required Object name}) => '${name} ble med', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} forlot', 'watchTogether.participantPaused' => ({required Object name}) => '${name} satte avspillingen på pause', 'watchTogether.participantResumed' => ({required Object name}) => '${name} startet avspillingen igjen', @@ -3413,6 +3436,11 @@ extension on TranslationsNb { 'videoSettings.audioOutput' => 'Lydutgang', 'videoSettings.performanceOverlay' => 'Ytelsesoverlegg', 'videoSettings.audioPassthrough' => 'Direkte lydutgang', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Surround', + 'videoSettings.audioOutputSpatial' => 'Romlig lyd', + 'videoSettings.audioOutputStereo' => 'Stereo', 'videoSettings.audioNormalization' => 'Normaliser lydstyrke', 'videoSettings.audioDownmix' => 'Nedmiks til stereo', 'performanceOverlay.color' => 'Farge', diff --git a/lib/i18n/strings_nl.g.dart b/lib/i18n/strings_nl.g.dart index 41ea0c1d..81d1b172 100644 --- a/lib/i18n/strings_nl.g.dart +++ b/lib/i18n/strings_nl.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$nl extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Streamt het testbestand precies zoals Atmos-weergave in de speler. Vereist de URL van het testbestand.'; @override String get atmosTestRawFile => 'Ruw EAC3-bestand'; @override String get atmosTestRawFileDescription => 'Speelt het testbestand met bekende lengte af. Vereist de URL van het testbestand.'; + @override String get atmosTestAsbarNative => 'Sample-bufferrenderer (native)'; + @override String get atmosTestAsbarNativeDescription => 'Stuurt de ongewijzigde gecomprimeerde audio van het bestand rechtstreeks naar de systeemrenderer. Vereist de URL van het testbestand.'; + @override String get atmosTestAsbarGenerated => 'Sample-bufferrenderer (opnieuw opgebouwd)'; + @override String get atmosTestAsbarGeneratedDescription => 'Hetzelfde, maar met de audiobeschrijving opgebouwd zoals bij afspelen. Vereist de URL van het testbestand.'; + @override String get atmosTestSessionMode => 'Filmafspeelmodus gebruiken'; + @override String get atmosTestSessionModeDescription => 'Uit gebruikt de modus die Dolby documenteert. Aan gebruikt de vorige modus.'; + @override String get atmosTestShowRoutePicker => 'AirPlay-uitvoer kiezen'; + @override String get atmosTestHideRoutePicker => 'AirPlay-uitvoerkiezer verbergen'; + @override String get atmosTestRoutePickerDescription => 'Stuurt de test naar een AirPlay-ontvanger. Alleen AirPlay meldt de bepaalde audiomodus.'; @override String get atmosTestStop => 'Test stoppen'; @override String get atmosTestUrl => 'URL van testbestand'; @override String get atmosTestUrlDescription => 'HTTP-URL van een ruw .ec3 Dolby Atmos-bestand (bijv. uitgepakt met ffmpeg)'; @@ -1514,6 +1523,11 @@ class _Translations$videoSettings$nl extends Translations$videoSettings$en { @override String get audioOutput => 'Audio-uitvoer'; @override String get performanceOverlay => 'Prestatie-overlay'; @override String get audioPassthrough => 'Audio-doorvoer'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Surround'; + @override String get audioOutputSpatial => 'Ruimtelijke audio'; + @override String get audioOutputStereo => 'Stereo'; @override String get audioNormalization => 'Volume normaliseren'; @override String get audioDownmix => 'Downmixen naar stereo'; } @@ -2463,6 +2477,15 @@ extension on TranslationsNl { 'settings.atmosTestRawStreamDescription' => 'Streamt het testbestand precies zoals Atmos-weergave in de speler. Vereist de URL van het testbestand.', 'settings.atmosTestRawFile' => 'Ruw EAC3-bestand', 'settings.atmosTestRawFileDescription' => 'Speelt het testbestand met bekende lengte af. Vereist de URL van het testbestand.', + 'settings.atmosTestAsbarNative' => 'Sample-bufferrenderer (native)', + 'settings.atmosTestAsbarNativeDescription' => 'Stuurt de ongewijzigde gecomprimeerde audio van het bestand rechtstreeks naar de systeemrenderer. Vereist de URL van het testbestand.', + 'settings.atmosTestAsbarGenerated' => 'Sample-bufferrenderer (opnieuw opgebouwd)', + 'settings.atmosTestAsbarGeneratedDescription' => 'Hetzelfde, maar met de audiobeschrijving opgebouwd zoals bij afspelen. Vereist de URL van het testbestand.', + 'settings.atmosTestSessionMode' => 'Filmafspeelmodus gebruiken', + 'settings.atmosTestSessionModeDescription' => 'Uit gebruikt de modus die Dolby documenteert. Aan gebruikt de vorige modus.', + 'settings.atmosTestShowRoutePicker' => 'AirPlay-uitvoer kiezen', + 'settings.atmosTestHideRoutePicker' => 'AirPlay-uitvoerkiezer verbergen', + 'settings.atmosTestRoutePickerDescription' => 'Stuurt de test naar een AirPlay-ontvanger. Alleen AirPlay meldt de bepaalde audiomodus.', 'settings.atmosTestStop' => 'Test stoppen', 'settings.atmosTestUrl' => 'URL van testbestand', 'settings.atmosTestUrlDescription' => 'HTTP-URL van een ruw .ec3 Dolby Atmos-bestand (bijv. uitgepakt met ffmpeg)', @@ -2690,6 +2713,8 @@ extension on TranslationsNl { 'videoControls.language' => 'Taal', 'videoControls.noSubtitlesFound' => 'Geen ondertitels gevonden', 'videoControls.noSubtitlesAvailable' => 'Geen ondertitels beschikbaar', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Geen audiotracks beschikbaar', 'videoControls.noTracksAvailable' => 'Geen tracks beschikbaar', 'videoControls.subtitleDownloaded' => 'Ondertitel gedownload', @@ -2699,8 +2724,6 @@ extension on TranslationsNl { 'messages.markedAsWatched' => 'Gemarkeerd als gekeken', 'messages.markedAsUnwatched' => 'Gemarkeerd als ongekeken', 'messages.markedAsWatchedOffline' => 'Gemarkeerd als bekeken (wordt gesynchroniseerd zodra je online bent)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Gemarkeerd als ongekeken (wordt gesynchroniseerd zodra je online bent)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Automatisch verwijderd: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('nl'))(n, one: 'Automatisch ${n} bekeken download verwijderd', other: 'Automatisch ${n} bekeken downloads verwijderd', ), @@ -3204,6 +3227,8 @@ extension on TranslationsNl { 'watchTogether.codeMustBe5Chars' => 'De sessiecode moet 5 tekens lang zijn', 'watchTogether.joinInstructions' => 'Voer de sessiecode van de host in om deel te nemen.', 'watchTogether.failedToCreate' => 'Sessie maken mislukt', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Deelnemen aan sessie mislukt', 'watchTogether.sessionCodeCopied' => 'Sessiecode naar het klembord gekopieerd', 'watchTogether.relayUnreachable' => 'De relayserver is onbereikbaar. Een blokkering door je internetprovider kan Samen kijken verhinderen.', @@ -3213,8 +3238,6 @@ extension on TranslationsNl { 'watchTogether.joinCurrentPlaybackDescription' => 'Ga terug naar wat de host nu kijkt', 'watchTogether.failedToOpenCurrentPlayback' => 'Wat nu wordt afgespeeld kon niet worden geopend', 'watchTogether.participantJoined' => ({required Object name}) => '${name} is toegetreden', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} heeft de sessie verlaten', 'watchTogether.participantPaused' => ({required Object name}) => '${name} heeft gepauzeerd', 'watchTogether.participantResumed' => ({required Object name}) => '${name} heeft hervat', @@ -3413,6 +3436,11 @@ extension on TranslationsNl { 'videoSettings.audioOutput' => 'Audio-uitvoer', 'videoSettings.performanceOverlay' => 'Prestatie-overlay', 'videoSettings.audioPassthrough' => 'Audio-doorvoer', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Surround', + 'videoSettings.audioOutputSpatial' => 'Ruimtelijke audio', + 'videoSettings.audioOutputStereo' => 'Stereo', 'videoSettings.audioNormalization' => 'Volume normaliseren', 'videoSettings.audioDownmix' => 'Downmixen naar stereo', 'performanceOverlay.color' => 'Kleur', diff --git a/lib/i18n/strings_pl.g.dart b/lib/i18n/strings_pl.g.dart index a1d23e2f..c7730b47 100644 --- a/lib/i18n/strings_pl.g.dart +++ b/lib/i18n/strings_pl.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$pl extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Przesyła strumieniowo plik testowy dokładnie tak jak podczas odtwarzania Atmos w odtwarzaczu. Wymaga adresu URL pliku testowego.'; @override String get atmosTestRawFile => 'Surowy plik EAC3'; @override String get atmosTestRawFileDescription => 'Odtwarza plik testowy o znanej długości. Wymaga URL pliku testowego.'; + @override String get atmosTestAsbarNative => 'Renderer bufora próbek (natywny)'; + @override String get atmosTestAsbarNativeDescription => 'Przekazuje nienaruszony skompresowany dźwięk pliku prosto do renderera systemu. Wymaga URL pliku testowego.'; + @override String get atmosTestAsbarGenerated => 'Renderer bufora próbek (odtworzony)'; + @override String get atmosTestAsbarGeneratedDescription => 'To samo, ale z opisem dźwięku budowanym tak jak przy odtwarzaniu. Wymaga URL pliku testowego.'; + @override String get atmosTestSessionMode => 'Użyj trybu odtwarzania filmów'; + @override String get atmosTestSessionModeDescription => 'Wyłączone używa trybu udokumentowanego przez Dolby. Włączone używa poprzedniego trybu.'; + @override String get atmosTestShowRoutePicker => 'Wybierz wyjście AirPlay'; + @override String get atmosTestHideRoutePicker => 'Ukryj wybór wyjścia AirPlay'; + @override String get atmosTestRoutePickerDescription => 'Wysyła test do odbiornika AirPlay. Tylko AirPlay zgłasza ustalony tryb dźwięku.'; @override String get atmosTestStop => 'Zatrzymaj test'; @override String get atmosTestUrl => 'Adres URL pliku testowego'; @override String get atmosTestUrlDescription => 'Adres URL HTTP surowego pliku Dolby Atmos w formacie .ec3 (np. wyodrębnionego za pomocą ffmpeg)'; @@ -1520,6 +1529,11 @@ class _Translations$videoSettings$pl extends Translations$videoSettings$en { @override String get audioOutput => 'Wyjście audio'; @override String get performanceOverlay => 'Nakładka wydajności'; @override String get audioPassthrough => 'Przekazywanie dźwięku'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Przestrzenny'; + @override String get audioOutputSpatial => 'Dźwięk przestrzenny'; + @override String get audioOutputStereo => 'Stereo'; @override String get audioNormalization => 'Normalizacja głośności'; @override String get audioDownmix => 'Miksowanie do stereo'; } @@ -2469,6 +2483,15 @@ extension on TranslationsPl { 'settings.atmosTestRawStreamDescription' => 'Przesyła strumieniowo plik testowy dokładnie tak jak podczas odtwarzania Atmos w odtwarzaczu. Wymaga adresu URL pliku testowego.', 'settings.atmosTestRawFile' => 'Surowy plik EAC3', 'settings.atmosTestRawFileDescription' => 'Odtwarza plik testowy o znanej długości. Wymaga URL pliku testowego.', + 'settings.atmosTestAsbarNative' => 'Renderer bufora próbek (natywny)', + 'settings.atmosTestAsbarNativeDescription' => 'Przekazuje nienaruszony skompresowany dźwięk pliku prosto do renderera systemu. Wymaga URL pliku testowego.', + 'settings.atmosTestAsbarGenerated' => 'Renderer bufora próbek (odtworzony)', + 'settings.atmosTestAsbarGeneratedDescription' => 'To samo, ale z opisem dźwięku budowanym tak jak przy odtwarzaniu. Wymaga URL pliku testowego.', + 'settings.atmosTestSessionMode' => 'Użyj trybu odtwarzania filmów', + 'settings.atmosTestSessionModeDescription' => 'Wyłączone używa trybu udokumentowanego przez Dolby. Włączone używa poprzedniego trybu.', + 'settings.atmosTestShowRoutePicker' => 'Wybierz wyjście AirPlay', + 'settings.atmosTestHideRoutePicker' => 'Ukryj wybór wyjścia AirPlay', + 'settings.atmosTestRoutePickerDescription' => 'Wysyła test do odbiornika AirPlay. Tylko AirPlay zgłasza ustalony tryb dźwięku.', 'settings.atmosTestStop' => 'Zatrzymaj test', 'settings.atmosTestUrl' => 'Adres URL pliku testowego', 'settings.atmosTestUrlDescription' => 'Adres URL HTTP surowego pliku Dolby Atmos w formacie .ec3 (np. wyodrębnionego za pomocą ffmpeg)', @@ -2696,6 +2719,8 @@ extension on TranslationsPl { 'videoControls.language' => 'Język', 'videoControls.noSubtitlesFound' => 'Nie znaleziono napisów', 'videoControls.noSubtitlesAvailable' => 'Brak dostępnych napisów', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Brak dostępnych ścieżek audio', 'videoControls.noTracksAvailable' => 'Brak dostępnych ścieżek', 'videoControls.subtitleDownloaded' => 'Napisy pobrane', @@ -2705,8 +2730,6 @@ extension on TranslationsPl { 'messages.markedAsWatched' => 'Oznaczono jako obejrzane', 'messages.markedAsUnwatched' => 'Oznaczono jako nieobejrzane', 'messages.markedAsWatchedOffline' => 'Oznaczono jako obejrzane (zsynchronizuje się po połączeniu)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Oznaczono jako nieobejrzane (zsynchronizuje się po połączeniu)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Automatycznie usunięto: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('pl'))(n, one: 'Automatycznie usunięto ${n} obejrzane pobranie', few: 'Automatycznie usunięto ${n} obejrzane pobrania', many: 'Automatycznie usunięto ${n} obejrzanych pobrań', other: 'Automatycznie usunięto ${n} obejrzanego pobrania', ), @@ -3210,6 +3233,8 @@ extension on TranslationsPl { 'watchTogether.codeMustBe5Chars' => 'Kod sesji musi mieć 5 znaków', 'watchTogether.joinInstructions' => 'Wpisz kod sesji hosta, aby dołączyć.', 'watchTogether.failedToCreate' => 'Nie udało się utworzyć sesji', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Nie udało się dołączyć do sesji', 'watchTogether.sessionCodeCopied' => 'Kod sesji skopiowany do schowka', 'watchTogether.relayUnreachable' => 'Serwer pośredniczący jest nieosiągalny. Blokada operatora internetowego może uniemożliwiać korzystanie z funkcji „Oglądaj razem”.', @@ -3219,8 +3244,6 @@ extension on TranslationsPl { 'watchTogether.joinCurrentPlaybackDescription' => 'Wróć do treści oglądanej obecnie przez gospodarza', 'watchTogether.failedToOpenCurrentPlayback' => 'Nie udało się otworzyć bieżącego odtwarzania', 'watchTogether.participantJoined' => ({required Object name}) => '${name} dołączył', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} opuścił', 'watchTogether.participantPaused' => ({required Object name}) => '${name} wstrzymał', 'watchTogether.participantResumed' => ({required Object name}) => '${name} wznowił', @@ -3419,6 +3442,11 @@ extension on TranslationsPl { 'videoSettings.audioOutput' => 'Wyjście audio', 'videoSettings.performanceOverlay' => 'Nakładka wydajności', 'videoSettings.audioPassthrough' => 'Przekazywanie dźwięku', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Przestrzenny', + 'videoSettings.audioOutputSpatial' => 'Dźwięk przestrzenny', + 'videoSettings.audioOutputStereo' => 'Stereo', 'videoSettings.audioNormalization' => 'Normalizacja głośności', 'videoSettings.audioDownmix' => 'Miksowanie do stereo', 'performanceOverlay.color' => 'Kolor', diff --git a/lib/i18n/strings_pt.g.dart b/lib/i18n/strings_pt.g.dart index 277756ac..38d885ea 100644 --- a/lib/i18n/strings_pt.g.dart +++ b/lib/i18n/strings_pt.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$pt extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Transmite o arquivo de teste exatamente como na reprodução Atmos pelo reprodutor. Requer a URL do arquivo de teste.'; @override String get atmosTestRawFile => 'Arquivo EAC3 bruto'; @override String get atmosTestRawFileDescription => 'Reproduz o arquivo de teste com duração conhecida. Requer a URL do arquivo de teste.'; + @override String get atmosTestAsbarNative => 'Renderizador de buffer de amostras (nativo)'; + @override String get atmosTestAsbarNativeDescription => 'Envia o áudio comprimido intacto do ficheiro diretamente para o renderizador do sistema. Requer o URL do ficheiro de teste.'; + @override String get atmosTestAsbarGenerated => 'Renderizador de buffer de amostras (reconstruído)'; + @override String get atmosTestAsbarGeneratedDescription => 'O mesmo, mas com a descrição de áudio construída como na reprodução. Requer o URL do ficheiro de teste.'; + @override String get atmosTestSessionMode => 'Usar modo de reprodução de filmes'; + @override String get atmosTestSessionModeDescription => 'Desativado usa o modo documentado pela Dolby. Ativado usa o modo anterior.'; + @override String get atmosTestShowRoutePicker => 'Escolher saída AirPlay'; + @override String get atmosTestHideRoutePicker => 'Ocultar seletor de saída AirPlay'; + @override String get atmosTestRoutePickerDescription => 'Envia o teste para um recetor AirPlay. Só o AirPlay comunica o modo de áudio resolvido.'; @override String get atmosTestStop => 'Parar teste'; @override String get atmosTestUrl => 'URL do arquivo de teste'; @override String get atmosTestUrlDescription => 'URL HTTP de um arquivo .ec3 Dolby Atmos bruto (ex.: extraído com ffmpeg)'; @@ -1514,6 +1523,11 @@ class _Translations$videoSettings$pt extends Translations$videoSettings$en { @override String get audioOutput => 'Saída de áudio'; @override String get performanceOverlay => 'Painel de desempenho'; @override String get audioPassthrough => 'Passagem direta de áudio'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Surround'; + @override String get audioOutputSpatial => 'Áudio espacial'; + @override String get audioOutputStereo => 'Estéreo'; @override String get audioNormalization => 'Normalizar intensidade sonora'; @override String get audioDownmix => 'Conversão para estéreo'; } @@ -2463,6 +2477,15 @@ extension on TranslationsPt { 'settings.atmosTestRawStreamDescription' => 'Transmite o arquivo de teste exatamente como na reprodução Atmos pelo reprodutor. Requer a URL do arquivo de teste.', 'settings.atmosTestRawFile' => 'Arquivo EAC3 bruto', 'settings.atmosTestRawFileDescription' => 'Reproduz o arquivo de teste com duração conhecida. Requer a URL do arquivo de teste.', + 'settings.atmosTestAsbarNative' => 'Renderizador de buffer de amostras (nativo)', + 'settings.atmosTestAsbarNativeDescription' => 'Envia o áudio comprimido intacto do ficheiro diretamente para o renderizador do sistema. Requer o URL do ficheiro de teste.', + 'settings.atmosTestAsbarGenerated' => 'Renderizador de buffer de amostras (reconstruído)', + 'settings.atmosTestAsbarGeneratedDescription' => 'O mesmo, mas com a descrição de áudio construída como na reprodução. Requer o URL do ficheiro de teste.', + 'settings.atmosTestSessionMode' => 'Usar modo de reprodução de filmes', + 'settings.atmosTestSessionModeDescription' => 'Desativado usa o modo documentado pela Dolby. Ativado usa o modo anterior.', + 'settings.atmosTestShowRoutePicker' => 'Escolher saída AirPlay', + 'settings.atmosTestHideRoutePicker' => 'Ocultar seletor de saída AirPlay', + 'settings.atmosTestRoutePickerDescription' => 'Envia o teste para um recetor AirPlay. Só o AirPlay comunica o modo de áudio resolvido.', 'settings.atmosTestStop' => 'Parar teste', 'settings.atmosTestUrl' => 'URL do arquivo de teste', 'settings.atmosTestUrlDescription' => 'URL HTTP de um arquivo .ec3 Dolby Atmos bruto (ex.: extraído com ffmpeg)', @@ -2690,6 +2713,8 @@ extension on TranslationsPt { 'videoControls.language' => 'Idioma', 'videoControls.noSubtitlesFound' => 'Nenhuma legenda encontrada', 'videoControls.noSubtitlesAvailable' => 'Nenhuma legenda disponível', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Nenhuma faixa de áudio disponível', 'videoControls.noTracksAvailable' => 'Nenhuma faixa disponível', 'videoControls.subtitleDownloaded' => 'Legenda baixada', @@ -2699,8 +2724,6 @@ extension on TranslationsPt { 'messages.markedAsWatched' => 'Marcado como assistido', 'messages.markedAsUnwatched' => 'Marcado como não assistido', 'messages.markedAsWatchedOffline' => 'Marcado como assistido (será sincronizado quando online)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Marcado como não assistido (será sincronizado quando online)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Removido automaticamente: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('pt'))(n, one: 'Removido automaticamente ${n} download assistido', other: 'Removidos automaticamente ${n} downloads assistidos', ), @@ -3204,6 +3227,8 @@ extension on TranslationsPt { 'watchTogether.codeMustBe5Chars' => 'O código da sessão deve ter 5 caracteres', 'watchTogether.joinInstructions' => 'Insira o código de sessão do anfitrião para entrar.', 'watchTogether.failedToCreate' => 'Falha ao criar sessão', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Falha ao entrar na sessão', 'watchTogether.sessionCodeCopied' => 'Código da sessão copiado para a área de transferência', 'watchTogether.relayUnreachable' => 'Servidor de retransmissão inacessível. O bloqueio pelo provedor de internet pode impedir o uso do Assistir Juntos.', @@ -3213,8 +3238,6 @@ extension on TranslationsPt { 'watchTogether.joinCurrentPlaybackDescription' => 'Voltar ao conteúdo que o anfitrião está assistindo agora', 'watchTogether.failedToOpenCurrentPlayback' => 'Falha ao abrir a reprodução atual', 'watchTogether.participantJoined' => ({required Object name}) => '${name} entrou', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} saiu', 'watchTogether.participantPaused' => ({required Object name}) => '${name} pausou', 'watchTogether.participantResumed' => ({required Object name}) => '${name} retomou', @@ -3413,6 +3436,11 @@ extension on TranslationsPt { 'videoSettings.audioOutput' => 'Saída de áudio', 'videoSettings.performanceOverlay' => 'Painel de desempenho', 'videoSettings.audioPassthrough' => 'Passagem direta de áudio', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Surround', + 'videoSettings.audioOutputSpatial' => 'Áudio espacial', + 'videoSettings.audioOutputStereo' => 'Estéreo', 'videoSettings.audioNormalization' => 'Normalizar intensidade sonora', 'videoSettings.audioDownmix' => 'Conversão para estéreo', 'performanceOverlay.color' => 'Cor', diff --git a/lib/i18n/strings_ru.g.dart b/lib/i18n/strings_ru.g.dart index ecd6df9a..5b02e6ef 100644 --- a/lib/i18n/strings_ru.g.dart +++ b/lib/i18n/strings_ru.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$ru extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Транслирует тестовый файл точно так же, как Atmos-воспроизведение в проигрывателе. Требуется URL тестового файла.'; @override String get atmosTestRawFile => 'Сырой файл EAC3'; @override String get atmosTestRawFileDescription => 'Воспроизводит тестовый файл с известной длиной. Требуется URL тестового файла.'; + @override String get atmosTestAsbarNative => 'Рендерер сэмпл-буфера (нативный)'; + @override String get atmosTestAsbarNativeDescription => 'Передаёт неизменённый сжатый звук файла прямо в системный рендерер. Требуется URL тестового файла.'; + @override String get atmosTestAsbarGenerated => 'Рендерер сэмпл-буфера (пересобранный)'; + @override String get atmosTestAsbarGeneratedDescription => 'То же, но с описанием звука, собранным как при воспроизведении. Требуется URL тестового файла.'; + @override String get atmosTestSessionMode => 'Использовать режим воспроизведения фильмов'; + @override String get atmosTestSessionModeDescription => 'Выключено — режим, описанный Dolby. Включено — прежний режим.'; + @override String get atmosTestShowRoutePicker => 'Выбрать выход AirPlay'; + @override String get atmosTestHideRoutePicker => 'Скрыть выбор выхода AirPlay'; + @override String get atmosTestRoutePickerDescription => 'Отправляет тест на приёмник AirPlay. Только AirPlay сообщает определённый режим звука.'; @override String get atmosTestStop => 'Остановить тест'; @override String get atmosTestUrl => 'URL тестового файла'; @override String get atmosTestUrlDescription => 'HTTP-URL сырого файла .ec3 Dolby Atmos (например, извлечённого через ffmpeg)'; @@ -1520,6 +1529,11 @@ class _Translations$videoSettings$ru extends Translations$videoSettings$en { @override String get audioOutput => 'Аудиовыход'; @override String get performanceOverlay => 'Оверлей производительности'; @override String get audioPassthrough => 'Сквозной вывод аудио'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Объёмный звук'; + @override String get audioOutputSpatial => 'Пространственное аудио'; + @override String get audioOutputStereo => 'Стерео'; @override String get audioNormalization => 'Нормализация громкости'; @override String get audioDownmix => 'Микширование в стерео'; } @@ -2469,6 +2483,15 @@ extension on TranslationsRu { 'settings.atmosTestRawStreamDescription' => 'Транслирует тестовый файл точно так же, как Atmos-воспроизведение в проигрывателе. Требуется URL тестового файла.', 'settings.atmosTestRawFile' => 'Сырой файл EAC3', 'settings.atmosTestRawFileDescription' => 'Воспроизводит тестовый файл с известной длиной. Требуется URL тестового файла.', + 'settings.atmosTestAsbarNative' => 'Рендерер сэмпл-буфера (нативный)', + 'settings.atmosTestAsbarNativeDescription' => 'Передаёт неизменённый сжатый звук файла прямо в системный рендерер. Требуется URL тестового файла.', + 'settings.atmosTestAsbarGenerated' => 'Рендерер сэмпл-буфера (пересобранный)', + 'settings.atmosTestAsbarGeneratedDescription' => 'То же, но с описанием звука, собранным как при воспроизведении. Требуется URL тестового файла.', + 'settings.atmosTestSessionMode' => 'Использовать режим воспроизведения фильмов', + 'settings.atmosTestSessionModeDescription' => 'Выключено — режим, описанный Dolby. Включено — прежний режим.', + 'settings.atmosTestShowRoutePicker' => 'Выбрать выход AirPlay', + 'settings.atmosTestHideRoutePicker' => 'Скрыть выбор выхода AirPlay', + 'settings.atmosTestRoutePickerDescription' => 'Отправляет тест на приёмник AirPlay. Только AirPlay сообщает определённый режим звука.', 'settings.atmosTestStop' => 'Остановить тест', 'settings.atmosTestUrl' => 'URL тестового файла', 'settings.atmosTestUrlDescription' => 'HTTP-URL сырого файла .ec3 Dolby Atmos (например, извлечённого через ffmpeg)', @@ -2696,6 +2719,8 @@ extension on TranslationsRu { 'videoControls.language' => 'Язык', 'videoControls.noSubtitlesFound' => 'Субтитры не найдены', 'videoControls.noSubtitlesAvailable' => 'Нет доступных субтитров', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Нет доступных аудиодорожек', 'videoControls.noTracksAvailable' => 'Нет доступных дорожек', 'videoControls.subtitleDownloaded' => 'Субтитры загружены', @@ -2705,8 +2730,6 @@ extension on TranslationsRu { 'messages.markedAsWatched' => 'Отмечено как просмотренное', 'messages.markedAsUnwatched' => 'Отмечено как непросмотренное', 'messages.markedAsWatchedOffline' => 'Отмечено как просмотренное (синхронизируется при подключении)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Отмечено как непросмотренное (синхронизируется при подключении)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Автоудалено: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n, one: 'Автоматически удалена ${n} просмотренная загрузка', few: 'Автоматически удалены ${n} просмотренные загрузки', many: 'Автоматически удалено ${n} просмотренных загрузок', other: 'Автоматически удалено ${n} просмотренной загрузки', ), @@ -3210,6 +3233,8 @@ extension on TranslationsRu { 'watchTogether.codeMustBe5Chars' => 'Код сессии должен содержать 5 символов', 'watchTogether.joinInstructions' => 'Введите код сессии организатора, чтобы присоединиться.', 'watchTogether.failedToCreate' => 'Не удалось создать сессию', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Не удалось присоединиться к сессии', 'watchTogether.sessionCodeCopied' => 'Код сессии скопирован в буфер обмена', 'watchTogether.relayUnreachable' => 'Сервер ретрансляции недоступен. Блокировка интернет-провайдером может помешать совместному просмотру.', @@ -3219,8 +3244,6 @@ extension on TranslationsRu { 'watchTogether.joinCurrentPlaybackDescription' => 'Вернуться к материалу, который сейчас смотрит организатор', 'watchTogether.failedToOpenCurrentPlayback' => 'Не удалось открыть текущее воспроизведение', 'watchTogether.participantJoined' => ({required Object name}) => '${name} присоединился', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} вышел', 'watchTogether.participantPaused' => ({required Object name}) => '${name} поставил на паузу', 'watchTogether.participantResumed' => ({required Object name}) => '${name} возобновил', @@ -3419,6 +3442,11 @@ extension on TranslationsRu { 'videoSettings.audioOutput' => 'Аудиовыход', 'videoSettings.performanceOverlay' => 'Оверлей производительности', 'videoSettings.audioPassthrough' => 'Сквозной вывод аудио', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Объёмный звук', + 'videoSettings.audioOutputSpatial' => 'Пространственное аудио', + 'videoSettings.audioOutputStereo' => 'Стерео', 'videoSettings.audioNormalization' => 'Нормализация громкости', 'videoSettings.audioDownmix' => 'Микширование в стерео', 'performanceOverlay.color' => 'Цвет', diff --git a/lib/i18n/strings_sv.g.dart b/lib/i18n/strings_sv.g.dart index 8917d6f3..43b43059 100644 --- a/lib/i18n/strings_sv.g.dart +++ b/lib/i18n/strings_sv.g.dart @@ -418,6 +418,15 @@ class _Translations$settings$sv extends Translations$settings$en { @override String get atmosTestRawStreamDescription => 'Strömmar testfilen precis som Atmos-uppspelning i spelaren. Kräver testfilens URL.'; @override String get atmosTestRawFile => 'Rå EAC3-fil'; @override String get atmosTestRawFileDescription => 'Spelar upp testfilen med känd längd. Kräver testfilens URL.'; + @override String get atmosTestAsbarNative => 'Sample-buffer-renderare (nativ)'; + @override String get atmosTestAsbarNativeDescription => 'Skickar filens orörda komprimerade ljud direkt till systemets renderare. Kräver testfilens URL.'; + @override String get atmosTestAsbarGenerated => 'Sample-buffer-renderare (ombyggd)'; + @override String get atmosTestAsbarGeneratedDescription => 'Samma sak, men med ljudbeskrivningen byggd som vid uppspelning. Kräver testfilens URL.'; + @override String get atmosTestSessionMode => 'Använd filmuppspelningsläge'; + @override String get atmosTestSessionModeDescription => 'Av använder läget som Dolby dokumenterar. På använder det tidigare läget.'; + @override String get atmosTestShowRoutePicker => 'Välj AirPlay-utgång'; + @override String get atmosTestHideRoutePicker => 'Dölj AirPlay-utgångsväljare'; + @override String get atmosTestRoutePickerDescription => 'Skickar testet till en AirPlay-mottagare. Endast AirPlay rapporterar det valda ljudläget.'; @override String get atmosTestStop => 'Stoppa test'; @override String get atmosTestUrl => 'Testfilens URL'; @override String get atmosTestUrlDescription => 'HTTP-URL till en rå .ec3 Dolby Atmos-fil (t.ex. extraherad med ffmpeg)'; @@ -1514,6 +1523,11 @@ class _Translations$videoSettings$sv extends Translations$videoSettings$en { @override String get audioOutput => 'Ljudutgång'; @override String get performanceOverlay => 'Prestandaöverlägg'; @override String get audioPassthrough => 'Ljudgenomströmning'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => 'Surround'; + @override String get audioOutputSpatial => 'Rumsligt ljud'; + @override String get audioOutputStereo => 'Stereo'; @override String get audioNormalization => 'Normalisera ljudstyrka'; @override String get audioDownmix => 'Nedmixning till stereo'; } @@ -2463,6 +2477,15 @@ extension on TranslationsSv { 'settings.atmosTestRawStreamDescription' => 'Strömmar testfilen precis som Atmos-uppspelning i spelaren. Kräver testfilens URL.', 'settings.atmosTestRawFile' => 'Rå EAC3-fil', 'settings.atmosTestRawFileDescription' => 'Spelar upp testfilen med känd längd. Kräver testfilens URL.', + 'settings.atmosTestAsbarNative' => 'Sample-buffer-renderare (nativ)', + 'settings.atmosTestAsbarNativeDescription' => 'Skickar filens orörda komprimerade ljud direkt till systemets renderare. Kräver testfilens URL.', + 'settings.atmosTestAsbarGenerated' => 'Sample-buffer-renderare (ombyggd)', + 'settings.atmosTestAsbarGeneratedDescription' => 'Samma sak, men med ljudbeskrivningen byggd som vid uppspelning. Kräver testfilens URL.', + 'settings.atmosTestSessionMode' => 'Använd filmuppspelningsläge', + 'settings.atmosTestSessionModeDescription' => 'Av använder läget som Dolby dokumenterar. På använder det tidigare läget.', + 'settings.atmosTestShowRoutePicker' => 'Välj AirPlay-utgång', + 'settings.atmosTestHideRoutePicker' => 'Dölj AirPlay-utgångsväljare', + 'settings.atmosTestRoutePickerDescription' => 'Skickar testet till en AirPlay-mottagare. Endast AirPlay rapporterar det valda ljudläget.', 'settings.atmosTestStop' => 'Stoppa test', 'settings.atmosTestUrl' => 'Testfilens URL', 'settings.atmosTestUrlDescription' => 'HTTP-URL till en rå .ec3 Dolby Atmos-fil (t.ex. extraherad med ffmpeg)', @@ -2690,6 +2713,8 @@ extension on TranslationsSv { 'videoControls.language' => 'Språk', 'videoControls.noSubtitlesFound' => 'Inga undertexter hittades', 'videoControls.noSubtitlesAvailable' => 'Inga undertexter tillgängliga', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => 'Inga ljudspår tillgängliga', 'videoControls.noTracksAvailable' => 'Inga spår tillgängliga', 'videoControls.subtitleDownloaded' => 'Undertexten har laddats ned', @@ -2699,8 +2724,6 @@ extension on TranslationsSv { 'messages.markedAsWatched' => 'Markerad som sedd', 'messages.markedAsUnwatched' => 'Markerad som osedd', 'messages.markedAsWatchedOffline' => 'Markerad som sedd (synkroniseras när online)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => 'Markerad som osedd (synkroniseras när online)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => 'Automatiskt borttagen: ${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('sv'))(n, one: 'Tog automatiskt bort ${n} sedd nedladdning', other: 'Tog automatiskt bort ${n} sedda nedladdningar', ), @@ -3204,6 +3227,8 @@ extension on TranslationsSv { 'watchTogether.codeMustBe5Chars' => 'Sessionskoden måste bestå av 5 tecken', 'watchTogether.joinInstructions' => 'Ange värdens sessionskod för att gå med.', 'watchTogether.failedToCreate' => 'Det gick inte att skapa sessionen', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => 'Det gick inte att gå med i sessionen', 'watchTogether.sessionCodeCopied' => 'Sessionskoden har kopierats till urklipp', 'watchTogether.relayUnreachable' => 'Reläservern kan inte nås. Din internetleverantör kan blockera Titta tillsammans.', @@ -3213,8 +3238,6 @@ extension on TranslationsSv { 'watchTogether.joinCurrentPlaybackDescription' => 'Hoppa tillbaka till det värden tittar på just nu', 'watchTogether.failedToOpenCurrentPlayback' => 'Kunde inte öppna aktuell uppspelning', 'watchTogether.participantJoined' => ({required Object name}) => '${name} gick med', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} lämnade', 'watchTogether.participantPaused' => ({required Object name}) => '${name} pausade', 'watchTogether.participantResumed' => ({required Object name}) => '${name} återupptog', @@ -3413,6 +3436,11 @@ extension on TranslationsSv { 'videoSettings.audioOutput' => 'Ljudutgång', 'videoSettings.performanceOverlay' => 'Prestandaöverlägg', 'videoSettings.audioPassthrough' => 'Ljudgenomströmning', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => 'Surround', + 'videoSettings.audioOutputSpatial' => 'Rumsligt ljud', + 'videoSettings.audioOutputStereo' => 'Stereo', 'videoSettings.audioNormalization' => 'Normalisera ljudstyrka', 'videoSettings.audioDownmix' => 'Nedmixning till stereo', 'performanceOverlay.color' => 'Färg', diff --git a/lib/i18n/strings_zh.g.dart b/lib/i18n/strings_zh.g.dart index fc7add1e..a5a26d9c 100644 --- a/lib/i18n/strings_zh.g.dart +++ b/lib/i18n/strings_zh.g.dart @@ -418,6 +418,15 @@ class Translations$settings$zh extends Translations$settings$en { @override String get atmosTestRawStreamDescription => '以与播放器内 Atmos 播放完全相同的方式流式传输测试文件。需要测试文件 URL。'; @override String get atmosTestRawFile => '原始 EAC3 文件'; @override String get atmosTestRawFileDescription => '以已知长度播放测试文件。需要测试文件 URL。'; + @override String get atmosTestAsbarNative => '采样缓冲渲染器(原生)'; + @override String get atmosTestAsbarNativeDescription => '将文件未经改动的压缩音频直接交给系统渲染器。需要测试文件 URL。'; + @override String get atmosTestAsbarGenerated => '采样缓冲渲染器(重建)'; + @override String get atmosTestAsbarGeneratedDescription => '相同,但音频描述按播放时的方式重建。需要测试文件 URL。'; + @override String get atmosTestSessionMode => '使用影片播放会话模式'; + @override String get atmosTestSessionModeDescription => '关闭时使用 Dolby 文档所述的模式。开启时使用先前的模式。'; + @override String get atmosTestShowRoutePicker => '选择 AirPlay 输出'; + @override String get atmosTestHideRoutePicker => '隐藏 AirPlay 输出选择器'; + @override String get atmosTestRoutePickerDescription => '将测试发送到 AirPlay 接收器。只有 AirPlay 会报告已确定的音频模式。'; @override String get atmosTestStop => '停止测试'; @override String get atmosTestUrl => '测试文件 URL'; @override String get atmosTestUrlDescription => '原始 .ec3 Dolby Atmos 文件的 HTTP URL(例如用 ffmpeg 提取)'; @@ -1511,6 +1520,11 @@ class Translations$videoSettings$zh extends Translations$videoSettings$en { @override String get audioOutput => '音频输出'; @override String get performanceOverlay => '性能监控'; @override String get audioPassthrough => '音频直通'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => '环绕声'; + @override String get audioOutputSpatial => '空间音频'; + @override String get audioOutputStereo => '立体声'; @override String get audioNormalization => '响度标准化'; @override String get audioDownmix => '下混为立体声'; } @@ -2460,6 +2474,15 @@ extension on TranslationsZh { 'settings.atmosTestRawStreamDescription' => '以与播放器内 Atmos 播放完全相同的方式流式传输测试文件。需要测试文件 URL。', 'settings.atmosTestRawFile' => '原始 EAC3 文件', 'settings.atmosTestRawFileDescription' => '以已知长度播放测试文件。需要测试文件 URL。', + 'settings.atmosTestAsbarNative' => '采样缓冲渲染器(原生)', + 'settings.atmosTestAsbarNativeDescription' => '将文件未经改动的压缩音频直接交给系统渲染器。需要测试文件 URL。', + 'settings.atmosTestAsbarGenerated' => '采样缓冲渲染器(重建)', + 'settings.atmosTestAsbarGeneratedDescription' => '相同,但音频描述按播放时的方式重建。需要测试文件 URL。', + 'settings.atmosTestSessionMode' => '使用影片播放会话模式', + 'settings.atmosTestSessionModeDescription' => '关闭时使用 Dolby 文档所述的模式。开启时使用先前的模式。', + 'settings.atmosTestShowRoutePicker' => '选择 AirPlay 输出', + 'settings.atmosTestHideRoutePicker' => '隐藏 AirPlay 输出选择器', + 'settings.atmosTestRoutePickerDescription' => '将测试发送到 AirPlay 接收器。只有 AirPlay 会报告已确定的音频模式。', 'settings.atmosTestStop' => '停止测试', 'settings.atmosTestUrl' => '测试文件 URL', 'settings.atmosTestUrlDescription' => '原始 .ec3 Dolby Atmos 文件的 HTTP URL(例如用 ffmpeg 提取)', @@ -2687,6 +2710,8 @@ extension on TranslationsZh { 'videoControls.language' => '语言', 'videoControls.noSubtitlesFound' => '未找到字幕', 'videoControls.noSubtitlesAvailable' => '没有可用字幕', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => '没有可用音轨', 'videoControls.noTracksAvailable' => '没有可用音轨', 'videoControls.subtitleDownloaded' => '字幕已下载', @@ -2696,8 +2721,6 @@ extension on TranslationsZh { 'messages.markedAsWatched' => '已标记为已观看', 'messages.markedAsUnwatched' => '已标记为未观看', 'messages.markedAsWatchedOffline' => '已标记为已观看(将在联网时同步)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => '已标记为未观看(将在联网时同步)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => '已自动移除:${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('zh'))(n, other: '已自动移除 ${n} 个看过的下载', ), @@ -3201,6 +3224,8 @@ extension on TranslationsZh { 'watchTogether.codeMustBe5Chars' => '会话代码必须是 5 个字符', 'watchTogether.joinInstructions' => '输入主持人的会话代码以加入。', 'watchTogether.failedToCreate' => '创建会话失败', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => '加入会话失败', 'watchTogether.sessionCodeCopied' => '会话代码已复制到剪贴板', 'watchTogether.relayUnreachable' => '无法访问中继服务器。网络运营商的屏蔽可能导致“一起看”不可用。', @@ -3210,8 +3235,6 @@ extension on TranslationsZh { 'watchTogether.joinCurrentPlaybackDescription' => '加入主持人当前正在观看的内容', 'watchTogether.failedToOpenCurrentPlayback' => '无法打开当前播放', 'watchTogether.participantJoined' => ({required Object name}) => '${name} 已加入', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} 已离开', 'watchTogether.participantPaused' => ({required Object name}) => '${name} 暂停了播放', 'watchTogether.participantResumed' => ({required Object name}) => '${name} 恢复了播放', @@ -3410,6 +3433,11 @@ extension on TranslationsZh { 'videoSettings.audioOutput' => '音频输出', 'videoSettings.performanceOverlay' => '性能监控', 'videoSettings.audioPassthrough' => '音频直通', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => '环绕声', + 'videoSettings.audioOutputSpatial' => '空间音频', + 'videoSettings.audioOutputStereo' => '立体声', 'videoSettings.audioNormalization' => '响度标准化', 'videoSettings.audioDownmix' => '下混为立体声', 'performanceOverlay.color' => '颜色', diff --git a/lib/i18n/strings_zh_Hant.g.dart b/lib/i18n/strings_zh_Hant.g.dart index 7d8e5d64..e0e13eb5 100644 --- a/lib/i18n/strings_zh_Hant.g.dart +++ b/lib/i18n/strings_zh_Hant.g.dart @@ -419,6 +419,15 @@ class _Translations$settings$zh_Hant extends Translations$settings$zh { @override String get atmosTestRawStreamDescription => '以與播放器播放 Atmos 完全相同的方式串流測試檔案。需要測試檔案的 URL。'; @override String get atmosTestRawFile => '原始 EAC3 檔案'; @override String get atmosTestRawFileDescription => '以已知長度播放測試檔案。需要測試檔案的 URL。'; + @override String get atmosTestAsbarNative => '取樣緩衝渲染器(原生)'; + @override String get atmosTestAsbarNativeDescription => '將檔案未經更動的壓縮音訊直接交給系統渲染器。需要測試檔案 URL。'; + @override String get atmosTestAsbarGenerated => '取樣緩衝渲染器(重建)'; + @override String get atmosTestAsbarGeneratedDescription => '相同,但音訊描述以播放時的方式重建。需要測試檔案 URL。'; + @override String get atmosTestSessionMode => '使用影片播放工作階段模式'; + @override String get atmosTestSessionModeDescription => '關閉時使用 Dolby 文件所述的模式。開啟時使用先前的模式。'; + @override String get atmosTestShowRoutePicker => '選擇 AirPlay 輸出'; + @override String get atmosTestHideRoutePicker => '隱藏 AirPlay 輸出選擇器'; + @override String get atmosTestRoutePickerDescription => '將測試傳送到 AirPlay 接收器。只有 AirPlay 會回報已確定的音訊模式。'; @override String get atmosTestStop => '停止測試'; @override String get atmosTestUrl => '測試檔案 URL'; @override String get atmosTestUrlDescription => '原始 .ec3 Dolby Atmos 檔案的 HTTP URL(例如使用 ffmpeg 提取的檔案)'; @@ -1512,6 +1521,11 @@ class _Translations$videoSettings$zh_Hant extends Translations$videoSettings$zh @override String get audioOutput => '音訊輸出'; @override String get performanceOverlay => '效能監控'; @override String get audioPassthrough => '音訊直通'; + @override String get audioOutputDolbyAtmos => 'Dolby Atmos'; + @override String get audioOutputDolbyAudio => 'Dolby Audio'; + @override String get audioOutputSurround => '環繞聲'; + @override String get audioOutputSpatial => '空間音訊'; + @override String get audioOutputStereo => '立體聲'; @override String get audioNormalization => '音量標準化'; @override String get audioDownmix => '下混為立體聲'; } @@ -2461,6 +2475,15 @@ extension on TranslationsZhHant { 'settings.atmosTestRawStreamDescription' => '以與播放器播放 Atmos 完全相同的方式串流測試檔案。需要測試檔案的 URL。', 'settings.atmosTestRawFile' => '原始 EAC3 檔案', 'settings.atmosTestRawFileDescription' => '以已知長度播放測試檔案。需要測試檔案的 URL。', + 'settings.atmosTestAsbarNative' => '取樣緩衝渲染器(原生)', + 'settings.atmosTestAsbarNativeDescription' => '將檔案未經更動的壓縮音訊直接交給系統渲染器。需要測試檔案 URL。', + 'settings.atmosTestAsbarGenerated' => '取樣緩衝渲染器(重建)', + 'settings.atmosTestAsbarGeneratedDescription' => '相同,但音訊描述以播放時的方式重建。需要測試檔案 URL。', + 'settings.atmosTestSessionMode' => '使用影片播放工作階段模式', + 'settings.atmosTestSessionModeDescription' => '關閉時使用 Dolby 文件所述的模式。開啟時使用先前的模式。', + 'settings.atmosTestShowRoutePicker' => '選擇 AirPlay 輸出', + 'settings.atmosTestHideRoutePicker' => '隱藏 AirPlay 輸出選擇器', + 'settings.atmosTestRoutePickerDescription' => '將測試傳送到 AirPlay 接收器。只有 AirPlay 會回報已確定的音訊模式。', 'settings.atmosTestStop' => '停止測試', 'settings.atmosTestUrl' => '測試檔案 URL', 'settings.atmosTestUrlDescription' => '原始 .ec3 Dolby Atmos 檔案的 HTTP URL(例如使用 ffmpeg 提取的檔案)', @@ -2688,6 +2711,8 @@ extension on TranslationsZhHant { 'videoControls.language' => '語言', 'videoControls.noSubtitlesFound' => '找不到字幕', 'videoControls.noSubtitlesAvailable' => '沒有可用的字幕', + _ => null, + } ?? switch (path) { 'videoControls.noAudioTracksAvailable' => '沒有可用的音軌', 'videoControls.noTracksAvailable' => '沒有可用的音訊或字幕', 'videoControls.subtitleDownloaded' => '字幕下載成功', @@ -2697,8 +2722,6 @@ extension on TranslationsZhHant { 'messages.markedAsWatched' => '已標記為已觀看', 'messages.markedAsUnwatched' => '已標記為未觀看', 'messages.markedAsWatchedOffline' => '已標記為已觀看(將在連線時同步)', - _ => null, - } ?? switch (path) { 'messages.markedAsUnwatchedOffline' => '已標記為未觀看(將在連線時同步)', 'messages.autoRemovedWatchedDownload' => ({required Object title}) => '已自動移除:${title}', 'messages.autoRemovedWatchedDownloads' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('zh'))(n, other: '已自動移除 ${n} 個已觀看的下載內容', ), @@ -3202,6 +3225,8 @@ extension on TranslationsZhHant { 'watchTogether.codeMustBe5Chars' => '工作階段代碼必須為 5 個字元', 'watchTogether.joinInstructions' => '輸入主持人的工作階段代碼以加入「一起看」。', 'watchTogether.failedToCreate' => '建立工作階段失敗', + _ => null, + } ?? switch (path) { 'watchTogether.failedToJoin' => '加入工作階段失敗', 'watchTogether.sessionCodeCopied' => '工作階段代碼已複製到剪貼簿', 'watchTogether.relayUnreachable' => '無法連線至中繼伺服器。ISP 封鎖可能會導致「一起看」無法使用。', @@ -3211,8 +3236,6 @@ extension on TranslationsZhHant { 'watchTogether.joinCurrentPlaybackDescription' => '同步至主持人目前的觀看進度', 'watchTogether.failedToOpenCurrentPlayback' => '無法開啟目前播放點', 'watchTogether.participantJoined' => ({required Object name}) => '${name} 已加入', - _ => null, - } ?? switch (path) { 'watchTogether.participantLeft' => ({required Object name}) => '${name} 已離開', 'watchTogether.participantPaused' => ({required Object name}) => '${name} 暫停了播放', 'watchTogether.participantResumed' => ({required Object name}) => '${name} 恢復了播放', @@ -3411,6 +3434,11 @@ extension on TranslationsZhHant { 'videoSettings.audioOutput' => '音訊輸出', 'videoSettings.performanceOverlay' => '效能監控', 'videoSettings.audioPassthrough' => '音訊直通', + 'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos', + 'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio', + 'videoSettings.audioOutputSurround' => '環繞聲', + 'videoSettings.audioOutputSpatial' => '空間音訊', + 'videoSettings.audioOutputStereo' => '立體聲', 'videoSettings.audioNormalization' => '音量標準化', 'videoSettings.audioDownmix' => '下混為立體聲', 'performanceOverlay.color' => '色彩', diff --git a/lib/i18n/sv.i18n.json b/lib/i18n/sv.i18n.json index d5d44cad..88269689 100644 --- a/lib/i18n/sv.i18n.json +++ b/lib/i18n/sv.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "Strömmar testfilen precis som Atmos-uppspelning i spelaren. Kräver testfilens URL.", "atmosTestRawFile": "Rå EAC3-fil", "atmosTestRawFileDescription": "Spelar upp testfilen med känd längd. Kräver testfilens URL.", + "atmosTestAsbarNative": "Sample-buffer-renderare (nativ)", + "atmosTestAsbarNativeDescription": "Skickar filens orörda komprimerade ljud direkt till systemets renderare. Kräver testfilens URL.", + "atmosTestAsbarGenerated": "Sample-buffer-renderare (ombyggd)", + "atmosTestAsbarGeneratedDescription": "Samma sak, men med ljudbeskrivningen byggd som vid uppspelning. Kräver testfilens URL.", + "atmosTestSessionMode": "Använd filmuppspelningsläge", + "atmosTestSessionModeDescription": "Av använder läget som Dolby dokumenterar. På använder det tidigare läget.", + "atmosTestShowRoutePicker": "Välj AirPlay-utgång", + "atmosTestHideRoutePicker": "Dölj AirPlay-utgångsväljare", + "atmosTestRoutePickerDescription": "Skickar testet till en AirPlay-mottagare. Endast AirPlay rapporterar det valda ljudläget.", "atmosTestStop": "Stoppa test", "atmosTestUrl": "Testfilens URL", "atmosTestUrlDescription": "HTTP-URL till en rå .ec3 Dolby Atmos-fil (t.ex. extraherad med ffmpeg)", @@ -1347,6 +1356,11 @@ "audioOutput": "Ljudutgång", "performanceOverlay": "Prestandaöverlägg", "audioPassthrough": "Ljudgenomströmning", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "Surround", + "audioOutputSpatial": "Rumsligt ljud", + "audioOutputStereo": "Stereo", "audioNormalization": "Normalisera ljudstyrka", "audioDownmix": "Nedmixning till stereo" }, diff --git a/lib/i18n/zh-Hant.i18n.json b/lib/i18n/zh-Hant.i18n.json index cddc185c..c95a91b9 100644 --- a/lib/i18n/zh-Hant.i18n.json +++ b/lib/i18n/zh-Hant.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "以與播放器播放 Atmos 完全相同的方式串流測試檔案。需要測試檔案的 URL。", "atmosTestRawFile": "原始 EAC3 檔案", "atmosTestRawFileDescription": "以已知長度播放測試檔案。需要測試檔案的 URL。", + "atmosTestAsbarNative": "取樣緩衝渲染器(原生)", + "atmosTestAsbarNativeDescription": "將檔案未經更動的壓縮音訊直接交給系統渲染器。需要測試檔案 URL。", + "atmosTestAsbarGenerated": "取樣緩衝渲染器(重建)", + "atmosTestAsbarGeneratedDescription": "相同,但音訊描述以播放時的方式重建。需要測試檔案 URL。", + "atmosTestSessionMode": "使用影片播放工作階段模式", + "atmosTestSessionModeDescription": "關閉時使用 Dolby 文件所述的模式。開啟時使用先前的模式。", + "atmosTestShowRoutePicker": "選擇 AirPlay 輸出", + "atmosTestHideRoutePicker": "隱藏 AirPlay 輸出選擇器", + "atmosTestRoutePickerDescription": "將測試傳送到 AirPlay 接收器。只有 AirPlay 會回報已確定的音訊模式。", "atmosTestStop": "停止測試", "atmosTestUrl": "測試檔案 URL", "atmosTestUrlDescription": "原始 .ec3 Dolby Atmos 檔案的 HTTP URL(例如使用 ffmpeg 提取的檔案)", @@ -1344,6 +1353,11 @@ "audioOutput": "音訊輸出", "performanceOverlay": "效能監控", "audioPassthrough": "音訊直通", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "環繞聲", + "audioOutputSpatial": "空間音訊", + "audioOutputStereo": "立體聲", "audioNormalization": "音量標準化", "audioDownmix": "下混為立體聲" }, diff --git a/lib/i18n/zh.i18n.json b/lib/i18n/zh.i18n.json index 7c6b819d..edf1a07e 100644 --- a/lib/i18n/zh.i18n.json +++ b/lib/i18n/zh.i18n.json @@ -289,6 +289,15 @@ "atmosTestRawStreamDescription": "以与播放器内 Atmos 播放完全相同的方式流式传输测试文件。需要测试文件 URL。", "atmosTestRawFile": "原始 EAC3 文件", "atmosTestRawFileDescription": "以已知长度播放测试文件。需要测试文件 URL。", + "atmosTestAsbarNative": "采样缓冲渲染器(原生)", + "atmosTestAsbarNativeDescription": "将文件未经改动的压缩音频直接交给系统渲染器。需要测试文件 URL。", + "atmosTestAsbarGenerated": "采样缓冲渲染器(重建)", + "atmosTestAsbarGeneratedDescription": "相同,但音频描述按播放时的方式重建。需要测试文件 URL。", + "atmosTestSessionMode": "使用影片播放会话模式", + "atmosTestSessionModeDescription": "关闭时使用 Dolby 文档所述的模式。开启时使用先前的模式。", + "atmosTestShowRoutePicker": "选择 AirPlay 输出", + "atmosTestHideRoutePicker": "隐藏 AirPlay 输出选择器", + "atmosTestRoutePickerDescription": "将测试发送到 AirPlay 接收器。只有 AirPlay 会报告已确定的音频模式。", "atmosTestStop": "停止测试", "atmosTestUrl": "测试文件 URL", "atmosTestUrlDescription": "原始 .ec3 Dolby Atmos 文件的 HTTP URL(例如用 ffmpeg 提取)", @@ -1344,6 +1353,11 @@ "audioOutput": "音频输出", "performanceOverlay": "性能监控", "audioPassthrough": "音频直通", + "audioOutputDolbyAtmos": "Dolby Atmos", + "audioOutputDolbyAudio": "Dolby Audio", + "audioOutputSurround": "环绕声", + "audioOutputSpatial": "空间音频", + "audioOutputStereo": "立体声", "audioNormalization": "响度标准化", "audioDownmix": "下混为立体声" }, diff --git a/lib/mpv/mpv.dart b/lib/mpv/mpv.dart index ab50c50e..669892ce 100644 --- a/lib/mpv/mpv.dart +++ b/lib/mpv/mpv.dart @@ -44,6 +44,7 @@ library; // Player +export 'player/audio_rendering_mode.dart'; export 'player/player.dart'; export 'player/player_state.dart'; export 'player/player_streams.dart'; diff --git a/lib/mpv/player/audio_rendering_mode.dart b/lib/mpv/player/audio_rendering_mode.dart new file mode 100644 index 00000000..93092edc --- /dev/null +++ b/lib/mpv/player/audio_rendering_mode.dart @@ -0,0 +1,33 @@ +/// The system's resolved audio rendering mode on Apple platforms, as reported +/// by `AVAudioSession.renderingMode` (tvOS/iOS 17.2+). +/// +/// Dolby's application guide requires players to badge playback from this +/// value. Apple documents it as populated for CarPlay and AirPlay routes, so a +/// direct HDMI route is expected to report `notApplicable`; that means +/// "unknown", not "not Dolby", and [isConclusive] encodes the difference. +class AudioRenderingMode { + const AudioRenderingMode({ + required this.name, + required this.rawValue, + required this.route, + required this.outputChannels, + required this.maxOutputChannels, + }); + + final String name; + final int rawValue; + final String route; + final int outputChannels; + final int maxOutputChannels; + + static const int notApplicable = 0; + static const int monoStereo = 1; + static const int surround = 2; + static const int spatialAudio = 3; + static const int dolbyAudio = 4; + static const int dolbyAtmos = 5; + + bool get isConclusive => rawValue != notApplicable && name != 'unavailable'; + bool get isDolbyAtmos => rawValue == dolbyAtmos; + bool get isDolbyAudio => rawValue == dolbyAudio; +} diff --git a/lib/mpv/player/player.dart b/lib/mpv/player/player.dart index 5f542e87..0df5bb1c 100644 --- a/lib/mpv/player/player.dart +++ b/lib/mpv/player/player.dart @@ -3,6 +3,7 @@ import 'dart:io' show Platform; import '../../media/media_display_criteria.dart'; import '../../media/playback_rate.dart'; import '../models.dart'; +import 'audio_rendering_mode.dart'; import 'platform/player_android.dart'; import 'player_native.dart'; import 'player_state.dart'; @@ -219,6 +220,9 @@ abstract class Player { /// passed through to the audio device without decoding. Future setAudioPassthrough(bool enabled); + /// The system's resolved audio rendering mode (Apple only); null elsewhere. + Future getAudioRenderingMode(); + /// Enable or disable loudness normalization. /// /// mpv backends insert/remove the `loudnorm` audio filter. Android diff --git a/lib/mpv/player/player_base.dart b/lib/mpv/player/player_base.dart index 5a59cb84..c255fa1e 100644 --- a/lib/mpv/player/player_base.dart +++ b/lib/mpv/player/player_base.dart @@ -11,6 +11,7 @@ import '../../utils/track_label_builder.dart'; import '../font_loader.dart'; import '../models.dart'; import 'mpv_node_decoder.dart'; +import 'audio_rendering_mode.dart'; import 'player.dart'; import 'player_state.dart'; import 'player_stream_controllers.dart'; @@ -835,6 +836,9 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player { // ignore: no-empty-block - base no-op, overridden by platform subclasses Future setAudioPassthrough(bool enabled) async {} + @override + Future getAudioRenderingMode() async => null; + /// mpv loudnorm targeting streaming-style loudness; mirrored by the /// Android ExoPlayer effect parameters in AudioNormalizationEffect.kt. static const _loudnormFilter = 'loudnorm=I=-14:TP=-3:LRA=4'; diff --git a/lib/mpv/player/player_native.dart b/lib/mpv/player/player_native.dart index f3e4f6e7..81901fc8 100644 --- a/lib/mpv/player/player_native.dart +++ b/lib/mpv/player/player_native.dart @@ -8,6 +8,7 @@ import 'package:flutter/services.dart'; import '../../media/media_display_criteria.dart'; import '../../utils/app_logger.dart'; import '../models.dart'; +import 'audio_rendering_mode.dart'; import 'player_base.dart'; typedef _AudioStateRequest = ({ @@ -645,6 +646,31 @@ class PlayerNative extends PlayerBase { await setProperty('audio-device', device.name); } + /// The system's resolved audio rendering mode, used for the Dolby playback + /// badge. Apple populates `AVAudioSession.renderingMode` for CarPlay and + /// AirPlay routes, so an Apple TV on HDMI is expected to report + /// `notApplicable` — treat that as unknown, never as "not Dolby". + /// Returns null on platforms without the native method. + @override + Future getAudioRenderingMode() async { + if (!Platform.isIOS || _nativeCoreUnavailable) return null; + try { + final raw = await invoke>('getAudioRenderingMode', const {}); + if (raw == null) return null; + return AudioRenderingMode( + name: raw['name'] as String? ?? 'unknown', + rawValue: (raw['rawValue'] as num?)?.toInt() ?? 0, + route: raw['route'] as String? ?? 'none', + outputChannels: (raw['outputChannels'] as num?)?.toInt() ?? 0, + maxOutputChannels: (raw['maxOutputChannels'] as num?)?.toInt() ?? 0, + ); + } on PlatformException { + return null; + } on MissingPluginException { + return null; + } + } + @override Future setProperty(String name, String value) => _setProperty(name, value, synchronizeRate: true); diff --git a/lib/screens/settings/atmos_diagnostics_screen.dart b/lib/screens/settings/atmos_diagnostics_screen.dart index 44efeea6..2c3c2d17 100644 --- a/lib/screens/settings/atmos_diagnostics_screen.dart +++ b/lib/screens/settings/atmos_diagnostics_screen.dart @@ -30,6 +30,7 @@ class _AtmosDiagnosticsScreenState extends State { Map _status = const {}; String? _activeMode; bool _stopping = false; + bool _routePickerVisible = false; @override void initState() { @@ -54,15 +55,36 @@ class _AtmosDiagnosticsScreenState extends State { } } + /// AirPlay is the only route where the system resolves `renderingMode` and + /// `supportedOutputChannelLayouts`, so the picker is what makes those arms of + /// the matrix testable. + Future _toggleRoutePicker() async { + final next = !_routePickerVisible; + try { + await _channel.invokeMethod(next ? 'showRoutePicker' : 'hideRoutePicker'); + if (!mounted) return; + setState(() => _routePickerVisible = next); + } on PlatformException catch (e) { + if (mounted) showErrorSnackBar(context, e.message ?? e.code); + } + } + Future _start(String mode) async { - final needsUrl = mode == 'rawEc3' || mode == 'rawEc3Finite'; + const urlModes = {'rawEc3', 'rawEc3Finite', 'asbarNative', 'asbarGenerated'}; + final needsUrl = urlModes.contains(mode); final url = SettingsService.instance.read(SettingsService.atmosProbeUrl); if (needsUrl && url.isEmpty) { showAppSnackBar(context, t.settings.atmosTestUrlMissing); return; } try { - await _channel.invokeMethod('start', {'mode': mode, if (needsUrl) 'url': url}); + await _channel.invokeMethod('start', { + 'mode': mode, + if (needsUrl) 'url': url, + 'sessionMode': SettingsService.instance.read(SettingsService.atmosProbeMoviePlaybackMode) + ? 'moviePlayback' + : 'default', + }); if (!mounted) return; setState(() => _activeMode = mode); } on PlatformException catch (e) { @@ -130,6 +152,30 @@ class _AtmosDiagnosticsScreenState extends State { title: t.settings.atmosTestRawFile, subtitle: t.settings.atmosTestRawFileDescription, ), + _testTile( + mode: 'asbarNative', + icon: Symbols.graphic_eq_rounded, + title: t.settings.atmosTestAsbarNative, + subtitle: t.settings.atmosTestAsbarNativeDescription, + ), + _testTile( + mode: 'asbarGenerated', + icon: Symbols.tune_rounded, + title: t.settings.atmosTestAsbarGenerated, + subtitle: t.settings.atmosTestAsbarGeneratedDescription, + ), + SettingNavigationTile( + icon: Symbols.airplay_rounded, + title: _routePickerVisible ? t.settings.atmosTestHideRoutePicker : t.settings.atmosTestShowRoutePicker, + subtitle: t.settings.atmosTestRoutePickerDescription, + onTap: _toggleRoutePicker, + ), + SettingSwitchTile( + pref: SettingsService.atmosProbeMoviePlaybackMode, + icon: Symbols.tv_options_input_settings_rounded, + title: t.settings.atmosTestSessionMode, + subtitle: t.settings.atmosTestSessionModeDescription, + ), SettingNavigationTile( icon: Symbols.stop_circle_rounded, title: t.settings.atmosTestStop, diff --git a/lib/services/settings_service.dart b/lib/services/settings_service.dart index cb4f8e0d..2ad9d0bc 100644 --- a/lib/services/settings_service.dart +++ b/lib/services/settings_service.dart @@ -306,6 +306,10 @@ class SettingsService extends BaseSharedPreferencesService { // Source URL for the Apple TV Atmos diagnostics screen; deliberately not // resettable so a tester keeps it across "Reset All Settings". static const atmosProbeUrl = StringPref('atmos_probe_url', defaultValue: ''); + // Session-mode A/B for the Atmos diagnostics screen. Off = the mode Dolby's + // application guide prescribes; on = the mode the audio output used before. + // Not resettable, for the same reason as the URL above. + static const atmosProbeMoviePlaybackMode = BoolPref('atmos_probe_movie_playback_mode'); static const crashReporting = BoolPref('crash_reporting', defaultValue: true); static const enableHardwareDecoding = BoolPref('enable_hardware_decoding', defaultValue: true); static const enableHDR = BoolPref('enable_hdr', defaultValue: true); diff --git a/lib/widgets/video_controls/sheets/video_settings_sheet.dart b/lib/widgets/video_controls/sheets/video_settings_sheet.dart index 06f78ade..38a3975a 100644 --- a/lib/widgets/video_controls/sheets/video_settings_sheet.dart +++ b/lib/widgets/video_controls/sheets/video_settings_sheet.dart @@ -180,6 +180,67 @@ class _SettingsToggleItemState extends State<_SettingsToggleItem> { } } +/// Reflects the system's resolved audio rendering mode, as the Dolby +/// application guide requires. Renders nothing until the system reports a +/// conclusive value: Apple only resolves `renderingMode` for CarPlay and +/// AirPlay routes, and showing "Stereo" for an inconclusive HDMI route would +/// be worse than showing nothing. +class _AudioRenderingModeItem extends StatefulWidget { + const _AudioRenderingModeItem({required this.player}); + + final Player player; + + @override + State<_AudioRenderingModeItem> createState() => _AudioRenderingModeItemState(); +} + +class _AudioRenderingModeItemState extends State<_AudioRenderingModeItem> { + AudioRenderingMode? _mode; + Timer? _poll; + + @override + void initState() { + super.initState(); + unawaited(_refresh()); + _poll = Timer.periodic(const Duration(seconds: 2), (_) => unawaited(_refresh())); + } + + @override + void dispose() { + _poll?.cancel(); + super.dispose(); + } + + Future _refresh() async { + final mode = await widget.player.getAudioRenderingMode(); + if (!mounted) return; + setState(() => _mode = mode); + } + + @override + Widget build(BuildContext context) { + final mode = _mode; + if (mode == null || !mode.isConclusive) return const SizedBox.shrink(); + final label = switch (mode.rawValue) { + AudioRenderingMode.dolbyAtmos => t.videoSettings.audioOutputDolbyAtmos, + AudioRenderingMode.dolbyAudio => t.videoSettings.audioOutputDolbyAudio, + AudioRenderingMode.surround => t.videoSettings.audioOutputSurround, + AudioRenderingMode.spatialAudio => t.videoSettings.audioOutputSpatial, + _ => t.videoSettings.audioOutputStereo, + }; + final highlighted = mode.isDolbyAtmos || mode.isDolbyAudio; + return FocusableListTile( + leading: AppIcon( + Symbols.spatial_audio_rounded, + fill: 1, + color: highlighted ? Colors.amber : tokens(context).textMuted, + ), + title: Text(t.videoSettings.audioOutput), + trailing: Text(label, style: TextStyle(color: tokens(context).textMuted)), + ); + } +} + /// Unified settings sheet for playback adjustments with in-sheet navigation class VideoSettingsSheet extends StatefulWidget { final Player player; @@ -580,6 +641,12 @@ class _VideoSettingsSheetState extends State { onAfterWrite: widget.player.setAudioPassthrough, ), + // Dolby playback badge. The Dolby application guide requires the app + // to reflect AVAudioSession.renderingMode; Apple only resolves that + // for CarPlay/AirPlay routes, so it is hidden rather than shown as + // "not Dolby" when the system reports notApplicable. + if (PlatformDetector.isAppleTV()) _AudioRenderingModeItem(player: widget.player), + // Audio Normalization _SettingsToggleItem( pref: SettingsService.audioNormalization, diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 0ad684b8..c8b8f6b4 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -38,4 +38,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: d16f5e5d196d1ca9863d7a71d5885cad7ffa7d2d -COCOAPODS: 1.17.0 +COCOAPODS: 1.16.2 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index cc7a1ff6..10e1d579 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -891,7 +891,7 @@ repositoryURL = "https://github.com/edde746/MPVKit"; requirement = { kind = exactVersion; - version = 1.0.13; + version = 1.0.14; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7dd8c5d5..1d8eaa8f 100644 --- a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/edde746/MPVKit", "state" : { - "revision" : "93101dc1d0903c48fa3054652805acacbb75e856", - "version" : "1.0.13" + "revision" : "3309e7c158e64adc9a5666df5e7aa474f2d3aaec", + "version" : "1.0.14" } }, { diff --git a/macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved b/macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7dd8c5d5..1d8eaa8f 100644 --- a/macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/edde746/MPVKit", "state" : { - "revision" : "93101dc1d0903c48fa3054652805acacbb75e856", - "version" : "1.0.13" + "revision" : "3309e7c158e64adc9a5666df5e7aa474f2d3aaec", + "version" : "1.0.14" } }, { diff --git a/shared/apple/AtmosProbe/AtmosProbePlugin.swift b/shared/apple/AtmosProbe/AtmosProbePlugin.swift index 1e2ea75e..575bf503 100644 --- a/shared/apple/AtmosProbe/AtmosProbePlugin.swift +++ b/shared/apple/AtmosProbe/AtmosProbePlugin.swift @@ -1,9 +1,14 @@ import AVFoundation import Flutter import Foundation +#if os(iOS) || os(tvOS) + import AVKit + import UIKit +#endif /// Diagnostics harness for #1300: plays known assets through a bare AVPlayer -/// so a tester can read the receiver's format display per test. +/// or through a bare AVSampleBufferAudioRenderer so a tester can read the +/// receiver's format display per test. /// /// Modes: /// - hlsAtmos: Apple's public fMP4 Atmos example stream (device+AVR+MAT baseline) @@ -13,6 +18,19 @@ import Foundation /// AVPlayer audio sink's feeding model /// - rawEc3Finite: same loader but passing through the real content length, /// isolating "loader trick" failures from "raw ES" failures +/// - asbarNative: the decisive arm. Reads the asset with AVAssetReader at +/// `outputSettings: nil` and hands the resulting *native* +/// compressed CMSampleBuffers and *native* CMFormatDescription +/// straight to AVSampleBufferAudioRenderer, following Apple's +/// flexible enhanced buffering sequence. No mpv, no FFmpeg +/// spdif muxer, no generated ASBD, no hand-built dec3. If this +/// reaches Atmos, the production sink has a construction bug; +/// if it does not, AVSampleBufferAudioRenderer cannot carry +/// JOC on this route and the architecture must change. +/// - asbarGenerated: same feed, but the format description is rebuilt the way +/// the mpv AO builds it (generated ASBD + dec3 magic cookie + +/// MPEG_5_1_C layout). A/B against asbarNative isolates +/// descriptor construction from everything else. public class AtmosProbePlugin: NSObject, FlutterPlugin { private static let hlsAtmosUrl = "https://devstreaming-cdn.apple.com/videos/streaming/examples/adv_dv_atmos/main.m3u8" @@ -21,6 +39,10 @@ public class AtmosProbePlugin: NSObject, FlutterPlugin { private var player: AVPlayer? private var loader: RawEc3Loader? + private var asbar: AsbarProbe? + #if os(iOS) || os(tvOS) + private var routePicker: AVRoutePickerView? + #endif public static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel( @@ -38,10 +60,16 @@ public class AtmosProbePlugin: NSObject, FlutterPlugin { result(FlutterError(code: "bad_args", message: "mode required", details: nil)) return } - start(mode: mode, url: args["url"] as? String, result: result) + start( + mode: mode, url: args["url"] as? String, + sessionMode: args["sessionMode"] as? String, result: result) case "stop": stopPlayback() result(nil) + case "showRoutePicker": + result(setRoutePickerVisible(true)) + case "hideRoutePicker": + result(setRoutePickerVisible(false)) case "getStatus": result(status()) default: @@ -49,7 +77,10 @@ public class AtmosProbePlugin: NSObject, FlutterPlugin { } } - private func start(mode: String, url: String?, result: @escaping FlutterResult) { + private func start( + mode: String, url: String?, sessionMode: String?, + result: @escaping FlutterResult + ) { stopPlayback() let item: AVPlayerItem @@ -71,6 +102,27 @@ public class AtmosProbePlugin: NSObject, FlutterPlugin { item = AVPlayerItem(asset: loader.asset) item.preferredForwardBufferDuration = 1.0 loader.begin() + case "asbarNative", "asbarGenerated": + guard let source = url.flatMap(URL.init(string:)) else { + result( + FlutterError(code: "bad_url", message: "\(mode) needs a source url", details: nil)) + return + } + let probe = AsbarProbe( + source: source, + regenerateFormatDescription: mode == "asbarGenerated", + // Dolby's Figure 1 prescribes mode .default; .moviePlayback is what + // the shipping AO used. Selectable so the tester can A/B it. + sessionMode: sessionMode == "moviePlayback" ? .moviePlayback : .default) + asbar = probe + probe.start { error in + if let error { + result(FlutterError(code: "asbar_failed", message: error, details: nil)) + } else { + result(nil) + } + } + return default: result(FlutterError(code: "bad_mode", message: mode, details: nil)) return @@ -78,18 +130,77 @@ public class AtmosProbePlugin: NSObject, FlutterPlugin { let player = AVPlayer(playerItem: item) player.automaticallyWaitsToMinimizeStalling = false - player.allowsExternalPlayback = false + // Must stay true: the route picker exists so these arms can be compared + // against the sample-buffer arms on an AirPlay destination, and AirPlay is + // the only route where the system resolves renderingMode and + // supportedOutputChannelLayouts. Pinning playback local would leave the + // AVPlayer controls on HDMI while the picker moved everything else. + player.allowsExternalPlayback = true self.player = player player.play() result(nil) } + /// Dolby's flow opens with an AVRoutePickerView so the tester can move + /// playback to an AirPlay destination. That matters here beyond conformance: + /// AVRoutePickerView.h states media from an AVSampleBufferAudioRenderer can + /// be routed to AirPlay on tvOS, and AirPlay is the only route where + /// `renderingMode` and `supportedOutputChannelLayouts` actually resolve — so + /// this is what makes the AirPlay arm of the test matrix reachable from the + /// device. + private func setRoutePickerVisible(_ visible: Bool) -> Bool { + #if os(iOS) || os(tvOS) + guard visible else { + routePicker?.removeFromSuperview() + routePicker = nil + return true + } + if routePicker != nil { return true } + guard let window = Self.keyWindow() else { return false } + let picker = AVRoutePickerView() + picker.translatesAutoresizingMaskIntoConstraints = false + window.addSubview(picker) + NSLayoutConstraint.activate([ + picker.centerXAnchor.constraint(equalTo: window.centerXAnchor), + picker.bottomAnchor.constraint(equalTo: window.centerYAnchor, constant: -40), + picker.widthAnchor.constraint(equalToConstant: 120), + picker.heightAnchor.constraint(equalToConstant: 80), + ]) + routePicker = picker + window.setNeedsFocusUpdate() + window.updateFocusIfNeeded() + return true + #else + return false + #endif + } + + #if os(iOS) || os(tvOS) + private static func keyWindow() -> UIWindow? { + UIApplication.shared.connectedScenes + .compactMap { $0 as? UIWindowScene } + .flatMap(\.windows) + .first { $0.isKeyWindow } + ?? UIApplication.shared.connectedScenes + .compactMap { $0 as? UIWindowScene } + .flatMap(\.windows) + .first + } + #endif + private func stopPlayback() { player?.pause() player?.replaceCurrentItem(with: nil) player = nil loader?.cancel() loader = nil + asbar?.cancel() + asbar = nil + _ = setRoutePickerVisible(false) + // Run isolation: never let a failed compressed route leak into the next + // variant or into other apps. + try? AVAudioSession.sharedInstance().setActive( + false, options: .notifyOthersOnDeactivation) } private func status() -> [String: Any] { @@ -101,9 +212,23 @@ public class AtmosProbePlugin: NSObject, FlutterPlugin { out["route"] = session.currentRoute.outputs.map { port in "\(port.portType.rawValue)/\(port.portName)/\(port.channels?.count ?? 0)ch" }.joined(separator: ", ") + out["sessionCategory"] = session.category.rawValue + out["sessionMode"] = session.mode.rawValue + out["routeSharingPolicy"] = session.routeSharingPolicy.rawValue + out["categoryOptions"] = session.categoryOptions.rawValue if #available(iOS 17.2, tvOS 17.2, *) { out["renderingMode"] = String(describing: session.renderingMode) out["renderingModeRawValue"] = session.renderingMode.rawValue + // Empty on HDMI by design (CarPlay/AirPlay only). Reported so a tester + // can tell "empty because HDMI" from "empty because inactive". + out["supportedOutputChannelLayouts"] = session.supportedOutputChannelLayouts.map { + String(format: "0x%08x/%uch", $0.layoutTag, $0.channelCount) + }.joined(separator: ", ") + } + + if let asbar { + out.merge(asbar.statusSnapshot()) { _, new in new } + return out } guard let player = player else { @@ -490,3 +615,451 @@ final class RawEc3Loader: NSObject, AVAssetResourceLoaderDelegate, URLSessionDat } } } + +/// Feeds compressed E-AC-3 access units to a bare `AVSampleBufferAudioRenderer` +/// using Apple's flexible enhanced buffering sequence. +/// +/// This is deliberately the shortest possible path from file bytes to the +/// system decoder: `AVAssetReader` at `outputSettings: nil` yields the native +/// compressed sample buffers and the native `CMFormatDescription` that +/// AVFoundation itself would use. Nothing else touches the data, so a failure +/// here is a property of the renderer, not of our packetization. +final class AsbarProbe: NSObject { + private static var statusContext = 0 + + private let source: URL + private let regenerateFormatDescription: Bool + private let sessionMode: AVAudioSession.Mode + private let queue = DispatchQueue( + label: "plezy.atmos.probe.asbar", qos: .userInitiated) + private let lock = NSLock() + + private var renderer: AVSampleBufferAudioRenderer? + private var synchronizer: AVSampleBufferRenderSynchronizer? + private var reader: AVAssetReader? + private var output: AVAssetReaderTrackOutput? + private var temporaryFile: URL? + private var download: URLSessionDownloadTask? + private var statusObserved = false + private var cancelled = false + + // Guarded by `lock`; read from the method-channel thread. + private var enqueuedSamples = 0 + private var nativeDescription = "unknown" + private var usedDescription = "unknown" + private var magicCookieHex = "none" + private var layoutTagText = "none" + private var phase = "starting" + private var failure: String? + + init( + source: URL, regenerateFormatDescription: Bool, sessionMode: AVAudioSession.Mode + ) { + self.source = source + self.regenerateFormatDescription = regenerateFormatDescription + self.sessionMode = sessionMode + super.init() + } + + /// `completion` reports only whether the run could be started. + func start(completion: @escaping (String?) -> Void) { + if source.isFileURL { + queue.async { [weak self] in + guard let self else { return } + let error = self.beginReading(from: self.source) + DispatchQueue.main.async { completion(error) } + } + return + } + + // AVAssetReader needs a seekable local asset; stage the source first. + setPhase("downloading") + let task = URLSession.shared.downloadTask(with: source) { [weak self] url, _, error in + guard let self else { return } + guard let url else { + let message = error?.localizedDescription ?? "download failed" + self.fail(message) + DispatchQueue.main.async { completion(message) } + return + } + // The temporary file is removed as soon as this handler returns. + let staged = FileManager.default.temporaryDirectory + .appendingPathComponent("plezy-asbar-\(UUID().uuidString)") + .appendingPathExtension(self.source.pathExtension.isEmpty ? "eac3" : self.source.pathExtension) + do { + try FileManager.default.moveItem(at: url, to: staged) + } catch { + let message = "failed to stage asset: \(error.localizedDescription)" + self.fail(message) + DispatchQueue.main.async { completion(message) } + return + } + self.lock.lock() + self.temporaryFile = staged + let aborted = self.cancelled + self.lock.unlock() + if aborted { + try? FileManager.default.removeItem(at: staged) + return + } + self.queue.async { + let failureMessage = self.beginReading(from: staged) + DispatchQueue.main.async { completion(failureMessage) } + } + } + lock.lock() + download = task + lock.unlock() + task.resume() + } + + func cancel() { + lock.lock() + cancelled = true + let task = download + let staged = temporaryFile + download = nil + temporaryFile = nil + lock.unlock() + task?.cancel() + + queue.sync { + if statusObserved, let renderer { + renderer.removeObserver( + self, forKeyPath: "status", context: &AsbarProbe.statusContext) + statusObserved = false + } + renderer?.stopRequestingMediaData() + renderer?.flush() + synchronizer?.rate = 0 + if let renderer, let synchronizer { + synchronizer.removeRenderer(renderer, at: .zero, completionHandler: nil) + } + reader?.cancelReading() + reader = nil + output = nil + renderer = nil + synchronizer = nil + } + if let staged { try? FileManager.default.removeItem(at: staged) } + setPhase("cancelled") + } + + /// Runs on `queue`. Returns a message on failure. + private func beginReading(from url: URL) -> String? { + lock.lock() + let aborted = cancelled + lock.unlock() + if aborted { return nil } + + let asset = AVURLAsset(url: url) + guard let track = asset.tracks(withMediaType: .audio).first else { + let message = "no audio track in \(url.lastPathComponent)" + fail(message) + return message + } + guard + let nativeFormat = (track.formatDescriptions as? [CMFormatDescription])?.first + else { + let message = "audio track has no format description" + fail(message) + return message + } + describe(nativeFormat) + + let assetReader: AVAssetReader + do { + assetReader = try AVAssetReader(asset: asset) + } catch { + let message = "AVAssetReader init failed: \(error.localizedDescription)" + fail(message) + return message + } + // `nil` output settings is what keeps the samples compressed. + let trackOutput = AVAssetReaderTrackOutput(track: track, outputSettings: nil) + trackOutput.alwaysCopiesSampleData = false + guard assetReader.canAdd(trackOutput) else { + let message = "AVAssetReader rejected a compressed output" + fail(message) + return message + } + assetReader.add(trackOutput) + guard assetReader.startReading() else { + let message = + "AVAssetReader.startReading failed: \(assetReader.error?.localizedDescription ?? "unknown")" + fail(message) + return message + } + + var substituteFormat: CMFormatDescription? + if regenerateFormatDescription { + let rebuilt = Self.regenerate(from: nativeFormat) + guard let format = rebuilt.format else { + let message = rebuilt.error ?? "format regeneration failed" + fail(message) + return message + } + substituteFormat = format + describeUsed(format) + } else { + describeUsed(nativeFormat) + } + + if let message = configureSession() { return message } + + let renderer = AVSampleBufferAudioRenderer() + let synchronizer = AVSampleBufferRenderSynchronizer() + synchronizer.addRenderer(renderer) + // Deliberately NOT disabling delaysRateChangeUntilHasSufficientMediaData: + // the reliable-start preroll is part of the sequence under test. + renderer.addObserver( + self, forKeyPath: "status", options: [.new], context: &AsbarProbe.statusContext) + + self.renderer = renderer + self.synchronizer = synchronizer + self.reader = assetReader + self.output = trackOutput + statusObserved = true + + setPhase("feeding") + // Apple's order: request media first, start the clock after. + renderer.requestMediaDataWhenReady(on: queue) { [weak self] in + self?.pump(substituteFormat: substituteFormat) + } + synchronizer.rate = 1 + return nil + } + + /// Runs on `queue`. + private func pump(substituteFormat: CMFormatDescription?) { + guard let renderer, let output, let reader else { return } + while renderer.isReadyForMoreMediaData { + guard reader.status == .reading, let sample = output.copyNextSampleBuffer() else { + renderer.stopRequestingMediaData() + setPhase(reader.status == .completed ? "finished" : "stopped(\(reader.status.rawValue))") + return + } + let enqueued: CMSampleBuffer + if let substituteFormat { + guard let rewrapped = Self.rewrap(sample, with: substituteFormat) else { + fail("failed to rewrap a sample with the generated description") + renderer.stopRequestingMediaData() + return + } + enqueued = rewrapped + } else { + enqueued = sample + } + renderer.enqueue(enqueued) + lock.lock() + enqueuedSamples += 1 + lock.unlock() + } + } + + private func configureSession() -> String? { + #if os(iOS) || os(tvOS) + let session = AVAudioSession.sharedInstance() + do { + try session.setCategory( + .playback, mode: sessionMode, policy: .longFormAudio, options: []) + } catch { + let message = "long-form session profile rejected: \(error.localizedDescription)" + fail(message) + return message + } + if #available(iOS 15.0, tvOS 15.0, *) { + try? session.setSupportsMultichannelContent(true) + } + do { + try session.setActive(true) + } catch { + let message = "session activation failed: \(error.localizedDescription)" + fail(message) + return message + } + #endif + return nil + } + + override func observeValue( + forKeyPath keyPath: String?, of object: Any?, + change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer? + ) { + guard context == &AsbarProbe.statusContext else { + super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) + return + } + guard let renderer = object as? AVSampleBufferAudioRenderer, + renderer.status == .failed + else { return } + let error = renderer.error as NSError? + fail( + "renderer failed: \(error?.domain ?? "-"):\(error?.code ?? 0) " + + (error?.localizedDescription ?? "unknown")) + } + + func statusSnapshot() -> [String: Any] { + lock.lock() + defer { lock.unlock() } + var out: [String: Any] = [ + "state": phase, + "asbarEnqueuedSamples": enqueuedSamples, + "asbarNativeFormat": nativeDescription, + "asbarUsedFormat": usedDescription, + "asbarMagicCookie": magicCookieHex, + "asbarChannelLayout": layoutTagText, + ] + if let failure { out["error"] = failure } + if let renderer { + out["asbarRendererStatus"] = + switch renderer.status { + case .unknown: "unknown" + case .rendering: "rendering" + case .failed: "failed" + @unknown default: "unrecognized" + } + } + if let synchronizer { + out["currentTime"] = CMTimeGetSeconds(synchronizer.currentTime()) + } + return out + } + + // MARK: - Format description helpers + + private func describe(_ format: CMFormatDescription) { + let text = Self.summarize(format) + lock.lock() + nativeDescription = text.summary + magicCookieHex = text.cookie + layoutTagText = text.layout + lock.unlock() + } + + private func describeUsed(_ format: CMFormatDescription) { + let text = Self.summarize(format) + lock.lock() + usedDescription = text.summary + lock.unlock() + } + + private static func summarize( + _ format: CMFormatDescription + ) -> (summary: String, cookie: String, layout: String) { + var summary = "subType=\(fourCCText(CMFormatDescriptionGetMediaSubType(format)))" + if let asbd = CMAudioFormatDescriptionGetStreamBasicDescription(format)?.pointee { + summary += + String( + format: " rate=%.0f ch=%u framesPerPacket=%u", asbd.mSampleRate, + asbd.mChannelsPerFrame, asbd.mFramesPerPacket) + } + var cookieSize = 0 + var cookie = "none" + if let bytes = CMAudioFormatDescriptionGetMagicCookie(format, sizeOut: &cookieSize), + cookieSize > 0 + { + cookie = Data(bytes: bytes, count: cookieSize).map { String(format: "%02x", $0) } + .joined() + } + var layoutSize = 0 + var layout = "none" + if let acl = CMAudioFormatDescriptionGetChannelLayout(format, sizeOut: &layoutSize) { + layout = String(format: "0x%08x", acl.pointee.mChannelLayoutTag) + } + return (summary, cookie, layout) + } + + private static func fourCCText(_ code: FourCharCode) -> String { + let bytes = [ + UInt8((code >> 24) & 0xFF), UInt8((code >> 16) & 0xFF), + UInt8((code >> 8) & 0xFF), UInt8(code & 0xFF), + ] + return String(bytes: bytes, encoding: .ascii) ?? String(code) + } + + /// Rebuild the description the way the mpv AO does: same ASBD and magic + /// cookie, but constructed by us rather than parsed out of the container, + /// with the Dolby-order 5.1 layout attached. + private static func regenerate( + from native: CMFormatDescription + ) -> (format: CMFormatDescription?, error: String?) { + guard var asbd = CMAudioFormatDescriptionGetStreamBasicDescription(native)?.pointee else { + return (nil, "native description has no ASBD") + } + var cookieSize = 0 + var cookieBytes: [UInt8] = [] + if let bytes = CMAudioFormatDescriptionGetMagicCookie(native, sizeOut: &cookieSize), + cookieSize > 0 + { + cookieBytes = Array(UnsafeRawBufferPointer(start: bytes, count: cookieSize)) + } + var layout = AudioChannelLayout() + layout.mChannelLayoutTag = + asbd.mChannelsPerFrame == 8 + ? kAudioChannelLayoutTag_MPEG_7_1_C : kAudioChannelLayoutTag_MPEG_5_1_C + + var rebuilt: CMFormatDescription? + let status = cookieBytes.withUnsafeBytes { cookie -> OSStatus in + CMAudioFormatDescriptionCreate( + allocator: kCFAllocatorDefault, + asbd: &asbd, + layoutSize: MemoryLayout.size, + layout: &layout, + magicCookieSize: cookie.count, + magicCookie: cookie.baseAddress, + extensions: nil, + formatDescriptionOut: &rebuilt) + } + guard status == noErr, let rebuilt else { + return (nil, "CMAudioFormatDescriptionCreate failed (\(status))") + } + return (rebuilt, nil) + } + + private static func rewrap( + _ sample: CMSampleBuffer, with format: CMFormatDescription + ) -> CMSampleBuffer? { + guard let blockBuffer = CMSampleBufferGetDataBuffer(sample) else { return nil } + var timing = CMSampleTimingInfo() + guard CMSampleBufferGetSampleTimingInfo(sample, at: 0, timingInfoOut: &timing) == noErr + else { return nil } + var sizeOut = 0 + let sizeStatus = CMSampleBufferGetSampleSizeArray( + sample, entryCount: 0, arrayToFill: nil, entriesNeededOut: &sizeOut) + var sizes = [Int](repeating: 0, count: max(sizeOut, 1)) + if sizeStatus == noErr, sizeOut > 0 { + _ = CMSampleBufferGetSampleSizeArray( + sample, entryCount: sizeOut, arrayToFill: &sizes, entriesNeededOut: nil) + } else { + sizes[0] = CMBlockBufferGetDataLength(blockBuffer) + } + var rewrapped: CMSampleBuffer? + let status = CMSampleBufferCreateReady( + allocator: kCFAllocatorDefault, + dataBuffer: blockBuffer, + formatDescription: format, + sampleCount: CMSampleBufferGetNumSamples(sample), + sampleTimingEntryCount: 1, + sampleTimingArray: &timing, + sampleSizeEntryCount: sizes.count, + sampleSizeArray: &sizes, + sampleBufferOut: &rewrapped) + return status == noErr ? rewrapped : nil + } + + // MARK: - State + + private func setPhase(_ value: String) { + lock.lock() + phase = value + lock.unlock() + } + + private func fail(_ message: String) { + lock.lock() + if failure == nil { failure = message } + phase = "failed" + lock.unlock() + } +} diff --git a/test/screens/settings/atmos_diagnostics_screen_test.dart b/test/screens/settings/atmos_diagnostics_screen_test.dart index 16e6aa7f..93ed8d41 100644 --- a/test/screens/settings/atmos_diagnostics_screen_test.dart +++ b/test/screens/settings/atmos_diagnostics_screen_test.dart @@ -30,7 +30,10 @@ void main() { Future pumpScreen(WidgetTester tester) async { await tester.pumpWidget(MaterialApp(theme: monoTheme(dark: true), home: const AtmosDiagnosticsScreen())); await tester.pump(); + // The screen is taller than the test viewport, so the scroll has to settle + // before the stop tile is hit-testable. await tester.ensureVisible(find.text(t.settings.atmosTestStop)); + await tester.pumpAndSettle(); } testWidgets('unmounting during stop does not set state or stop twice', (tester) async { diff --git a/test/services/music/music_playback_service_test.dart b/test/services/music/music_playback_service_test.dart index e619a5f3..c637c896 100644 --- a/test/services/music/music_playback_service_test.dart +++ b/test/services/music/music_playback_service_test.dart @@ -9,6 +9,7 @@ import 'package:plezy/media/media_item.dart'; import 'package:plezy/media/media_kind.dart'; import 'package:plezy/media/media_server_client.dart'; import 'package:plezy/mpv/models.dart'; +import 'package:plezy/mpv/player/audio_rendering_mode.dart'; import 'package:plezy/mpv/player/player.dart'; import 'package:plezy/mpv/player/player_state.dart'; import 'package:plezy/mpv/player/player_streams.dart'; @@ -320,6 +321,9 @@ class FakePlayer implements Player { @override Future setAudioPassthrough(bool enabled) async {} + @override + Future getAudioRenderingMode() async => null; + @override Future setAudioNormalization(bool enabled) async {} diff --git a/tvos/Runner.xcodeproj/project.pbxproj b/tvos/Runner.xcodeproj/project.pbxproj index a13afd4e..975058bb 100644 --- a/tvos/Runner.xcodeproj/project.pbxproj +++ b/tvos/Runner.xcodeproj/project.pbxproj @@ -1140,7 +1140,7 @@ repositoryURL = "https://github.com/edde746/MPVKit"; requirement = { kind = exactVersion; - version = 1.0.13; + version = 1.0.14; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/tvos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/tvos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 327a8153..47e29ffe 100644 --- a/tvos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/tvos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/edde746/MPVKit", "state" : { - "revision" : "93101dc1d0903c48fa3054652805acacbb75e856", - "version" : "1.0.13" + "revision" : "3309e7c158e64adc9a5666df5e7aa474f2d3aaec", + "version" : "1.0.14" } } ], diff --git a/tvos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved b/tvos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved index 327a8153..47e29ffe 100644 --- a/tvos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/tvos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/edde746/MPVKit", "state" : { - "revision" : "93101dc1d0903c48fa3054652805acacbb75e856", - "version" : "1.0.13" + "revision" : "3309e7c158e64adc9a5666df5e7aa474f2d3aaec", + "version" : "1.0.14" } } ], diff --git a/tvos/Runner/AppDelegate.swift b/tvos/Runner/AppDelegate.swift index 272a2b44..18ec5676 100644 --- a/tvos/Runner/AppDelegate.swift +++ b/tvos/Runner/AppDelegate.swift @@ -118,11 +118,24 @@ import wakelock_plus _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + // Dolby's sequence diagram prescribes exactly this at app launch: the + // long-form playback profile, then activation, so the session is eligible + // for the system's Dolby decode/render path and its rendering capabilities + // can be read before any content is chosen. The mpv AVFoundation audio + // output reconfigures and re-activates the same shared session at playback + // start; this establishes the launch-time state the guide expects. do { let session = AVAudioSession.sharedInstance() - try session.setCategory(.playback, mode: .default) + try session.setCategory( + .playback, mode: .default, policy: .longFormAudio, options: []) + try session.setActive(true) } catch { - print("Failed to configure audio session: \(error)") + print("Failed to configure long-form audio session: \(error)") + do { + try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default) + } catch { + print("Failed to configure audio session: \(error)") + } } application.beginReceivingRemoteControlEvents() diff --git a/tvos/scripts/test_wire_mpv.rb b/tvos/scripts/test_wire_mpv.rb index be5fac98..047bac72 100755 --- a/tvos/scripts/test_wire_mpv.rb +++ b/tvos/scripts/test_wire_mpv.rb @@ -26,8 +26,8 @@ class WireMpvTest < Minitest::Test ].freeze MPVKIT_PIN = { 'location' => 'https://github.com/edde746/MPVKit', - 'revision' => '93101dc1d0903c48fa3054652805acacbb75e856', - 'version' => '1.0.13', + 'revision' => '3309e7c158e64adc9a5666df5e7aa474f2d3aaec', + 'version' => '1.0.14', }.freeze def setup diff --git a/tvos/scripts/wire_mpv.rb b/tvos/scripts/wire_mpv.rb index fe338de0..06f88e1c 100755 --- a/tvos/scripts/wire_mpv.rb +++ b/tvos/scripts/wire_mpv.rb @@ -50,7 +50,7 @@ end # Swift Package: MPVKit. Restore each graph edge independently so a project # with a surviving package reference cannot silently omit the Runner linkage. pkg_url = 'https://github.com/edde746/MPVKit' -pkg_version = '1.0.13' +pkg_version = '1.0.14' pkg = project.root_object.package_references.find do |candidate| candidate.repositoryURL == pkg_url rescue false end