Implement Liquidsoap 2.2.x Rolling Release (#6249)
* Update paths for fallbacks in utility scripts. * Move LS util files up. * Update installed LS version. * Initial LS config changes for 2.2.x. * Fix Shoutcast on 2.2.x. * Update changelog. * Replace deprecated LS operators & fix a warning (#6246) * Update Liquidsoap 2.2.x rolling release. * Don't send empty annotations. * Update for Enums.
This commit is contained in:
parent
437ca77ead
commit
35a6c8c014
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -3,6 +3,20 @@
|
|||
These changes have not yet been incorporated into a stable release, but if you are on the latest version of the rolling
|
||||
release channel, you can take advantage of these new features and fixes.
|
||||
|
||||
## New Features/Changes
|
||||
|
||||
- **Update to Liquidsoap 2.2.x**: We're updating to the latest version of Liquidsoap, which includes many bug fixes,
|
||||
performance improvements and other changes. We have adopted our syntax to match Liquidsoap's new supported syntax, but
|
||||
if you use custom Liquidsoap code, you will need to update your code accordingly. You can see the most important
|
||||
changes in this [migration guide](https://www.liquidsoap.info/doc-dev/migrating.html#from-2.1.x-to-2.2.x). The most
|
||||
common changes you will need to make are to mutable (`ref()`) variables:
|
||||
- `!var` becomes `var()`
|
||||
- `var := value` optionally becomes `var.set(value)`
|
||||
|
||||
## Code Quality/Technical Changes
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
---
|
||||
|
||||
# AzuraCast 0.18.3 (Jun 5, 2023)
|
||||
|
|
|
@ -31,4 +31,6 @@ interface StationMountInterface
|
|||
public function getAutodjAdapterType(): AdapterTypeInterface;
|
||||
|
||||
public function getIsPublic(): bool;
|
||||
|
||||
public function getIsShoutcast(): bool;
|
||||
}
|
||||
|
|
|
@ -413,6 +413,14 @@ class StationMount implements
|
|||
return $this->getStation()->getFrontendType();
|
||||
}
|
||||
|
||||
public function getIsShoutcast(): bool
|
||||
{
|
||||
return match ($this->getAutodjAdapterType()) {
|
||||
FrontendAdapters::Shoutcast => true,
|
||||
default => false
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the API version of the object/array.
|
||||
*
|
||||
|
|
|
@ -11,7 +11,6 @@ use App\Radio\Enums\StreamProtocols;
|
|||
use App\Radio\Remote\AbstractRemote;
|
||||
use App\Utilities;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Stringable;
|
||||
|
||||
|
@ -376,6 +375,14 @@ class StationRemote implements
|
|||
return (RemoteAdapters::AzuraRelay !== $this->getType());
|
||||
}
|
||||
|
||||
public function getIsShoutcast(): bool
|
||||
{
|
||||
return match ($this->getAutodjAdapterType()) {
|
||||
RemoteAdapters::Shoutcast1, RemoteAdapters::Shoutcast2 => true,
|
||||
default => false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the API version of the object/array.
|
||||
*
|
||||
|
|
|
@ -83,44 +83,56 @@ final class Annotations implements EventSubscriberInterface
|
|||
return;
|
||||
}
|
||||
|
||||
$backendConfig = $station->getBackendConfig();
|
||||
|
||||
$annotations = [];
|
||||
$annotationsRaw = [
|
||||
$annotationsRaw = array_filter([
|
||||
'title' => $media->getTitle(),
|
||||
'artist' => $media->getArtist(),
|
||||
'duration' => $media->getLength(),
|
||||
'song_id' => $media->getSongId(),
|
||||
'media_id' => $media->getId(),
|
||||
'liq_amplify' => $media->getAmplify() ?? 0.0,
|
||||
'liq_cross_duration' => $media->getFadeOverlap() ?? $backendConfig->getCrossfadeDuration(),
|
||||
'liq_fade_in' => $media->getFadeIn() ?? $backendConfig->getCrossfade(),
|
||||
'liq_fade_out' => $media->getFadeOut() ?? $backendConfig->getCrossfade(),
|
||||
'liq_amplify' => $media->getAmplify(),
|
||||
'liq_cross_duration' => $media->getFadeOverlap(),
|
||||
'liq_fade_in' => $media->getFadeIn(),
|
||||
'liq_fade_out' => $media->getFadeOut(),
|
||||
'liq_cue_in' => $media->getCueIn(),
|
||||
'liq_cue_out' => $media->getCueOut(),
|
||||
];
|
||||
]);
|
||||
|
||||
// Safety checks for cue lengths.
|
||||
if ($annotationsRaw['liq_cue_out'] < 0) {
|
||||
if (
|
||||
isset($annotationsRaw['liq_cue_out'])
|
||||
&& $annotationsRaw['liq_cue_out'] < 0
|
||||
) {
|
||||
$cue_out = abs($annotationsRaw['liq_cue_out']);
|
||||
if (0.0 === $cue_out || $cue_out > $annotationsRaw['duration']) {
|
||||
$annotationsRaw['liq_cue_out'] = null;
|
||||
} else {
|
||||
$annotationsRaw['liq_cue_out'] = max(0, $annotationsRaw['duration'] - $cue_out);
|
||||
|
||||
if (0.0 === $cue_out) {
|
||||
unset($annotationsRaw['liq_cue_out']);
|
||||
}
|
||||
|
||||
if (isset($annotationsRaw['duration'])) {
|
||||
if ($cue_out > $annotationsRaw['duration']) {
|
||||
unset($annotationsRaw['liq_cue_out']);
|
||||
} else {
|
||||
$annotationsRaw['liq_cue_out'] = max(0, $annotationsRaw['duration'] - $cue_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($annotationsRaw['liq_cue_out'] > $annotationsRaw['duration']) {
|
||||
$annotationsRaw['liq_cue_out'] = null;
|
||||
|
||||
if (
|
||||
isset($annotationsRaw['liq_cue_out'], $annotationsRaw['duration'])
|
||||
&& $annotationsRaw['liq_cue_out'] > $annotationsRaw['duration']
|
||||
) {
|
||||
unset($annotationsRaw['liq_cue_out']);
|
||||
}
|
||||
if ($annotationsRaw['liq_cue_in'] > $annotationsRaw['duration']) {
|
||||
$annotationsRaw['liq_cue_in'] = null;
|
||||
|
||||
if (
|
||||
isset($annotationsRaw['liq_cue_in'], $annotationsRaw['duration'])
|
||||
&& $annotationsRaw['liq_cue_in'] > $annotationsRaw['duration']
|
||||
) {
|
||||
unset($annotationsRaw['liq_cue_in']);
|
||||
}
|
||||
|
||||
foreach ($annotationsRaw as $name => $prop) {
|
||||
if (null === $prop) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$prop = ConfigWriter::annotateString((string)$prop);
|
||||
|
||||
// Convert Liquidsoap-specific annotations to floats.
|
||||
|
|
|
@ -201,11 +201,9 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
settings.server.socket.path.set("{$socketFile}")
|
||||
|
||||
settings.harbor.bind_addrs.set(["0.0.0.0"])
|
||||
|
||||
settings.tag.encodings.set(["UTF-8","ISO-8859-1"])
|
||||
settings.encoder.metadata.export.set(["artist","title","album","song"])
|
||||
|
||||
setenv("TZ", "{$stationTz}")
|
||||
environment.set("TZ", "{$stationTz}")
|
||||
|
||||
autodj_is_loading = ref(true)
|
||||
ignore(autodj_is_loading)
|
||||
|
@ -233,8 +231,8 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
<<<LIQ
|
||||
azuracast_api_url = "{$stationApiUrl}"
|
||||
azuracast_api_key = "{$stationApiAuth}"
|
||||
|
||||
def azuracast_api_call(~timeout_ms=2000, url, payload) =
|
||||
|
||||
def azuracast_api_call(~timeout=2.0, url, payload) =
|
||||
full_url = "#{azuracast_api_url}/#{url}"
|
||||
|
||||
log("API #{url} - Sending POST request to '#{full_url}' with body: #{payload}")
|
||||
|
@ -245,7 +243,7 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
("User-Agent", "Liquidsoap AzuraCast"),
|
||||
("X-Liquidsoap-Api-Key", "#{azuracast_api_key}")
|
||||
],
|
||||
timeout_ms=timeout_ms,
|
||||
timeout=timeout,
|
||||
data=payload
|
||||
)
|
||||
|
||||
|
@ -271,7 +269,7 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
["#{station_media_dir}/#{arg}"]
|
||||
end
|
||||
|
||||
add_protocol(
|
||||
protocol.add(
|
||||
"media",
|
||||
azuracast_media_protocol,
|
||||
doc="Pull files from AzuraCast media directory.",
|
||||
|
@ -283,15 +281,15 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
$event->appendBlock(
|
||||
<<<LIQ
|
||||
def azuracast_media_protocol(~rlog=_,~maxtime,arg) =
|
||||
timeout_ms = 1000 * (int_of_float(maxtime) - int_of_float(time()))
|
||||
|
||||
timeout = 1000.0 * (maxtime - time())
|
||||
|
||||
j = json()
|
||||
j.add("uri", arg)
|
||||
|
||||
[azuracast_api_call(timeout_ms=timeout_ms, "cp", json.stringify(j))]
|
||||
|
||||
[azuracast_api_call(timeout=timeout, "cp", json.stringify(j))]
|
||||
end
|
||||
|
||||
add_protocol(
|
||||
protocol.add(
|
||||
"media",
|
||||
azuracast_media_protocol,
|
||||
temporary=true,
|
||||
|
@ -605,22 +603,22 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
|
||||
# Delayed ping for AutoDJ Next Song
|
||||
def wait_for_next_song(autodj)
|
||||
autodj_ping_attempts := !autodj_ping_attempts + 1
|
||||
|
||||
autodj_ping_attempts.set(autodj_ping_attempts() + 1)
|
||||
|
||||
if source.is_ready(autodj) then
|
||||
log("AutoDJ is ready!")
|
||||
autodj_is_loading := false
|
||||
autodj_is_loading.set(false)
|
||||
-1.0
|
||||
elsif !autodj_ping_attempts > 200 then
|
||||
elsif autodj_ping_attempts() > 200 then
|
||||
log("AutoDJ could not be initialized within the specified timeout.")
|
||||
autodj_is_loading := false
|
||||
autodj_is_loading.set(false)
|
||||
-1.0
|
||||
else
|
||||
0.5
|
||||
end
|
||||
end
|
||||
|
||||
dynamic = request.dynamic(id="next_song", timeout=20., retry_delay=10., autodj_next_song)
|
||||
|
||||
dynamic = request.dynamic(id="next_song", timeout=20.0, retry_delay=10., autodj_next_song)
|
||||
dynamic = cue_cut(id="cue_next_song", dynamic)
|
||||
|
||||
dynamic_startup = fallback(
|
||||
|
@ -630,14 +628,14 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
dynamic,
|
||||
source.available(
|
||||
blank(id = "autodj_startup_blank", duration = 120.),
|
||||
predicate.activates({!autodj_is_loading})
|
||||
predicate.activates({autodj_is_loading()})
|
||||
)
|
||||
]
|
||||
)
|
||||
radio = fallback(id="autodj_fallback", track_sensitive = true, [dynamic_startup, radio])
|
||||
|
||||
ref_dynamic = ref(dynamic);
|
||||
thread.run.recurrent(delay=0.25, { wait_for_next_song(!ref_dynamic) })
|
||||
thread.run.recurrent(delay=0.25, { wait_for_next_song(ref_dynamic()) })
|
||||
LIQ
|
||||
);
|
||||
}
|
||||
|
@ -833,7 +831,7 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
$event->appendBlock(
|
||||
<<<LS
|
||||
def live_aware_crossfade(old, new) =
|
||||
if !to_live then
|
||||
if to_live() then
|
||||
# If going to the live show, play a simple sequence
|
||||
sequence([fade.out(old.source),fade.in(new.source)])
|
||||
else
|
||||
|
@ -884,13 +882,13 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
end
|
||||
|
||||
response = azuracast_api_call(
|
||||
timeout_ms=5000,
|
||||
timeout=5.0,
|
||||
"auth",
|
||||
json.stringify(auth_info)
|
||||
)
|
||||
|
||||
if (response == "true") then
|
||||
last_authenticated_dj := auth_info.user
|
||||
last_authenticated_dj.set(auth_info.user)
|
||||
true
|
||||
else
|
||||
false
|
||||
|
@ -898,14 +896,14 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
end
|
||||
|
||||
def live_connected(header) =
|
||||
dj = !last_authenticated_dj
|
||||
dj = last_authenticated_dj()
|
||||
log("DJ Source connected! Last authenticated DJ: #{dj} - #{header}")
|
||||
|
||||
live_enabled := true
|
||||
live_dj := dj
|
||||
|
||||
|
||||
live_enabled.set(true)
|
||||
live_dj.set(dj)
|
||||
|
||||
_ = azuracast_api_call(
|
||||
timeout_ms=5000,
|
||||
timeout=5.0,
|
||||
"djon",
|
||||
json.stringify({user = dj})
|
||||
)
|
||||
|
@ -913,13 +911,13 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
|
||||
def live_disconnected() =
|
||||
_ = azuracast_api_call(
|
||||
timeout_ms=5000,
|
||||
timeout=5.0,
|
||||
"djoff",
|
||||
json.stringify({user = !live_dj})
|
||||
json.stringify({user = live_dj()})
|
||||
)
|
||||
|
||||
live_enabled := false
|
||||
live_dj := ""
|
||||
|
||||
live_enabled.set(false)
|
||||
live_dj.set("")
|
||||
end
|
||||
LIQ
|
||||
);
|
||||
|
@ -967,12 +965,12 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
# Skip non-live track when live DJ goes live.
|
||||
def check_live() =
|
||||
if live.is_ready() then
|
||||
if not !to_live then
|
||||
to_live := true
|
||||
if not to_live() then
|
||||
to_live.set(true)
|
||||
radio_without_live.skip()
|
||||
end
|
||||
else
|
||||
to_live := false
|
||||
to_live.set(false)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -997,10 +995,11 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
recording_extension = "{$recordExtension}"
|
||||
|
||||
output.file(
|
||||
{$formatString},
|
||||
{$formatString},
|
||||
fun () -> begin
|
||||
if (!live_enabled) then
|
||||
"#{recording_base_path}/#{!live_dj}/{$recordPathPrefix}_%Y%m%d-%H%M%S.#{recording_extension}.tmp"
|
||||
if (live_enabled()) then
|
||||
"#{recording_base_path}/#{live_dj()}/{$recordPathPrefix}_%Y%m%d-%H%M%S.#{recording_extension}.tmp"
|
||||
else
|
||||
""
|
||||
end
|
||||
|
@ -1058,7 +1057,10 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
<<<LIQ
|
||||
error_file = single(id="error_jingle", "{$errorFile}")
|
||||
|
||||
error_file = single(id="error_jingle", "{$errorFile}")
|
||||
|
||||
def tag_error_file(m) =
|
||||
ignore(m)
|
||||
ignore(m)
|
||||
[("is_error_file", "true")]
|
||||
end
|
||||
|
@ -1077,10 +1079,10 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
def metadata_updated(m) =
|
||||
def f() =
|
||||
if (m["is_error_file"] != "true") then
|
||||
if (m["title"] != !last_title or m["artist"] != !last_artist) then
|
||||
last_title := m["title"]
|
||||
last_artist := m["artist"]
|
||||
|
||||
if (m["title"] != last_title() or m["artist"] != last_artist()) then
|
||||
last_title.set(m["title"])
|
||||
last_artist.set(m["artist"])
|
||||
|
||||
j = json()
|
||||
|
||||
if (m["song_id"] != "") then
|
||||
|
@ -1109,9 +1111,9 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
last_metadata = ref([])
|
||||
def handle_jingle_mode(m) =
|
||||
if (m["jingle_mode"] == "true") then
|
||||
!last_metadata
|
||||
last_metadata()
|
||||
else
|
||||
last_metadata := m
|
||||
last_metadata.set(m)
|
||||
m
|
||||
end
|
||||
end
|
||||
|
@ -1284,7 +1286,10 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
}
|
||||
|
||||
$output_params[] = 'name = "' . self::cleanUpString($station->getName()) . '"';
|
||||
$output_params[] = 'description = "' . self::cleanUpString($station->getDescription()) . '"';
|
||||
|
||||
if (!$mount->getIsShoutcast()) {
|
||||
$output_params[] = 'description = "' . self::cleanUpString($station->getDescription()) . '"';
|
||||
}
|
||||
$output_params[] = 'genre = "' . self::cleanUpString($station->getGenre()) . '"';
|
||||
|
||||
if (!empty($station->getUrl())) {
|
||||
|
@ -1294,17 +1299,21 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
$output_params[] = 'public = ' . ($mount->getIsPublic() ? 'true' : 'false');
|
||||
$output_params[] = 'encoding = "' . $charset . '"';
|
||||
|
||||
if (null !== $protocol) {
|
||||
if (!$mount->getIsShoutcast() && null !== $protocol) {
|
||||
$output_params[] = 'protocol="' . $protocol->value . '"';
|
||||
}
|
||||
|
||||
if ($format->sendIcyMetadata()) {
|
||||
$output_params[] = 'icy_metadata="true"';
|
||||
$output_params[] = 'send_icy_metadata="true"';
|
||||
}
|
||||
|
||||
$output_params[] = 'radio';
|
||||
|
||||
return 'output.icecast(' . implode(', ', $output_params) . ')';
|
||||
$outputCommand = ($mount->getIsShoutcast())
|
||||
? 'output.shoutcast'
|
||||
: 'output.icecast';
|
||||
|
||||
return $outputCommand . '(' . implode(', ', $output_params) . ')';
|
||||
}
|
||||
|
||||
private function getOutputFormatString(StreamFormats $format, int $bitrate = 128): string
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
liquidsoap.chroot.make('/tmp/liquidsoap')
|
||||
shutdown()
|
|
@ -15,14 +15,12 @@ apt-get install -y --no-install-recommends ladspa-sdk
|
|||
|
||||
# Per-architecture LS installs
|
||||
ARCHITECTURE=amd64
|
||||
ARM_FULL_BUILD="${ARM_FULL_BUILD:-false}"
|
||||
|
||||
if [[ "$(uname -m)" = "aarch64" && ${ARM_FULL_BUILD} == "false" ]]; then
|
||||
if [[ "$(uname -m)" = "aarch64" ]]; then
|
||||
ARCHITECTURE=arm64
|
||||
fi
|
||||
|
||||
# wget -O /tmp/liquidsoap.deb "https://github.com/savonet/liquidsoap/releases/download/v2.1.4/liquidsoap_2.1.4-ubuntu-jammy-1_${ARCHITECTURE}.deb"
|
||||
wget -O /tmp/liquidsoap.deb "https://github.com/savonet/liquidsoap-release-assets/releases/download/rolling-release-v2.1.x/liquidsoap-d6313d1_2.1.5-ubuntu-jammy-1_${ARCHITECTURE}.deb"
|
||||
wget -O /tmp/liquidsoap.deb "https://github.com/savonet/liquidsoap-release-assets/releases/download/rolling-release-v2.2.x/liquidsoap-8101608_2.2.0-ubuntu-jammy-1_${ARCHITECTURE}.deb"
|
||||
|
||||
dpkg -i /tmp/liquidsoap.deb
|
||||
apt-get install -y -f --no-install-recommends
|
||||
|
|
|
@ -17,14 +17,14 @@ output.file(%vorbis.cbr(samplerate=44100, channels=2, bitrate=128), "fallback-[1
|
|||
output.file(%vorbis.cbr(samplerate=44100, channels=2, bitrate=192), "fallback-[192].ogg", input, fallible=true)
|
||||
output.file(%vorbis.cbr(samplerate=44100, channels=2, bitrate=256), "fallback-[256].ogg", input, fallible=true)
|
||||
output.file(%vorbis.cbr(samplerate=44100, channels=2, bitrate=320), "fallback-[320].ogg", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=32, afterburner=false, aot="mpeg4_he_aac_v2", sbr_mode=true), "fallback-[32].mp4", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=48, afterburner=false, aot="mpeg4_he_aac_v2", sbr_mode=true), "fallback-[48].mp4", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=64, afterburner=false, aot="mpeg4_he_aac_v2", sbr_mode=true), "fallback-[64].mp4", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=96, afterburner=false, aot="mpeg4_aac_lc", sbr_mode=true), "fallback-[96].mp4", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=128, afterburner=false, aot="mpeg4_aac_lc", sbr_mode=true), "fallback-[128].mp4", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=192, afterburner=true, aot="mpeg4_aac_lc", sbr_mode=true), "fallback-[192].mp4", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=256, afterburner=true, aot="mpeg4_aac_lc", sbr_mode=true), "fallback-[256].mp4", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=320, afterburner=true, aot="mpeg4_aac_lc", sbr_mode=true), "fallback-[320].mp4", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=32, afterburner=false, aot="mpeg4_he_aac_v2", sbr_mode=true), "fallback-[32].aac", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=48, afterburner=false, aot="mpeg4_he_aac_v2", sbr_mode=true), "fallback-[48].aac", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=64, afterburner=false, aot="mpeg4_he_aac_v2", sbr_mode=true), "fallback-[64].aac", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=96, afterburner=false, aot="mpeg4_aac_lc", sbr_mode=true), "fallback-[96].aac", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=128, afterburner=false, aot="mpeg4_aac_lc", sbr_mode=true), "fallback-[128].aac", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=192, afterburner=true, aot="mpeg4_aac_lc", sbr_mode=true), "fallback-[192].aac", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=256, afterburner=true, aot="mpeg4_aac_lc", sbr_mode=true), "fallback-[256].aac", input, fallible=true)
|
||||
output.file(%fdkaac(channels=2, samplerate=44100, bitrate=320, afterburner=true, aot="mpeg4_aac_lc", sbr_mode=true), "fallback-[320].aac", input, fallible=true)
|
||||
output.file(%opus(samplerate=48000, bitrate=32, vbr="constrained", application="audio", channels=2, signal="music", complexity=10, max_bandwidth="full_band"), "fallback-[32].opus", input, fallible=true)
|
||||
output.file(%opus(samplerate=48000, bitrate=48, vbr="constrained", application="audio", channels=2, signal="music", complexity=10, max_bandwidth="full_band"), "fallback-[48].opus", input, fallible=true)
|
||||
output.file(%opus(samplerate=48000, bitrate=64, vbr="constrained", application="audio", channels=2, signal="music", complexity=10, max_bandwidth="full_band"), "fallback-[64].opus", input, fallible=true)
|
Loading…
Reference in New Issue