Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 16 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ lmdb: third_party/lmdb
.PHONY: libvpx
libvpx: third_party/libvpx

.PHONY: flac
flac: third_party/flac

.PHONY: cacert
cacert: third_party/cacert.pem

Expand All @@ -100,7 +103,19 @@ third_party_dir:

.PHONY: third_party
third_party: third_party_dir libvpx openssl opus samplerate portaudio lmdb \
cacert
flac cacert


third_party/flac:
$(HIDE)cd third_party && \
wget ${FLAC_MIRROR}/flac-${FLAC_VERSION}.tar.xz && \
tar -xvf flac-${FLAC_VERSION}.tar.xz && \
mv flac-${FLAC_VERSION} flac && cd flac && \
$(_ARCH_CONFIGURE) \
--disable-ogg --enable-static --disable-cpplibs && \
make -j4 && \
cp src/libFLAC/.libs/libFLAC.a ../lib/ && \
cp -a include/FLAC ../include

third_party/libvpx:
$(HIDE)cd third_party && \
Expand Down
9 changes: 9 additions & 0 deletions cmake/FindFLAC.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FIND_PATH(FLAC_INCLUDE_DIR FLAC/metadata.h HINTS include)

FIND_LIBRARY(FLAC_LIBRARIES NAMES FLAC HINTS lib)

INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(FLAC DEFAULT_MSG FLAC_LIBRARIES FLAC_INCLUDE_DIR)

# show the FLAC_INCLUDE_DIR and FLAC_LIBRARIES variables only in the advanced view
MARK_AS_ADVANCED(FLAC_INCLUDE_DIR FLAC_LIBRARIES)
5 changes: 4 additions & 1 deletion libsl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
project(sl LANGUAGES C)

find_package(LMDB REQUIRED)
find_package(FLAC REQUIRED)

##############################################################################
#
Expand All @@ -22,10 +23,12 @@ set(SRCS
src/audio.c
src/conf.c
src/db.c
src/flac.c
src/http/client.c
src/http/server.c
src/main.c
src/meters.c
src/record.c
src/tracks.c
src/ws.c
)
Expand Down Expand Up @@ -83,7 +86,7 @@ LIST(APPEND COMPILED_RESOURCES ${OUTPUT_FILE})
#
# Main target object
#
set(LINKLIBS baresip re ${LMDB_LIBRARIES} ${OPENH264_LIBRARIES} stdc++)
set(LINKLIBS baresip re ${FLAC_LIBRARIES} ${LMDB_LIBRARIES} stdc++)

if(WIN32)
list(APPEND LINKLIBS winmm setupapi)
Expand Down
18 changes: 18 additions & 0 deletions libsl/include/studiolink.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,24 @@ int sl_account_close(void);
struct ua *sl_account_ua(void);


/******************************************************************************
* record.c
*/
uint64_t sl_record_msecs(void);
void sl_record_toggle(const char *folder);
int sl_record_start(const char *folder);
void sl_record(struct auframe *af);
int sl_record_close(void);


/******************************************************************************
* flac.c
*/
struct flac;
int sl_flac_init(struct flac **flacp, struct auframe *af, char *file);
int sl_flac_record(struct flac *flac, struct auframe *af, uint64_t offset);


#ifdef __cplusplus
}
#endif
Expand Down
164 changes: 164 additions & 0 deletions libsl/src/flac.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#include <FLAC/metadata.h>
#include <FLAC/stream_encoder.h>
#include <string.h>

#include <re.h>
#include <rem.h>
#include <baresip.h>
#include <studiolink.h>

struct flac {
FLAC__StreamEncoder *enc;
FLAC__StreamMetadata *m[2];
FLAC__int32 *pcm;
};


static void flac_destruct(void *arg)
{
struct flac *flac = arg;

mem_deref(flac->pcm);
FLAC__stream_encoder_finish(flac->enc);
FLAC__stream_encoder_delete(flac->enc);
FLAC__metadata_object_delete(flac->m[0]);
FLAC__metadata_object_delete(flac->m[1]);
}


int sl_flac_init(struct flac **flacp, struct auframe *af, char *file)
{

struct flac *flac;
FLAC__bool ret;
FLAC__StreamEncoderInitStatus init;
FLAC__StreamMetadata_VorbisComment_Entry entry;


if (!flacp || !af || !file)
return EINVAL;

flac = mem_zalloc(sizeof(struct flac), flac_destruct);
if (!flac)
return ENOMEM;

flac->pcm = mem_zalloc(af->sampc * sizeof(FLAC__int32), NULL);


flac->enc = FLAC__stream_encoder_new();
if (!flac->enc)
return ENOMEM;

ret = FLAC__stream_encoder_set_verify(flac->enc, true);
ret &= FLAC__stream_encoder_set_compression_level(flac->enc, 5);
ret &= FLAC__stream_encoder_set_channels(flac->enc, af->ch);
ret &= FLAC__stream_encoder_set_bits_per_sample(flac->enc, 16);
ret &= FLAC__stream_encoder_set_sample_rate(flac->enc, af->srate);
ret &= FLAC__stream_encoder_set_total_samples_estimate(flac->enc, 0);

if (!ret) {
warning("record: FLAC__stream_encoder_set\n");
return EINVAL;
}

/* METADATA */
flac->m[0] =
FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
flac->m[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);

ret = FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(
&entry, "ENCODED_BY", "STUDIO LINK MIX");

ret &= FLAC__metadata_object_vorbiscomment_append_comment(
flac->m[0], entry, /*copy=*/false);

if (!ret) {
warning("record: FLAC METADATA ERROR: out of memory or tag "
"error\n");
return ENOMEM;
}

flac->m[1]->length = 1234; /* padding length */

ret = FLAC__stream_encoder_set_metadata(flac->enc, flac->m, 2);

if (!ret) {
warning("record: FLAC__stream_encoder_set_metadata\n");
return ENOMEM;
}

init = FLAC__stream_encoder_init_file(flac->enc, file, NULL, NULL);

if (init != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
warning("record: FLAC ERROR: initializing encoder: %s\n",
FLAC__StreamEncoderInitStatusString[init]);
return ENOMEM;
}

*flacp = flac;

return 0;
}


int sl_flac_record(struct flac *flac, struct auframe *af, uint64_t offset)
{
FLAC__StreamEncoderState state;
FLAC__bool ret;

if (!flac || !af || !af->ch)
return EINVAL;

if (offset > 24 * 3600 * 1000) {
warning("flac_record: ignoring high >24h offset (%llu)\n",
offset);
offset = 0;
}

if (offset < 40 /*ms*/)
offset = 0;

if (offset) {
info("flac_record: offset %llu id %u\n", offset, af->id);
memset(flac->pcm, 0, af->sampc * sizeof(FLAC__int32));
uint64_t offsampc = af->srate * af->ch * offset / 1000;

while (offsampc) {
ret = FLAC__stream_encoder_process_interleaved(
flac->enc, flac->pcm,
(uint32_t)af->sampc / af->ch);
if (!ret)
goto err;

if (offsampc >= af->sampc)
offsampc -= af->sampc;
else {
ret = FLAC__stream_encoder_process_interleaved(
flac->enc, flac->pcm,
(uint32_t)offsampc / af->ch);
if (!ret)
goto err;
offsampc = 0;
}
}
}

int16_t *sampv = (int16_t *)af->sampv;

for (size_t i = 0; i < af->sampc; i++) {
flac->pcm[i] = sampv[i];
}

ret = FLAC__stream_encoder_process_interleaved(
flac->enc, flac->pcm, (uint32_t)af->sampc / af->ch);
if (ret)
return 0;


err:
state = FLAC__stream_encoder_get_state(flac->enc);
warning("record: FLAC ENCODE ERROR: %s\n",
FLAC__StreamEncoderStateString[state]);

return EPROTO;
}
10 changes: 10 additions & 0 deletions libsl/src/http/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,16 @@ static void http_req_handler(struct http_conn *conn,
}


if (0 == pl_strcasecmp(&msg->path, "/api/v1/record") &&
0 == pl_strcasecmp(&msg->met, "POST")) {

sl_record_toggle("/tmp");
http_sreply(conn, 200, "OK", "text/html", "", 0);

goto out;
}


#ifndef RELEASE
/* Default return OPTIONS - needed on dev for preflight CORS Check
* @TODO: add release test */
Expand Down
2 changes: 1 addition & 1 deletion libsl/src/meters.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ static void write_ws(void)
p[0] = '\0';

/* Record time */
re_snprintf(one_peak, sizeof(one_peak), "0 0 ");
re_snprintf(one_peak, sizeof(one_peak), "%llu ", sl_record_msecs());
strcat((char *)p, one_peak);

for (i = 0; i < MAX_METERS; i++) {
Expand Down
Loading
Loading