Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ff8b75d
Update koe
davidffa Jun 2, 2022
2d2392b
Implement voice receive (op: 'record')
davidffa Jun 2, 2022
ee090e1
Add LavalinkNatives module & refactor build script
davidffa Jun 6, 2022
e63bfb9
Use native library (libmp3lame) to encode the pcm frames
davidffa Jun 8, 2022
971f144
Add compiled natives for libmp3lame
davidffa Jun 8, 2022
500e4a7
Update koe
davidffa Jun 8, 2022
515d9ff
Ignore audio packets older than 100ms
davidffa Jun 8, 2022
9274d7e
Fix high heap allocations
davidffa Jun 15, 2022
a74ae1b
Add records/ to gitignore
davidffa Jun 15, 2022
8d7869e
Update koe
davidffa Jun 15, 2022
d9f8bfc
Fix NPE
davidffa Jun 15, 2022
e38ab71
Handle AudioReceiver cleanup
davidffa Jun 18, 2022
b863122
Allow sending record payload before voiceUpdate
davidffa Jun 18, 2022
9df9bb0
Use id instead of channelid
davidffa Jun 18, 2022
fa9bb95
Start AudioReceiver if already connected
davidffa Jun 18, 2022
0d1a2de
Implement REST endpoints for audio receive system
davidffa Jun 19, 2022
2de4559
Fix response type
davidffa Jun 19, 2022
145ec30
Update koe & add Epoll support for linux aarch64
davidffa Jun 22, 2022
c8ca4e4
Use NAS configurable
davidffa Jun 22, 2022
82ae874
Add option to rec self audio & optimizations
davidffa Jun 22, 2022
ef54adf
Merge branch 'dev' into feat/voice-receive
davidffa Jun 22, 2022
6905f59
Fix race condition
davidffa Jun 23, 2022
f848c8f
Only require id when start recording
davidffa Jun 25, 2022
56567e2
Update koe
davidffa Jun 25, 2022
52fec9e
Rewind the mp3 silence buf after write
davidffa Jun 25, 2022
e0cb838
Fix concurrency bug
davidffa Jun 25, 2022
147d496
Update koe
davidffa Jun 25, 2022
e74c202
Emit event when finishing recording
davidffa Jun 25, 2022
e1b5203
Update koe
davidffa Jun 25, 2022
a25d063
Update koe
davidffa Jun 25, 2022
a60cc83
Allow to select certain users to record
davidffa Jun 26, 2022
ceea2ea
Support encoding mono audio on Mp3Encoder
davidffa Jul 1, 2022
7a55c93
Initialize right channel array
davidffa Jul 1, 2022
b6059ff
Rebuilt natives
davidffa Jul 1, 2022
d3c13bf
Support mono audio & pcm output
davidffa Jul 1, 2022
e0d5096
Send speaking events
davidffa Jul 3, 2022
c14ab3f
Refactor NAS disabled log
davidffa Jul 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ logs/
# Build
target/
build/
dist/
out/
bin/

Expand All @@ -29,3 +30,7 @@ application.yml
.settings

VERSION.txt

LavalinkNatives/lame/lame*
records/
.DS_Store
55 changes: 55 additions & 0 deletions LavalinkNatives/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 3.0)
project(mp3encoder C)

add_subdirectory(lame)

if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
include_directories("$ENV{JAVA_HOME}/include/win32")
set(SYSNAME "win")
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
include_directories("$ENV{JAVA_HOME}/include/linux")
set(SYSNAME "linux")
else()
include_directories("$ENV{JAVA_HOME}/include/darwin")
set(SYSNAME "darwin")
endif()

if ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
add_definitions(-Dinline=__inline)

set(COMPILER_FLAGS "")
set(COMPILER_FLAGS_DEBUG "/MTd")
set(COMPILER_FLAGS_RELEASE "/Ox /MT")
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
set(COMPILER_FLAGS "-fvisibility=hidden")
set(COMPILER_FLAGS_DEBUG "-g")
set(COMPILER_FLAGS_RELEASE "-O3 -DNDEBUG")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-dead_strip")
else()
set(COMPILER_FLAGS "-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function -fvisibility=hidden")
set(COMPILER_FLAGS_DEBUG "-g")
set(COMPILER_FLAGS_RELEASE "-O3 -DNDEBUG")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections -Wl,--exclude-libs,ALL -Wl,--strip-all")
endif()

set(CMAKE_C_FLAGS_DEBUG "${COMPILER_FLAGS} ${COMPILER_FLAGS_DEBUG}")
set(CMAKE_C_FLAGS_RELEASE "${COMPILER_FLAGS} ${COMPILER_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_DEBUG "${COMPILER_FLAGS} ${COMPILER_FLAGS_DEBUG}")
set(CMAKE_CXX_FLAGS_RELEASE "${COMPILER_FLAGS} ${COMPILER_FLAGS_RELEASE}")

include_directories("$ENV{JAVA_HOME}/include")
include_directories("./lame/lame-3.100/include")
#link_directories("./libs")

if (DEFINED ENV{DIST_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "$ENV{DIST_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "$ENV{DIST_DIR}")
endif()

add_library(mp3encoder SHARED Mp3Encoder.c)

if (WIN32)
target_link_libraries(mp3encoder lame)
else()
target_link_libraries(mp3encoder lame m)
endif()
68 changes: 68 additions & 0 deletions LavalinkNatives/Mp3Encoder.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <jni.h>
#include <lame.h>

#ifdef __GNUC__
#define EXPORT __attribute__ ((visibility("default"))) JNIEXPORT
#else
#define EXPORT JNIEXPORT
#endif

EXPORT jlong JNICALL Java_lavalink_server_natives_mp3_Mp3EncoderLibrary_create(JNIEnv *jni, jobject me, jint sample_rate, jint channels, jint bitrate) {
lame_t encoder = lame_init();

lame_set_in_samplerate(encoder, sample_rate);
lame_set_num_channels(encoder, channels);
lame_set_VBR(encoder, vbr_off);
lame_set_brate(encoder, bitrate / 1000);
lame_set_out_samplerate(encoder, sample_rate);
lame_init_params(encoder);

return (jlong) encoder;
}

EXPORT jint JNICALL Java_lavalink_server_natives_mp3_Mp3EncoderLibrary_encodeStereo(JNIEnv *jni, jobject me, jlong instance, jobject direct_input, jint frame_size, jobject direct_output, jint output_length) {
lame_t encoder = (lame_t) instance;

if (instance == 0) {
return 0;
}

short int* input = (*jni)->GetDirectBufferAddress(jni, direct_input);
unsigned char* output = (*jni)->GetDirectBufferAddress(jni, direct_output);

return lame_encode_buffer_interleaved(encoder, input, frame_size, output, output_length);
}

EXPORT jint JNICALL Java_lavalink_server_natives_mp3_Mp3EncoderLibrary_encodeMono(JNIEnv *jni, jobject me, jlong instance, jobject direct_input, jint frame_size, jobject direct_output, jint output_length) {
lame_t encoder = (lame_t) instance;

if (instance == 0) {
return 0;
}

short int* input = (*jni)->GetDirectBufferAddress(jni, direct_input);
short int* r = NULL;
unsigned char* output = (*jni)->GetDirectBufferAddress(jni, direct_output);

return lame_encode_buffer(encoder, input, r, frame_size, output, output_length);
}

EXPORT jint JNICALL Java_lavalink_server_natives_mp3_Mp3EncoderLibrary_flush(JNIEnv *jni, jobject me, jlong instance, jobject direct_output, jint output_length) {
lame_t encoder = (lame_t) instance;

if (instance == 0) {
return 0;
}

unsigned char* output = (*jni)->GetDirectBufferAddress(jni, direct_output);

return lame_encode_flush(encoder, output, output_length);
}

EXPORT void JNICALL Java_lavalink_server_natives_mp3_Mp3EncoderLibrary_destroy(JNIEnv *jni, jobject me, jlong instance) {
lame_t encoder = (lame_t) instance;

if (encoder != NULL) {
lame_close(encoder);
}
}
39 changes: 39 additions & 0 deletions LavalinkNatives/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
plugins {
id 'de.undercouch.download' version '5.1.0'
}

apply from: 'natives.gradle'

ext.lameVersion = '3.100'

task load { doLast {
if (!file("$projectDir/lame/lame-${lameVersion}").exists()) {
def downloadPath = "$buildDir/tmp/temp.tar.gz"
def unpackPath = "$projectDir/lame"

download.run {
src "https://sourceforge.net/projects/lame/files/lame/$lameVersion/lame-${lameVersion}.tar.gz/download"
dest downloadPath
}

copy {
from tarTree(file(downloadPath))
into unpackPath
}
}
}}

task compileNatives() { }
task checkNatives() { }

def buildTaskConfig = [
buildBase: buildDir,
projectBase: projectDir,
deployBase: project(':Lavalink-Server').projectDir,
setupDependency: tasks.load,
compileTask: tasks.compileNatives,
checkTask: tasks.checkNatives,
name: 'libmp3encoder'
]

createBuildTask(tasks, buildTaskConfig)
40 changes: 40 additions & 0 deletions LavalinkNatives/lame/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 3.0)
project(lame C)

set(LAME_VERSION 3.100)

get_filename_component(ROOT_DIR "." ABSOLUTE)
set(LIBMP3LAME_SOURCE "${ROOT_DIR}/lame-${LAME_VERSION}/libmp3lame")

add_definitions(-DHAVE_STDINT_H)
add_definitions(-DUSE_FAST_LOG)
add_definitions(-DTAKEHIRO_IEEE754_HACK)

if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
set(CMAKE_C_FLAGS_RELEASE "/MT")
add_definitions(-DUSE_LAYER_2)
add_definitions(-DHAVE_CONFIG_H)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_CRT_SECURE_NO_DEPRECATED)
configure_file("${ROOT_DIR}/lame-${LAME_VERSION}/configMS.h" "${ROOT_DIR}/lame-${LAME_VERSION}/config.h" COPYONLY)
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fdata-sections -ffunction-sections")
add_definitions(-DSTDC_HEADERS)

if(NOT ieee754_float32_t)
add_definitions(-Dieee754_float32_t=float)
endif()
endif()

file(GLOB MAIN_SOURCES "${LIBMP3LAME_SOURCE}/*.c")

include_directories(${ROOT_DIR}/lame-${LAME_VERSION}/include)
include_directories(${ROOT_DIR}/lame-${LAME_VERSION})
include_directories(${LIBMP3LAME_SOURCE})

if (WIN32)
include_directories(${LIBMP3LAME_SOURCE}/vector)
add_library(${PROJECT_NAME} STATIC ${MAIN_SOURCES} ${ROOT_DIR}/lame-${LAME_VERSION}/libmp3lame/vector/xmm_quantize_sub.c)
else()
add_library(${PROJECT_NAME} STATIC ${MAIN_SOURCES})
endif()
97 changes: 97 additions & 0 deletions LavalinkNatives/natives.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import org.apache.tools.ant.taskdefs.condition.Os

def getBuildParameters(base) {
def arch = System.getProperty("os.arch")
if (arch == 'amd64') arch = 'x86-64'

if (Os.isFamily(Os.FAMILY_WINDOWS)) {
return [
'identifier': "win-" + arch,
'library': "${base}.dll",
'setupArguments': ['-DCMAKE_BUILD_TYPE=Release', '-A', 'x64'],
'buildArguments': ['--config', 'Release'],
'env': [:]
]
} else if (Os.isFamily(Os.FAMILY_MAC)) {
return [
'identifier': 'darwin-' + arch,
'library': "lib${base}.dylib",
'setupArguments': ['-DCMAKE_BUILD_TYPE=Release'],
'buildArguments': [],
'env': [:]
]
} else {
return [
'identifier': "linux-" + arch,
'library': "lib${base}.so",
'setupArguments': ['-DCMAKE_BUILD_TYPE=Release'],
'buildArguments': [],
'env': [:]
]
}
}

def getHomeDirectory() {
def directory = file(System.getProperty('java.home'))
return directory.name == 'jre' ? directory.parentFile.absolutePath : directory.absolutePath
}

def createBuildTask(tasksHolder, config) {
def parameters = getBuildParameters(config.name)
def buildDirectory = "${config.buildBase}/${parameters.identifier}"
def distDirectory = "${config.projectBase}/dist/${parameters.identifier}"
def deployDirectory = "${config.deployBase}/src/main/resources/natives/${parameters.identifier}"
def taskBase = "${config.name}"

parameters.env.put('DIST_DIR', distDirectory)
parameters.env.put('JAVA_HOME', getHomeDirectory())

def setupTask = tasksHolder.create("${taskBase}-setup", Exec) {
doFirst {
file(buildDirectory).with {
it.deleteDir()
it.mkdirs()
}
}

workingDir buildDirectory
executable 'cmake'
args(parameters.setupArguments + ['../..'])
environment parameters.env
}

def buildTask = tasksHolder.create("${taskBase}-build", Exec) {
workingDir buildDirectory
executable 'cmake'
args(['--build', '.'] + parameters.buildArguments)
environment parameters.env
}

def deployTask = tasksHolder.create("${taskBase}-deploy") { doLast {
copy {
from distDirectory
into deployDirectory
}
}}

tasksHolder.create("${taskBase}-deploy-only") { doLast {
copy {
from distDirectory
into deployDirectory
}
}}

if (config.setupDependency) {
setupTask.dependsOn(config.setupDependency)
}

buildTask.dependsOn(setupTask)
deployTask.dependsOn(buildTask)
config.compileTask.dependsOn(deployTask)

if (!file("${deployDirectory}/${parameters.library}").exists()) {
config.checkTask.dependsOn(deployTask)
}
}

ext.createBuildTask = { tasksHolder, config -> createBuildTask(tasksHolder, config) }
Loading