diff --git a/lib/components/TranscodingSettingsScreen/VorbisSwitch.dart b/lib/components/TranscodingSettingsScreen/VorbisSwitch.dart new file mode 100644 index 000000000..6496936bb --- /dev/null +++ b/lib/components/TranscodingSettingsScreen/VorbisSwitch.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:hive/hive.dart'; + +import '../../services/FinampSettingsHelper.dart'; +import '../../models/FinampModels.dart'; + +class VorbisSwitch extends StatelessWidget { + const VorbisSwitch({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder>( + valueListenable: FinampSettingsHelper.finampSettingsListener, + builder: (context, box, child) { + bool? useVorbis = box.get("FinampSettings")?.useVorbis; + + return SwitchListTile( + title: const Text("Use Vorbis Codec"), + subtitle: const Text( + "If enabled, music streams will be transcoded to Vorbis and not AAC by the server."), + value: useVorbis ?? false, + onChanged: useVorbis == null + ? null + : (value) { + FinampSettings finampSettingsTemp = + box.get("FinampSettings")!; + finampSettingsTemp.useVorbis = value; + box.put("FinampSettings", finampSettingsTemp); + }, + ); + }, + ); + } +} diff --git a/lib/models/FinampModels.dart b/lib/models/FinampModels.dart index 77dd0353c..2412d3bcb 100644 --- a/lib/models/FinampModels.dart +++ b/lib/models/FinampModels.dart @@ -44,6 +44,7 @@ const _contentGridViewCrossAxisCountPortrait = 2; const _contentGridViewCrossAxisCountLandscape = 3; const _showTextOnGridView = true; const _sleepTimerSeconds = 1800; // 30 Minutes +const _useVorbis = false; @HiveType(typeId: 28) class FinampSettings { @@ -68,6 +69,7 @@ class FinampSettings { _contentGridViewCrossAxisCountLandscape, this.showTextOnGridView = _showTextOnGridView, this.sleepTimerSeconds = _sleepTimerSeconds, + this.useVorbis = _useVorbis, }); @HiveField(0) @@ -123,6 +125,11 @@ class FinampSettings { @HiveField(14, defaultValue: _sleepTimerSeconds) int sleepTimerSeconds; + /// Whether or not to request Vorbis as the transcoding codec. + /// If false, AAC will be used. + @HiveField(15, defaultValue: _useVorbis) + bool useVorbis; + static Future create() async { Directory internalSongDir = await getInternalSongDir(); return FinampSettings( diff --git a/lib/models/FinampModels.g.dart b/lib/models/FinampModels.g.dart index fb823e7bb..823dd1e37 100644 --- a/lib/models/FinampModels.g.dart +++ b/lib/models/FinampModels.g.dart @@ -178,13 +178,14 @@ class FinampSettingsAdapter extends TypeAdapter { fields[12] == null ? 3 : fields[12] as int, showTextOnGridView: fields[13] == null ? true : fields[13] as bool, sleepTimerSeconds: fields[14] == null ? 1800 : fields[14] as int, + useVorbis: fields[15] == null ? false : fields[15] as bool, ); } @override void write(BinaryWriter writer, FinampSettings obj) { writer - ..writeByte(15) + ..writeByte(16) ..writeByte(0) ..write(obj.isOffline) ..writeByte(1) @@ -214,7 +215,9 @@ class FinampSettingsAdapter extends TypeAdapter { ..writeByte(13) ..write(obj.showTextOnGridView) ..writeByte(14) - ..write(obj.sleepTimerSeconds); + ..write(obj.sleepTimerSeconds) + ..writeByte(15) + ..write(obj.useVorbis); } @override diff --git a/lib/screens/TranscodingSettingsScreen.dart b/lib/screens/TranscodingSettingsScreen.dart index e09ab379c..b42d31d99 100644 --- a/lib/screens/TranscodingSettingsScreen.dart +++ b/lib/screens/TranscodingSettingsScreen.dart @@ -1,7 +1,10 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import '../components/TranscodingSettingsScreen/TranscodeSwitch.dart'; import '../components/TranscodingSettingsScreen/BitrateSelector.dart'; +import '../components/TranscodingSettingsScreen/VorbisSwitch.dart'; class TranscodingSettingsScreen extends StatelessWidget { const TranscodingSettingsScreen({Key? key}) : super(key: key); @@ -17,14 +20,7 @@ class TranscodingSettingsScreen extends StatelessWidget { children: [ const TranscodeSwitch(), const BitrateSelector(), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - "Jellyfin uses AAC for transcoding.", - style: Theme.of(context).textTheme.caption, - textAlign: TextAlign.center, - ), - ), + if (!(Platform.isIOS || Platform.isMacOS)) const VorbisSwitch(), ], ), ), diff --git a/lib/services/AudioServiceHelper.dart b/lib/services/AudioServiceHelper.dart index 906115ab6..e1c94128f 100644 --- a/lib/services/AudioServiceHelper.dart +++ b/lib/services/AudioServiceHelper.dart @@ -234,6 +234,7 @@ class AudioServiceHelper { "shouldTranscode": FinampSettingsHelper.finampSettings.shouldTranscode, "downloadedSongJson": (await _getDownloadedSong(item.id))?.toJson(), "isOffline": FinampSettingsHelper.finampSettings.isOffline, + "useVorbis": FinampSettingsHelper.finampSettings.useVorbis, // TODO: Maybe add transcoding bitrate here? }, rating: Rating.newHeartRating(item.userData?.isFavorite ?? false), diff --git a/lib/services/MusicPlayerBackgroundTask.dart b/lib/services/MusicPlayerBackgroundTask.dart index 2ef0e3781..2700b6042 100644 --- a/lib/services/MusicPlayerBackgroundTask.dart +++ b/lib/services/MusicPlayerBackgroundTask.dart @@ -473,7 +473,8 @@ class MusicPlayerBackgroundTask extends BaseAudioHandler { return Future.error( "Offline mode enabled but downloaded song not found."); } else { - if (mediaItem.extras!["shouldTranscode"] == true) { + if (mediaItem.extras!["shouldTranscode"] == true && + mediaItem.extras!["useVorbis"] == false) { return HlsAudioSource(await _songUri(mediaItem)); } else { return AudioSource.uri(await _songUri(mediaItem)); @@ -524,10 +525,10 @@ class MusicPlayerBackgroundTask extends BaseAudioHandler { "MaxStreamingBitrate": mediaItem.extras!["shouldTranscode"] ? FinampSettingsHelper.finampSettings.transcodeBitrate.toString() : "999999999", - "AudioCodec": "aac", + "AudioCodec": mediaItem.extras!["useVorbis"] ? "vorbis" : "aac", "TranscodingContainer": "ts", "TranscodingProtocol": - mediaItem.extras!["shouldTranscode"] ? "hls" : "http", + mediaItem.extras!["shouldTranscode"] ? (mediaItem.extras!["useVorbis"] ? "http" : "hls") : "http", "ApiKey": _jellyfinApiData.currentUser!.accessToken, }, );