Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[xcode] Support for ALAC encoded RSP/DAAP streaming #1698

Closed
wants to merge 3 commits into from
Closed
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
21 changes: 13 additions & 8 deletions owntone.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -187,19 +187,24 @@ library {
# Should we import the content of iTunes smart playlists?
# itunes_smartpl = false

# Decoding options for DAAP and RSP clients
# Transcoding options for DAAP and RSP clients
# Since iTunes has native support for mpeg, mp4a, mp4v, alac and wav,
# such files will be sent as they are. Any other formats will be decoded
# to raw wav. If OwnTone detects a non-iTunes DAAP client, it is
# assumed to only support mpeg and wav, other formats will be decoded.
# Here you can change when to decode. Note that these settings only
# affect serving media to DAAP and RSP clients, they have no effect on
# such files will be sent as they are. Any other formats will be
# transcoded. Some other clients, including Roku/RSP, announce what
# formats they support, and the server will transcode to one of those if
# necessary. Clients that don't announce supported formats are assumed
# to support mpeg (mp3), wav and alac.
# Here you can change when and how to transcode. The settings *only*
# affect serving audio to DAAP and RSP clients, they have no effect on
# direct AirPlay, Chromecast and local audio playback.
# Formats: mp4a, mp4v, mpeg, alac, flac, mpc, ogg, wma, wmal, wmav, aif, wav
# Formats that should never be decoded
# Formats that should never be transcoded
# no_decode = { "format", "format" }
# Formats that should always be decoded
# Formats that should always be transcoded
# force_decode = { "format", "format" }
# Prefer transcode to wav (default), alac or mpeg (mp3 with the bit rate
# configured below in the streaming section)
# prefer_format = "format"

# Set ffmpeg filters (similar to 'ffmpeg -af xxx') that you want the
# server to use when decoding files from your library. Examples:
Expand Down
1 change: 1 addition & 0 deletions src/conffile.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ static cfg_opt_t sec_library[] =
CFG_BOOL("itunes_smartpl", cfg_false, CFGF_NONE),
CFG_STR_LIST("no_decode", NULL, CFGF_NONE),
CFG_STR_LIST("force_decode", NULL, CFGF_NONE),
CFG_STR("prefer_format", NULL, CFGF_NONE),
CFG_BOOL("pipe_autostart", cfg_true, CFGF_NONE),
CFG_INT("pipe_sample_rate", 44100, CFGF_NONE),
CFG_INT("pipe_bits_per_sample", 16, CFGF_NONE),
Expand Down
29 changes: 16 additions & 13 deletions src/httpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,19 @@ struct stream_ctx {

static const struct content_type_map ext2ctype[] =
{
{ ".html", XCODE_NONE, "text/html; charset=utf-8" },
{ ".xml", XCODE_NONE, "text/xml; charset=utf-8" },
{ ".css", XCODE_NONE, "text/css; charset=utf-8" },
{ ".txt", XCODE_NONE, "text/plain; charset=utf-8" },
{ ".js", XCODE_NONE, "application/javascript; charset=utf-8" },
{ ".gif", XCODE_NONE, "image/gif" },
{ ".ico", XCODE_NONE, "image/x-ico" },
{ ".png", XCODE_PNG, "image/png" },
{ ".jpg", XCODE_JPEG, "image/jpeg" },
{ ".mp3", XCODE_MP3, "audio/mpeg" },
{ ".wav", XCODE_WAV, "audio/wav" },
{ NULL, XCODE_NONE, NULL }
{ ".html", XCODE_NONE, "text/html; charset=utf-8" },
{ ".xml", XCODE_NONE, "text/xml; charset=utf-8" },
{ ".css", XCODE_NONE, "text/css; charset=utf-8" },
{ ".txt", XCODE_NONE, "text/plain; charset=utf-8" },
{ ".js", XCODE_NONE, "application/javascript; charset=utf-8" },
{ ".gif", XCODE_NONE, "image/gif" },
{ ".ico", XCODE_NONE, "image/x-ico" },
{ ".png", XCODE_PNG, "image/png" },
{ ".jpg", XCODE_JPEG, "image/jpeg" },
{ ".mp3", XCODE_MP3, "audio/mpeg" },
{ ".m4a", XCODE_MP4_ALAC, "audio/mp4" },
{ ".wav", XCODE_WAV, "audio/wav" },
{ NULL, XCODE_NONE, NULL }
};

static char webroot_directory[PATH_MAX];
Expand Down Expand Up @@ -677,15 +678,17 @@ static struct stream_ctx *
stream_new_transcode(struct media_file_info *mfi, enum transcode_profile profile, struct httpd_request *hreq,
int64_t offset, int64_t end_offset, event_callback_fn stream_cb)
{
struct media_quality quality = { 0 };
struct stream_ctx *st;
struct media_quality quality = { HTTPD_STREAM_SAMPLE_RATE, HTTPD_STREAM_BPS, HTTPD_STREAM_CHANNELS, HTTPD_STREAM_BIT_RATE };

st = stream_new(mfi, hreq, stream_cb);
if (!st)
{
goto error;
}

// We use source sample rate etc, but for MP3 we must set a bit rate
quality.bit_rate = cfg_getint(cfg_getsec(cfg, "streaming"), "bit_rate");
st->xcode = transcode_setup(profile, &quality, mfi->data_kind, mfi->path, mfi->song_length);
if (!st->xcode)
{
Expand Down
7 changes: 6 additions & 1 deletion src/httpd_daap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1151,7 +1151,7 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
size_t len;
enum transcode_profile profile;
struct transcode_metadata_string xcode_metadata;
struct media_quality quality = { HTTPD_STREAM_SAMPLE_RATE, HTTPD_STREAM_BPS, HTTPD_STREAM_CHANNELS, HTTPD_STREAM_BIT_RATE };
struct media_quality quality = { 0 };
uint32_t len_ms;
int nmeta = 0;
int sort_headers;
Expand Down Expand Up @@ -1239,6 +1239,11 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
if (safe_atou32(dbmfi.song_length, &len_ms) < 0)
len_ms = 3 * 60 * 1000; // just a fallback default

safe_atoi32(dbmfi.samplerate, &quality.sample_rate);
safe_atoi32(dbmfi.bits_per_sample, &quality.bits_per_sample);
safe_atoi32(dbmfi.channels, &quality.channels);
quality.bit_rate = cfg_getint(cfg_getsec(cfg, "streaming"), "bit_rate");

transcode_metadata_strings_set(&xcode_metadata, profile, &quality, len_ms);
dbmfi.type = xcode_metadata.type;
dbmfi.codectype = xcode_metadata.codectype;
Expand Down
5 changes: 0 additions & 5 deletions src/httpd_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@
#define HTTP_BADGATEWAY 502 /**< received an invalid response from the upstream */
#define HTTP_SERVUNAVAIL 503 /**< the server is not available */

#define HTTPD_STREAM_SAMPLE_RATE 44100
#define HTTPD_STREAM_BPS 16
#define HTTPD_STREAM_CHANNELS 2
#define HTTPD_STREAM_BIT_RATE 320000


struct httpd_request;

Expand Down
17 changes: 16 additions & 1 deletion src/httpd_rsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ rsp_reply_db(struct httpd_request *hreq)
static int
item_add(xml_node *parent, struct query_params *qp, const char *user_agent, const char *client_codecs, int mode)
{
struct media_quality quality = { HTTPD_STREAM_SAMPLE_RATE, HTTPD_STREAM_BPS, HTTPD_STREAM_CHANNELS, HTTPD_STREAM_BIT_RATE };
struct media_quality quality = { 0 };
struct db_media_file_info dbmfi;
struct transcode_metadata_string xcode_metadata;
enum transcode_profile profile;
Expand All @@ -437,6 +437,11 @@ item_add(xml_node *parent, struct query_params *qp, const char *user_agent, cons
if (safe_atou32(dbmfi.song_length, &len_ms) < 0)
len_ms = 3 * 60 * 1000; // just a fallback default

safe_atoi32(dbmfi.samplerate, &quality.sample_rate);
safe_atoi32(dbmfi.bits_per_sample, &quality.bits_per_sample);
safe_atoi32(dbmfi.channels, &quality.channels);
quality.bit_rate = cfg_getint(cfg_getsec(cfg, "streaming"), "bit_rate");

transcode_metadata_strings_set(&xcode_metadata, profile, &quality, len_ms);
dbmfi.type = xcode_metadata.type;
dbmfi.codectype = xcode_metadata.codectype;
Expand Down Expand Up @@ -710,6 +715,16 @@ rsp_stream(struct httpd_request *hreq)
// /rsp/stream/36364
// /rsp/db/0?query=id%3D36365&type=full
// /rsp/stream/36365
//
// Headers sent from Roku M2000 and M1001 in stream requests (and other?):
//
// 'User-Agent': 'Roku SoundBridge/3.0'
// 'Host': '192.168.1.119:3689'
// 'Accept': '*/*'
// 'Pragma': 'no-cache'
// 'accept-codecs': 'wma,mpeg,wav,mp4a,alac'
// 'rsp-version': '0.1'
// 'transcode-codecs': 'wav,mp3'
static struct httpd_uri_map rsp_handlers[] =
{
{
Expand Down
12 changes: 12 additions & 0 deletions src/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ net_is_http_or_https(const char *url);

/* ----------------------- Conversion/hashing/sanitizers -------------------- */

#ifdef HAVE_ENDIAN_H
# include <endian.h>
#elif defined(HAVE_SYS_ENDIAN_H)
# include <sys/endian.h>
#elif defined(HAVE_LIBKERN_OSBYTEORDER_H)
#include <libkern/OSByteOrder.h>
#define htobe16(x) OSSwapHostToBigInt16(x)
#define be16toh(x) OSSwapBigToHostInt16(x)
#define htobe32(x) OSSwapHostToBigInt32(x)
#define be32toh(x) OSSwapBigToHostInt32(x)
#endif

// Samples to bytes, bytes to samples
#define STOB(s, bits, c) ((s) * (c) * (bits) / 8)
#define BTOS(b, bits, c) ((b) / ((c) * (bits) / 8))
Expand Down
11 changes: 2 additions & 9 deletions src/outputs/cast.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,7 @@
#include <ifaddrs.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef HAVE_ENDIAN_H
# include <endian.h>
#elif defined(HAVE_SYS_ENDIAN_H)
# include <sys/endian.h>
#elif defined(HAVE_LIBKERN_OSBYTEORDER_H)
#include <libkern/OSByteOrder.h>
#define htobe32(x) OSSwapHostToBigInt32(x)
#define be32toh(x) OSSwapBigToHostInt32(x)
#endif

#include <gnutls/gnutls.h>
#include <event2/event.h>
#include <json.h>
Expand All @@ -54,6 +46,7 @@
#include "outputs.h"
#include "db.h"
#include "artwork.h"
#include "misc.h"

#ifdef HAVE_PROTOBUF_OLD
#include "cast_channel.v0.pb-c.h"
Expand Down
12 changes: 0 additions & 12 deletions src/outputs/rtp_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,6 @@
#include <inttypes.h>
#include <stdbool.h>

#ifdef HAVE_ENDIAN_H
# include <endian.h>
#elif defined(HAVE_SYS_ENDIAN_H)
# include <sys/endian.h>
#elif defined(HAVE_LIBKERN_OSBYTEORDER_H)
#include <libkern/OSByteOrder.h>
#define htobe16(x) OSSwapHostToBigInt16(x)
#define be16toh(x) OSSwapBigToHostInt16(x)
#define htobe32(x) OSSwapHostToBigInt32(x)
#define be32toh(x) OSSwapBigToHostInt32(x)
#endif

struct rtcp_timestamp
{
uint32_t pos;
Expand Down
Loading
Loading