Skip to content

Commit 5d1b06d

Browse files
committed
Allowing programmatic registration of new decoders (#343)
1 parent b9afd9c commit 5d1b06d

2 files changed

Lines changed: 80 additions & 17 deletions

File tree

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2021 devgianlu
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package xyz.gianlu.librespot.player.codecs;
18+
19+
import org.jetbrains.annotations.NotNull;
20+
import org.jetbrains.annotations.Nullable;
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
23+
import xyz.gianlu.librespot.audio.GeneralAudioStream;
24+
import xyz.gianlu.librespot.audio.NormalizationData;
25+
import xyz.gianlu.librespot.audio.format.SuperAudioFormat;
26+
import xyz.gianlu.librespot.player.PlayerConfiguration;
27+
28+
import java.util.*;
29+
30+
/**
31+
* @author devgianlu
32+
*/
33+
public final class Codecs {
34+
private static final Map<SuperAudioFormat, HashSet<Class<? extends Codec>>> codecs = new EnumMap<>(SuperAudioFormat.class);
35+
private static final Logger LOGGER = LoggerFactory.getLogger(Codecs.class);
36+
37+
static {
38+
registerCodec(SuperAudioFormat.VORBIS, VorbisCodec.class);
39+
registerCodec(SuperAudioFormat.MP3, Mp3Codec.class);
40+
}
41+
42+
private Codecs() {
43+
}
44+
45+
@Nullable
46+
public static Codec initCodec(@NotNull SuperAudioFormat format, @NotNull GeneralAudioStream audioFile, @Nullable NormalizationData normalizationData, @NotNull PlayerConfiguration conf, int duration) {
47+
Set<Class<? extends Codec>> set = codecs.get(format);
48+
if (set == null) return null;
49+
50+
Optional<Class<? extends Codec>> opt = set.stream().findFirst();
51+
if (!opt.isPresent()) return null;
52+
53+
try {
54+
Class<? extends Codec> clazz = opt.get();
55+
return clazz.getConstructor(GeneralAudioStream.class, NormalizationData.class, PlayerConfiguration.class, int.class).newInstance(audioFile, normalizationData, conf, duration);
56+
} catch (ReflectiveOperationException ex) {
57+
LOGGER.error("Failed initializing Codec instance for {}", format, ex);
58+
return null;
59+
}
60+
}
61+
62+
public static void registerCodec(@NotNull SuperAudioFormat format, @NotNull Class<? extends Codec> clazz) {
63+
codecs.computeIfAbsent(format, (key) -> new HashSet<>(5)).add(clazz);
64+
}
65+
66+
public static void replaceCodecs(@NotNull SuperAudioFormat format, @NotNull Class<? extends Codec> clazz) {
67+
Set<Class<? extends Codec>> set = codecs.get(format);
68+
if (set != null) set.clear();
69+
registerCodec(format, clazz);
70+
}
71+
72+
public static void unregisterCodec(@NotNull Class<? extends Codec> clazz) {
73+
for (Set<Class<? extends Codec>> set : codecs.values())
74+
set.remove(clazz);
75+
}
76+
}

player/src/main/java/xyz/gianlu/librespot/player/playback/PlayerQueueEntry.java

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package xyz.gianlu.librespot.player.playback;
1818

19-
import javazoom.jl.decoder.BitstreamException;
2019
import org.jetbrains.annotations.NotNull;
2120
import org.jetbrains.annotations.Nullable;
2221
import org.slf4j.Logger;
@@ -33,8 +32,7 @@
3332
import xyz.gianlu.librespot.player.PlayerConfiguration;
3433
import xyz.gianlu.librespot.player.StateWrapper;
3534
import xyz.gianlu.librespot.player.codecs.Codec;
36-
import xyz.gianlu.librespot.player.codecs.Mp3Codec;
37-
import xyz.gianlu.librespot.player.codecs.VorbisCodec;
35+
import xyz.gianlu.librespot.player.codecs.Codecs;
3836
import xyz.gianlu.librespot.player.codecs.VorbisOnlyAudioQuality;
3937
import xyz.gianlu.librespot.player.crossfade.CrossfadeController;
4038
import xyz.gianlu.librespot.player.metrics.PlaybackMetrics;
@@ -132,20 +130,9 @@ private void load(boolean preload) throws IOException, Codec.CodecException, Mer
132130
if (crossfade.hasAnyFadeOut() || conf.preloadEnabled)
133131
notifyInstant(INSTANT_PRELOAD, (int) (crossfade.fadeOutStartTimeMin() - TimeUnit.SECONDS.toMillis(20)));
134132

135-
switch (stream.in.codec()) {
136-
case VORBIS:
137-
codec = new VorbisCodec(stream.in, stream.normalizationData, conf, metadata.duration());
138-
break;
139-
case MP3:
140-
try {
141-
codec = new Mp3Codec(stream.in, stream.normalizationData, conf, metadata.duration());
142-
} catch (BitstreamException ex) {
143-
throw new IOException(ex);
144-
}
145-
break;
146-
default:
147-
throw new UnsupportedEncodingException(stream.in.codec().toString());
148-
}
133+
codec = Codecs.initCodec(stream.in.codec(), stream.in, stream.normalizationData, conf, metadata.duration());
134+
if (codec == null)
135+
throw new UnsupportedEncodingException(stream.in.codec().toString());
149136

150137
LOGGER.trace("Loaded {} codec. {of: {}, format: {}, playbackId: {}}", stream.in.codec(), stream.in.describe(), codec.getAudioFormat(), playbackId);
151138
}

0 commit comments

Comments
 (0)