Skip to content

Commit

Permalink
added aac audio
Browse files Browse the repository at this point in the history
  • Loading branch information
mariotaku committed Apr 4, 2024
1 parent 1b29c0d commit 7fc02ca
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 13 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ if (NOT INIH_FOUND)
list(POP_BACK CMAKE_MESSAGE_INDENT)
endif ()

include(ExternalFdkAAC)

if (TARGET_WEBOS)
pkg_check_modules(PBNJSON_C REQUIRED pbnjson_c)
pkg_check_modules(PMLOG REQUIRED PmLogLib)
Expand Down Expand Up @@ -240,6 +242,9 @@ target_link_libraries(moonlight-lib PUBLIC lv_gridview lv_sdl_img)
target_include_directories(moonlight-lib SYSTEM PUBLIC ${OPUS_INCLUDE_DIRS})
target_link_libraries(moonlight-lib PUBLIC ${OPUS_LIBRARIES})

target_include_directories(moonlight-lib SYSTEM PUBLIC ${FDKAAC_INCLUDE_DIRS})
target_link_libraries(moonlight-lib PUBLIC ${FDKAAC_LIBRARIES} ss4s-ringbuf)

target_include_directories(moonlight-lib SYSTEM PUBLIC ${MBEDTLS_INCLUDE_DIRS})
target_link_libraries(moonlight-lib PUBLIC ${MBEDCRYPTO_LIBRARY} ${MBEDX509_LIBRARY})

Expand Down
36 changes: 36 additions & 0 deletions cmake/ExternalFdkAAC.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
include(ExternalProject)

set(EXT_FDKAAC_TOOLCHAIN_ARGS)
if (CMAKE_TOOLCHAIN_FILE)
list(APPEND EXT_FDKAAC_TOOLCHAIN_ARGS "-DCMAKE_TOOLCHAIN_FILE:string=${CMAKE_TOOLCHAIN_FILE}")
endif ()
if (CMAKE_TOOLCHAIN_ARGS)
list(APPEND EXT_FDKAAC_TOOLCHAIN_ARGS "-DCMAKE_TOOLCHAIN_ARGS:string=${CMAKE_TOOLCHAIN_ARGS}")
endif ()

set(LIB_FILENAME "${CMAKE_SHARED_LIBRARY_PREFIX}fdk-aac${CMAKE_SHARED_LIBRARY_SUFFIX}")

ExternalProject_Add(ext_fdkaac
URL https://github.com/mstorsjo/fdk-aac/archive/refs/tags/v2.0.3.tar.gz
URL_HASH SHA256=e25671cd96b10bad896aa42ab91a695a9e573395262baed4e4a2ff178d6a3a78
CMAKE_ARGS ${EXT_OPUS_TOOLCHAIN_ARGS}
-DCMAKE_BUILD_TYPE:string=${CMAKE_BUILD_TYPE}
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
BUILD_BYPRODUCTS <INSTALL_DIR>/lib/${LIB_FILENAME}
)
ExternalProject_Get_Property(ext_fdkaac INSTALL_DIR)

add_library(ext_fdkaac_target SHARED IMPORTED)
set_target_properties(ext_fdkaac_target PROPERTIES IMPORTED_LOCATION ${INSTALL_DIR}/lib/${LIB_FILENAME})

add_dependencies(ext_fdkaac_target ext_fdkaac)

set(FDKAAC_INCLUDE_DIRS ${INSTALL_DIR}/include)
set(FDKAAC_LIBRARIES ext_fdkaac_target)
set(FDKAAC_FOUND TRUE)

if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR lib)
endif ()

install(DIRECTORY ${INSTALL_DIR}/lib/ DESTINATION ${CMAKE_INSTALL_LIBDIR})
129 changes: 117 additions & 12 deletions src/app/stream/audio/session_audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,88 @@
#include "stream/connection/session_connection.h"
#include "ss4s.h"
#include "stream/session_priv.h"
#include <fdk-aac/FDK_audio.h>
#include <fdk-aac/aacenc_lib.h>
#include <assert.h>
#include "ringbuf.h"
#include "logging.h"

#define SAMPLES_PER_FRAME 240

static session_t *session = NULL;
static SS4S_Player *player = NULL;
static OpusMSDecoder *decoder = NULL;
static unsigned char *pcmbuf = NULL;
static int frame_size = 0, unit_size = 0;
static HANDLE_AACENCODER aac_encoder = NULL;
static sdlaud_ringbuf *a52_ringbuf = NULL;
static unsigned char *buffer = NULL;
static unsigned char *buffer2 = NULL;
static int frame_size = 0, unit_size = 0, channel_count = 0;

struct __attribute__((packed)) OpusHeader {
__attribute__((unused)) char magic[8];
__attribute__((unused)) uint8_t version;
__attribute__((unused)) uint8_t channelCount;
__attribute__((unused)) uint16_t preSkip;
__attribute__((unused)) uint32_t inputSampleRate;
__attribute__((unused)) int16_t outputGain;
__attribute__((unused)) uint8_t mappingFamily;
__attribute__((unused)) struct {
uint8_t streamCount;
uint8_t coupledCount;
uint8_t mapping[255];
} mappingTable;
};

static size_t serialize_opus_header(const OPUS_MULTISTREAM_CONFIGURATION *opusConfig, unsigned char *out);

static int aud_init(int audioConfiguration, const POPUS_MULTISTREAM_CONFIGURATION opusConfig, void *context,
int arFlags) {
(void) audioConfiguration;
(void) arFlags;
session = context;
player = session->player;
SS4S_AudioCodec codec = SS4S_AUDIO_PCM_S16LE;
SS4S_AudioCodec codec;
size_t codecDataLen = 0;
int samplesPerFrame = SAMPLES_PER_FRAME;
if (session->audio_cap.codecs & SS4S_AUDIO_OPUS) {
codec = SS4S_AUDIO_OPUS;
decoder = NULL;
pcmbuf = NULL;
aac_encoder = NULL;
a52_ringbuf = NULL;
buffer = malloc(sizeof(struct OpusHeader));
codecDataLen = serialize_opus_header(opusConfig, buffer);
} else {
codec = SS4S_AUDIO_AAC;
int rc;
decoder = opus_multistream_decoder_create(opusConfig->sampleRate, opusConfig->channelCount, opusConfig->streams,
opusConfig->coupledStreams, opusConfig->mapping, &rc);
if (rc != 0) {
return rc;
}
aacEncOpen(&aac_encoder, 0, opusConfig->channelCount);
aacEncoder_SetParam(aac_encoder, AACENC_AOT, AOT_AAC_LC);
aacEncoder_SetParam(aac_encoder, AACENC_BITRATE, 320000);
aacEncoder_SetParam(aac_encoder, AACENC_SAMPLERATE, opusConfig->sampleRate);
aacEncoder_SetParam(aac_encoder, AACENC_CHANNELMODE, opusConfig->channelCount == 6 ? MODE_1_2_2_1 : MODE_2);
aacEncoder_SetParam(aac_encoder, AACENC_TRANSMUX, TT_MP4_ADTS);

channel_count = opusConfig->channelCount;
frame_size = SAMPLES_PER_FRAME * 64;
unit_size = (int) (opusConfig->channelCount * sizeof(int16_t));
pcmbuf = calloc(unit_size, frame_size);
buffer = calloc(unit_size, frame_size);
buffer2 = calloc(unit_size, frame_size);
a52_ringbuf = sdlaud_ringbuf_new(unit_size * 1024 * 2);
samplesPerFrame = 1024;
}
SS4S_AudioInfo info = {
.numOfChannels = opusConfig->channelCount,
.codec = codec,
.appName = "Moonlight",
.streamName = "Streaming",
.sampleRate = opusConfig->sampleRate,
.samplesPerFrame = SAMPLES_PER_FRAME,
.samplesPerFrame = samplesPerFrame,
.codecData = buffer,
.codecDataLen = codecDataLen,
};
return SS4S_PlayerAudioOpen(player, &info);
}
Expand All @@ -54,23 +98,84 @@ static void aud_cleanup() {
opus_multistream_decoder_destroy(decoder);
decoder = NULL;
}
if (pcmbuf != NULL) {
free(pcmbuf);
pcmbuf = NULL;
if (buffer != NULL) {
free(buffer);
buffer = NULL;
}
if (buffer2 != NULL) {
free(buffer2);
buffer2 = NULL;
}
if (aac_encoder != NULL) {
aacEncClose(&aac_encoder);
aac_encoder = NULL;
}
if (a52_ringbuf != NULL) {
sdlaud_ringbuf_delete(a52_ringbuf);
a52_ringbuf = NULL;
}
session = NULL;
}

static void aud_feed(char *sampleData, int sampleLength) {
if (decoder != NULL) {
int decode_len = opus_multistream_decode(decoder, (unsigned char *) sampleData, sampleLength,
(opus_int16 *) pcmbuf, frame_size, 0);
SS4S_PlayerAudioFeed(player, pcmbuf, unit_size * decode_len);
int decoded_samples = opus_multistream_decode(decoder, (unsigned char *) sampleData, sampleLength,
(opus_int16 *) buffer, frame_size, 0);
// Encode the decoded audio to AAC
INT inBufId = IN_AUDIO_DATA, outBufId = OUT_BITSTREAM_DATA;
INT inBufSize = unit_size * decoded_samples, outBufSize = unit_size * frame_size;
INT outBufElSize = 1;
AACENC_BufDesc in_buf = {0}, out_buf = {0};
AACENC_InArgs in_args = {0};
AACENC_OutArgs out_args = {0};

in_buf.numBufs = 1;
in_buf.bufs = (void **) &buffer;
in_buf.bufferIdentifiers = &inBufId;
in_buf.bufSizes = &inBufSize;
in_buf.bufElSizes = &unit_size;

out_buf.numBufs = 1;
out_buf.bufs = (void **) &buffer2;
out_buf.bufferIdentifiers = &outBufId;
out_buf.bufSizes = &outBufSize;
out_buf.bufElSizes = &outBufElSize;

in_args.numInSamples = decoded_samples * channel_count;

AACENC_ERROR encError = aacEncEncode(aac_encoder, &in_buf, &out_buf, &in_args, &out_args);
if (encError != AACENC_OK) {
commons_log_error("Audio", "Failed to encode audio: %d", encError);
return;
}
if (out_args.numOutBytes > 0) {
SS4S_PlayerAudioFeed(player, buffer2, out_args.numOutBytes);
}
} else {
SS4S_PlayerAudioFeed(player, (unsigned char *) sampleData, sampleLength);
}
}

size_t serialize_opus_header(const OPUS_MULTISTREAM_CONFIGURATION *opusConfig, unsigned char *out) {
struct OpusHeader *header = (struct OpusHeader *) out;
memset(header, 0, sizeof(struct OpusHeader));
memcpy(header->magic, "OpusHead", 8);
header->version = 1;
header->channelCount = opusConfig->channelCount;
header->preSkip = SDL_SwapLE16(0);
header->inputSampleRate = SDL_SwapLE32(opusConfig->sampleRate);
header->outputGain = SDL_SwapLE16(0);
if (opusConfig->streams > 2) {
header->mappingFamily = 1;
}
header->mappingTable.streamCount = opusConfig->streams;
header->mappingTable.coupledCount = opusConfig->coupledStreams;
for (int i = 0; i < opusConfig->streams; i++) {
header->mappingTable.mapping[i] = opusConfig->mapping[i];
}
return 21 + opusConfig->streams;
}

AUDIO_RENDERER_CALLBACKS ss4s_aud_callbacks = {
.init = aud_init,
.cleanup = aud_cleanup,
Expand Down

0 comments on commit 7fc02ca

Please sign in to comment.