diff --git a/configure.ac b/configure.ac index 388fae2..c868a1f 100644 --- a/configure.ac +++ b/configure.ac @@ -1073,6 +1073,24 @@ AC_SUBST(OPENSSL_LIBS) AM_CONDITIONAL([HAVE_OPENSSL], [test "x$HAVE_OPENSSL" = x1]) AS_IF([test "x$HAVE_OPENSSL" = "x1"], AC_DEFINE([HAVE_OPENSSL], 1, [Have OpenSSL])) +#### Simple ALAC support (for Airtunes/RAOP) #### + +AC_ARG_ENABLE([libsalac], + AS_HELP_STRING([--disable-libsalac],[Disable Simple ALAC support (used for Airtunes/RAOP)])) + +AS_IF([test "x$enable_libsalac" != "xno"], + [PKG_CHECK_MODULES(LIBSALAC, [ libsalac-1.0 > 0.0 ], HAVE_LIBSALAC=1, HAVE_LIBSALAC=0)], + HAVE_LIBSALAC=0) + +AS_IF([test "x$enable_libsalac" = "xyes" && test "x$HAVE_LIBSALAC" = "x0"], + [AC_MSG_ERROR([*** Simple ALAC Libraray not found])]) + +AC_SUBST(LIBSALAC_CFLAGS) +AC_SUBST(LIBSALAC_LIBS) +AM_CONDITIONAL([HAVE_LIBSALAC], [test "x$HAVE_LIBSALAC" = x1]) +AS_IF([test "x$HAVE_LIBSALAC" = "x1"], AC_DEFINE([HAVE_LIBSALAC], 1, [Have Simple ALAC Library])) + + #### FFTW (optional) #### AC_ARG_WITH([fftw], diff --git a/src/Makefile.am b/src/Makefile.am index a621a30..8dd1272 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1038,9 +1038,9 @@ librtp_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@ libraop_la_SOURCES = \ modules/raop/raop_client.c modules/raop/raop_client.h \ modules/raop/base64.c modules/raop/base64.h -libraop_la_CFLAGS = $(AM_CFLAGS) $(OPENSSL_CFLAGS) -I$(top_srcdir)/src/modules/rtp +libraop_la_CFLAGS = $(AM_CFLAGS) $(OPENSSL_CFLAGS) $(LIBSALAC_CFLAGS) -I$(top_srcdir)/src/modules/rtp -I/usr/local/include/libsalac-1.0 libraop_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version -libraop_la_LIBADD = $(AM_LIBADD) $(OPENSSL_LIBS) libpulsecore-@PA_MAJORMINOR@.la librtp.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la +libraop_la_LIBADD = $(AM_LIBADD) $(OPENSSL_LIBS) $(LIBSALAC_LIBS) libpulsecore-@PA_MAJORMINOR@.la librtp.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la # Avahi libavahi_wrap_la_SOURCES = pulsecore/avahi-wrap.c pulsecore/avahi-wrap.h diff --git a/src/modules/raop/module-raop-sink.c b/src/modules/raop/module-raop-sink.c index 17edbb6..8dcfbd5 100644 --- a/src/modules/raop/module-raop-sink.c +++ b/src/modules/raop/module-raop-sink.c @@ -434,7 +434,7 @@ static void thread_func(void *userdata) { pa_assert(u->raw_memchunk.length > 0); length = u->raw_memchunk.length; - pa_raop_client_encode_block(u->raop, &u->raw_memchunk, &u->encoded_memchunk); + pa_raop_client_encode_alac_block(u->raop, &u->raw_memchunk, &u->encoded_memchunk); u->encoding_ratio = (double) u->encoded_memchunk.length / (double) (length - u->raw_memchunk.length); overhead = u->encoded_memchunk.length - (length - u->raw_memchunk.length); } diff --git a/src/modules/raop/raop_client.c b/src/modules/raop/raop_client.c index 8730953..5021490 100644 --- a/src/modules/raop/raop_client.c +++ b/src/modules/raop/raop_client.c @@ -59,6 +59,8 @@ #include "rtsp_client.h" #include "base64.h" +#include + #define FRAMES_PER_PACKET 352 #define AES_CHUNKSIZE 16 @@ -930,6 +932,9 @@ pa_raop_client* pa_raop_client_new(pa_core *core, const char *host, pa_sample_sp /* Packet sync interval should be around 1s. */ c->sync_interval = spec.rate / FRAMES_PER_PACKET; c->sync_count = 0; + + /* Initialize ALAC encoder */ + init_encoder(); } return c; @@ -945,6 +950,9 @@ void pa_raop_client_free(pa_raop_client *c) { pa_xfree(c->sid); pa_xfree(c->host); pa_xfree(c); + + /* Free encoder */ + delete_encoder(); } int pa_raop_client_connect(pa_raop_client *c) { @@ -1116,6 +1124,68 @@ int pa_raop_client_encode_block(pa_raop_client *c, pa_memchunk *raw, pa_memchunk return rv; } +int pa_raop_client_encode_alac_block(pa_raop_client *c, pa_memchunk *raw, pa_memchunk *encoded) { + const size_t offset = sizeof(audio_header); + unsigned char *block_raw = NULL; + uint8_t *block_enc = NULL; + int rv = 0; + + int frames = 0; + int alac_size = 0; + size_t enc_size = 0; + size_t length = 0; + + uint8_t *chunk_enc = NULL; + uint8_t *chunk_raw = NULL; + int num_enc = 0; + + pa_assert(c); + pa_assert(raw); + pa_assert(raw->memblock); + pa_assert(raw->length > 0); + pa_assert(encoded); + + pa_memchunk_reset(encoded); + + /* Max encoded chunk size is audio header offset + alac header size + unencoded length */ + frames = (int) (raw->length / 4); + length = frames * 4; + enc_size = offset + 16 + length; + + /* Acquire encoded chunk and memblock, set chunk index to 0 */ + encoded->memblock = pa_memblock_new(c->core->mempool, enc_size); + block_enc = pa_memblock_acquire(encoded->memblock); + chunk_enc = block_enc + encoded->index + offset; + + /* Acquire raw block and set offset to chunk */ + block_raw = pa_memblock_acquire(raw->memblock); + chunk_raw = block_raw + raw->index; + + if (chunk_raw != NULL && chunk_enc != NULL) { + alac_size = 0; + num_enc = encode_alac((unsigned char *) chunk_raw, (int) raw->length, (unsigned char*) chunk_enc, (int) alac_size); + + if (num_enc == 0) + rv = -1; + else + rv = 0; + + raw->index += raw->length; + raw->length -= raw->length; + } + + /* Encrypt our data if (RSA) encryption is supported */ + if (c->encryption) + aes_encrypt(c, chunk_enc, num_enc); + + encoded->length = num_enc + offset; + c->rtptime += FRAMES_PER_PACKET; + + pa_memblock_release(raw->memblock); + pa_memblock_release(encoded->memblock); + return rv; +} + int pa_raop_client_send_audio_packet(pa_raop_client *c, pa_memchunk *block, ssize_t *written) { uint32_t *buf = NULL; ssize_t length = 0; diff --git a/src/modules/raop/raop_client.h b/src/modules/raop/raop_client.h index 63b6224..79a9586 100644 --- a/src/modules/raop/raop_client.h +++ b/src/modules/raop/raop_client.h @@ -42,6 +42,7 @@ int pa_raop_client_handle_timing_packet(pa_raop_client *c, const uint8_t packet[ int pa_raop_client_handle_control_packet(pa_raop_client *c, const uint8_t packet[], ssize_t size); int pa_raop_client_get_blocks_size(pa_raop_client *c, size_t *size); int pa_raop_client_encode_block(pa_raop_client *c, pa_memchunk *raw, pa_memchunk *encoded); +int pa_raop_client_encode_alac_block(pa_raop_client *c, pa_memchunk *raw, pa_memchunk *encoded); int pa_raop_client_send_audio_packet(pa_raop_client *c, pa_memchunk *block, ssize_t *written); int pa_raop_client_set_volume(pa_raop_client *c, pa_volume_t volume);