/** * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { Platform } from "react-native"; import MediaTypes from "../../constants/MediaTypes"; import { getSubtitleProfiles } from "./subtitles"; export type PlatformType = "ios" | "android"; export type PlayerType = "mpv"; export type AudioTranscodeModeType = "auto" | "stereo" | "5.1" | "passthrough"; export interface ProfileOptions { /** Target platform */ platform?: PlatformType; /** Video player being used */ player?: PlayerType; /** Audio transcoding mode */ audioMode?: AudioTranscodeModeType; } /** * Audio direct play profiles for standalone audio items in MPV player. * These define which audio file formats can be played directly without transcoding. */ const getAudioDirectPlayProfile = (platform: PlatformType) => { if (platform === "ios") { // iOS audio formats supported by MPV return { Type: MediaTypes.Audio, Container: "mp3,m4a,aac,flac,alac,wav,aiff,caf", AudioCodec: "mp3,aac,alac,flac,opus,pcm", }; } // Android audio formats supported by MPV return { Type: MediaTypes.Audio, Container: "mp3,m4a,aac,ogg,flac,wav,webm,mka", AudioCodec: "mp3,aac,flac,vorbis,opus,pcm", }; }; /** * Audio codec profiles for standalone audio items in MPV player. * These define codec constraints for audio file playback. */ const getAudioCodecProfile = (platform: PlatformType) => { if (platform === "ios") { // iOS audio codec constraints for MPV return { Type: MediaTypes.Audio, Codec: "aac,ac3,eac3,mp3,flac,alac,opus,pcm", }; } // Android audio codec constraints for MPV return { Type: MediaTypes.Audio, Codec: "aac,ac3,eac3,mp3,flac,vorbis,opus,pcm", }; }; /** * Gets the video audio codec configuration based on platform and audio mode. * * MPV (via FFmpeg) can decode all audio codecs including TrueHD and DTS-HD MA. * The audioMode setting only controls the maximum channel count - MPV will * decode and downmix as needed. */ const getVideoAudioCodecs = ( platform: PlatformType, audioMode: AudioTranscodeModeType, ): { directPlayCodec: string; maxAudioChannels: string } => { // Base codecs const baseCodecs = "aac,mp3,flac,opus,vorbis"; // Surround codecs const surroundCodecs = "ac3,eac3,dts"; // Lossless HD codecs - MPV decodes these and downmixes as needed const losslessHdCodecs = "truehd"; // Platform-specific codecs const platformCodecs = platform === "ios" ? "alac,wma" : "wma"; // MPV can decode all codecs - only channel count varies by mode const allCodecs = `${baseCodecs},${surroundCodecs},${losslessHdCodecs},${platformCodecs}`; switch (audioMode) { case "stereo": // Limit to 2 channels - MPV will decode and downmix return { directPlayCodec: allCodecs, maxAudioChannels: "2", }; case "5.1": // Limit to 6 channels return { directPlayCodec: allCodecs, maxAudioChannels: "6", }; case "passthrough": // Allow up to 8 channels - for external DAC/receiver setups return { directPlayCodec: allCodecs, maxAudioChannels: "8", }; default: // Auto mode: default to 5.1 (6 channels) return { directPlayCodec: allCodecs, maxAudioChannels: "6", }; } }; /** * Generates a device profile for Jellyfin playback. */ export const generateDeviceProfile = (options: ProfileOptions = {}) => { const platform = (options.platform || Platform.OS) as PlatformType; const audioMode = options.audioMode || "auto"; const { directPlayCodec, maxAudioChannels } = getVideoAudioCodecs( platform, audioMode, ); /** * Device profile for MPV player */ const profile = { Name: "1. MPV", MaxStaticBitrate: 999_999_999, MaxStreamingBitrate: 999_999_999, CodecProfiles: [ { Type: MediaTypes.Video, Codec: "h264,mpeg4,divx,xvid,wmv,vc1,vp8,vp9,av1", }, { Type: MediaTypes.Video, Codec: "hevc,h265", Conditions: [ { Condition: "LessThanEqual", Property: "VideoLevel", Value: "153", IsRequired: false, }, { Condition: "NotEquals", Property: "VideoRangeType", Value: "DOVI", //no dolby vision at all IsRequired: true, }, ], }, getAudioCodecProfile(platform), ], DirectPlayProfiles: [ { Type: MediaTypes.Video, Container: "mp4,mkv,avi,mov,flv,ts,m2ts,webm,ogv,3gp,hls", VideoCodec: "h264,hevc,mpeg4,divx,xvid,wmv,vc1,vp8,vp9,av1,avi,mpeg,mpeg2video", AudioCodec: directPlayCodec, }, getAudioDirectPlayProfile(platform), ], TranscodingProfiles: [ { Type: MediaTypes.Video, Context: "Streaming", Protocol: "hls", Container: "ts", VideoCodec: "h264, hevc", AudioCodec: "aac,mp3,ac3,dts", MaxAudioChannels: maxAudioChannels, }, { Type: MediaTypes.Audio, Context: "Streaming", Protocol: "http", Container: "mp3", AudioCodec: "mp3", MaxAudioChannels: "2", }, ], SubtitleProfiles: getSubtitleProfiles(), }; return profile; }; // Default export for backward compatibility export default generateDeviceProfile();