Skip to content

Commit

Permalink
Server: Make the config better and more extensible.
Browse files Browse the repository at this point in the history
  • Loading branch information
e3ndr committed Oct 2, 2023
1 parent 39ac36d commit 5966046
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 110 deletions.
14 changes: 10 additions & 4 deletions server/src/main/java/xyz/e3ndr/athena/Athena.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@ public class Athena {
public static final int STREAMING_BUFFER_SIZE = 64/*kb*/ * 1000;
public static final int TRANSCODING_BUFFER_SIZE = 512/*kb*/ * 1000;

public static File mediaDirectory;
public static File cacheDirectory;
public static File ingestDirectory;
public static final File mediaDirectory = new File("./Media");
public static final File cacheDirectory = new File("./Cache");
public static final File ingestDirectory = new File("./Ingest");

static {
Athena.mediaDirectory.mkdirs();
Athena.cacheDirectory.mkdirs();
Athena.ingestDirectory.mkdirs();
}

public static boolean enableCudaAcceleration;
public static Config config = new Config();

public static List<MediaSession> mediaSessions = Collections.synchronizedList(new LinkedList<>());
public static List<TranscodeSession> transcodeSessions = Collections.synchronizedList(new LinkedList<>());
Expand Down
73 changes: 53 additions & 20 deletions server/src/main/java/xyz/e3ndr/athena/Config.java
Original file line number Diff line number Diff line change
@@ -1,39 +1,72 @@
package xyz.e3ndr.athena;

import java.io.File;

import co.casterlabs.rakurai.json.annotating.JsonClass;
import lombok.Getter;
import co.casterlabs.rakurai.json.annotating.JsonField;
import lombok.ToString;

@Getter
@ToString
@JsonClass(exposeAll = true)
public class Config {
private boolean debug = false;
private boolean disableColoredConsole = false;
public ConsoleConfig console = new ConsoleConfig();
public ServiceConfig services = new ServiceConfig();
public SessionConfig sessions = new SessionConfig();
public TranscodeConfig transcoding = new TranscodeConfig();

@ToString
@JsonClass(exposeAll = true)
public static class ConsoleConfig {
public boolean debug = false;
public @JsonField("disable_color") boolean disableColor = false;
}

private String mediaDirectory = "./Media";
private String cacheDirectory = "./Cache";
private String ingestDirectory = "./Ingest";
@ToString
@JsonClass(exposeAll = true)
public static class ServiceConfig {
public HttpServiceConfig http = new HttpServiceConfig();
public FtpServiceConfig ftp = new FtpServiceConfig();
public @JsonField("simple_ui") SimpleUIConfig simpleUI = new SimpleUIConfig();
public @JsonField("wii_mc") WiiMCServiceConfig wiimc = new WiiMCServiceConfig();

private boolean enableCudaAcceleration;
@ToString
@JsonClass(exposeAll = true)
public static class HttpServiceConfig {
public boolean enable = true;
public int port = 8125;
}

// -1 to disable.
private int webUiPort = 8127;
private int httpPort = 8125;
private int ftpPort = 8126;
@ToString
@JsonClass(exposeAll = true)
public static class FtpServiceConfig {
public boolean enable = true;
public int port = 8126;
}

@ToString
@JsonClass(exposeAll = true)
public static class SimpleUIConfig {
public boolean enable = true;
public int port = 8127;
}

public File getMediaDirectory() {
return new File(this.mediaDirectory);
}

public File getCacheDirectory() {
return new File(this.cacheDirectory);
@ToString
@JsonClass(exposeAll = true)
public static class SessionConfig {
}

public File getIngestDirectory() {
return new File(this.ingestDirectory);
@ToString
@JsonClass(exposeAll = true)
public static class TranscodeConfig {
public TranscodeAcceleration acceleration = TranscodeAcceleration.SOFTWARE_ONLY;

public static enum TranscodeAcceleration {
SOFTWARE_ONLY,
NVIDIA_PREFERRED,
// TODO AMD & Intel encoders.
// TODO Implement hardware decoding to speed up the transcode pipeline.
// https://trac.ffmpeg.org/wiki/HWAccelIntro
}
}

}
69 changes: 20 additions & 49 deletions server/src/main/java/xyz/e3ndr/athena/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import co.casterlabs.rakurai.json.Rson;
import co.casterlabs.rakurai.json.serialization.JsonParseException;
import co.casterlabs.sora.SoraFramework;
import lombok.Getter;
import xyz.e3ndr.athena.server.ftp.AthenaFtpServer;
import xyz.e3ndr.athena.server.http.AthenaHttpServer;
import xyz.e3ndr.athena.webui.AthenaUIServer;
Expand All @@ -20,8 +19,6 @@ public class Launcher {

private static final FastLogger logger = new FastLogger();

private static @Getter Config config;

public static void main(String[] args) throws Exception {
ClassLoader.getPlatformClassLoader().setDefaultAssertionStatus(true);

Expand All @@ -31,62 +28,36 @@ public static void main(String[] args) throws Exception {
// Load the config.
if (configFile.exists()) {
try {
config = Rson.DEFAULT.fromJson(Files.readString(configFile.toPath()), Config.class);

// disableColoredConsole
FastLoggingFramework.setColorEnabled(!config.isDisableColoredConsole());

// debug
FastLoggingFramework.setDefaultLevel(config.isDebug() ? LogLevel.DEBUG : LogLevel.INFO);

// enableCudaAcceleration
Athena.enableCudaAcceleration = config.isEnableCudaAcceleration();

// mediaDirectory
Athena.mediaDirectory = config.getMediaDirectory();
if (!Athena.mediaDirectory.exists()) {
logger.info("Media directory doesn't exist, creating it now.");
Athena.mediaDirectory.mkdirs();
} else if (!Athena.mediaDirectory.isDirectory()) {
logger.fatal("Media directory is not actually a directory, crashing.");
System.exit(-1);
}

// cacheDirectory
Athena.cacheDirectory = config.getCacheDirectory();
if (!Athena.cacheDirectory.exists()) {
logger.info("Cache directory doesn't exist, creating it now.");
Athena.cacheDirectory.mkdirs();
} else if (!Athena.cacheDirectory.isDirectory()) {
logger.fatal("Cache directory is not actually a directory, crashing.");
System.exit(-1);
}

// ingestDirectory
Athena.ingestDirectory = config.getIngestDirectory();
if (!Athena.ingestDirectory.exists()) {
logger.info("Ingest directory doesn't exist, creating it now.");
Athena.ingestDirectory.mkdirs();
} else if (!Athena.ingestDirectory.isDirectory()) {
logger.fatal("Ingest directory is not actually a directory, crashing.");
System.exit(-1);
}
Athena.config = Rson.DEFAULT.fromJson(Files.readString(configFile.toPath()), Config.class);

logger.debug("Using config: %s", config);
logger.debug("Using config: %s", Athena.config);
} catch (JsonParseException e) {
logger.severe("Unable to parse config file, is it malformed?\n%s", e);
}
} else {
config = new Config();
logger.info("Config file doesn't exist, creating a new file.");
}

Files.writeString(configFile.toPath(), Rson.DEFAULT.toJson(config).toString(true));
Files.writeString(configFile.toPath(), Rson.DEFAULT.toJson(Athena.config).toString(true));

// disableColoredConsole
FastLoggingFramework.setColorEnabled(!Athena.config.console.disableColor);

// debug
FastLoggingFramework.setDefaultLevel(Athena.config.console.debug ? LogLevel.DEBUG : LogLevel.INFO);

// Go!
AsyncTask.createNonDaemon(() -> new AthenaHttpServer().start(config));
AsyncTask.createNonDaemon(() -> new AthenaFtpServer().start(config));
AsyncTask.createNonDaemon(() -> new AthenaUIServer().start(config));
if (Athena.config.services.http.enable) {
AsyncTask.createNonDaemon(() -> new AthenaHttpServer().start());
}

if (Athena.config.services.http.enable) {
AsyncTask.createNonDaemon(() -> new AthenaFtpServer().start());
}

if (Athena.config.services.simpleUI.enable) {
AsyncTask.createNonDaemon(() -> new AthenaUIServer().start());
}
}

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package xyz.e3ndr.athena.server;

import xyz.e3ndr.athena.Config;

public interface AthenaServer {

public void start(Config config);
public void start();

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import java.util.LinkedList;
import java.util.List;

import xyz.e3ndr.athena.Config;
import xyz.e3ndr.athena.Athena;
import xyz.e3ndr.athena.server.AthenaServer;
import xyz.e3ndr.fastloggingframework.logging.FastLogger;
import xyz.e3ndr.fastloggingframework.logging.LogLevel;
Expand All @@ -24,9 +24,8 @@ public class AthenaFtpServer implements AthenaServer {

@SuppressWarnings("resource")
@Override
public void start(Config config) {
int controlPort = config.getFtpPort();
if (controlPort == -1) return;
public void start() {
int controlPort = Athena.config.services.ftp.port;

// Generate a list of ports.
for (int idx = 0; idx < +MAX_CLIENTS; idx++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@
import co.casterlabs.sora.SoraLauncher;
import co.casterlabs.sora.api.SoraPlugin;
import lombok.NonNull;
import xyz.e3ndr.athena.Config;
import xyz.e3ndr.athena.Athena;
import xyz.e3ndr.athena.server.AthenaServer;
import xyz.e3ndr.fastloggingframework.logging.FastLogger;
import xyz.e3ndr.fastloggingframework.logging.LogLevel;

public class AthenaHttpServer implements AthenaServer {

@Override
public void start(Config config) {
public void start() {
try {
int port = config.getHttpPort();

if (port == -1) return;
int port = Athena.config.services.http.port;

SoraFramework framework = new SoraLauncher()
.setPort(port)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import co.casterlabs.sora.api.http.HttpProvider;
import co.casterlabs.sora.api.http.SoraHttpSession;
import co.casterlabs.sora.api.http.annotations.HttpEndpoint;
import xyz.e3ndr.athena.Launcher;
import xyz.e3ndr.athena.Athena;

class MetaRoutes implements HttpProvider {

Expand All @@ -18,9 +18,7 @@ public HttpResponse onWellKnown(SoraHttpSession session) {

@HttpEndpoint(uri = "/*")
public HttpResponse onGetIndex(SoraHttpSession session) {
int webUiPort = Launcher.getConfig().getWebUiPort();

if (webUiPort == -1) {
if (Athena.config.services.simpleUI.enable) {
return HttpResponse
.newFixedLengthResponse(
StandardHttpStatus.OK,
Expand All @@ -31,7 +29,7 @@ public HttpResponse onGetIndex(SoraHttpSession session) {
return HttpResponse
.newFixedLengthResponse(
StandardHttpStatus.OK,
"There's nothing here..... Are you looking for the UI? If so, that's on port " + webUiPort + "."
"There's nothing here..... Are you looking for the UI? If so, that's on port " + Athena.config.services.simpleUI.port + "."
)
.setMimeType("text/plain");
}
Expand Down
36 changes: 22 additions & 14 deletions server/src/main/java/xyz/e3ndr/athena/transcoding/FFMpegArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.LinkedList;
import java.util.List;

import xyz.e3ndr.athena.Config.TranscodeConfig.TranscodeAcceleration;
import xyz.e3ndr.athena.types.AudioCodec;
import xyz.e3ndr.athena.types.VideoCodec;
import xyz.e3ndr.athena.types.VideoQuality;
Expand All @@ -27,7 +28,7 @@ public static List<String> a_getFF(AudioCodec codec) {
return null;
}

public static List<String> v_getFF(VideoCodec codec, VideoQuality quality, boolean enableCuda) {
public static List<String> v_getFF(VideoCodec codec, VideoQuality quality, TranscodeAcceleration acceleration) {
// TODO the more advanced parameters for HEVC and AV1

switch (codec) {
Expand All @@ -36,13 +37,15 @@ public static List<String> v_getFF(VideoCodec codec, VideoQuality quality, boole

case H264_BASELINE:
case H264_HIGH:
return getH264Args(codec, quality, enableCuda);
return getH264Args(codec, quality, acceleration);

case HEVC:
if (enableCuda) {
return Arrays.asList("-c:v", "hevc_nvenc");
} else {
return Arrays.asList("-c:v", "hevc");
switch (acceleration) {
case NVIDIA_PREFERRED:
return Arrays.asList("-c:v", "hevc_nvenc");

case SOFTWARE_ONLY:
return Arrays.asList("-c:v", "hevc");
}

case AV1:
Expand All @@ -54,15 +57,19 @@ public static List<String> v_getFF(VideoCodec codec, VideoQuality quality, boole
return null;
}

private static List<String> getH264Args(VideoCodec codec, VideoQuality quality, boolean enableCuda) {
private static List<String> getH264Args(VideoCodec codec, VideoQuality quality, TranscodeAcceleration acceleration) {
List<String> args = new LinkedList<>();

if (enableCuda) {
args.add("-c:v");
args.add("h264_nvenc");
} else {
args.add("-c:v");
args.add("h264");
switch (acceleration) {
case NVIDIA_PREFERRED:
args.add("-c:v");
args.add("h264_nvenc");
break;

case SOFTWARE_ONLY:
args.add("-c:v");
args.add("h264");
break;
}

switch (codec) {
Expand All @@ -78,7 +85,8 @@ private static List<String> getH264Args(VideoCodec codec, VideoQuality quality,
args.add("high");
args.add("-level");
args.add("5.0");
if (!enableCuda) {
if (acceleration != TranscodeAcceleration.NVIDIA_PREFERRED) {
// NVIDIA does not support tune.
args.add("-tune");
args.add("film");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public static TranscodeSession start(File targetFile, Media media, VideoQuality
}

/* ---- Video ---- */
command.addAll(FFMpegArgs.v_getFF(desiredVCodec, desiredQuality, Athena.enableCudaAcceleration));
command.addAll(FFMpegArgs.v_getFF(desiredVCodec, desiredQuality, Athena.config.transcoding.acceleration));

if (desiredVCodec != VideoCodec.SOURCE) {
command.add("-b:v");
Expand Down
Loading

0 comments on commit 5966046

Please sign in to comment.