[httpd] Check speaker settings to determine DAAP/RSP stream format
This commit is contained in:
parent
62b42ce354
commit
ff2d0b4ab1
31
src/httpd.c
31
src/httpd.c
|
@ -1069,7 +1069,7 @@ httpd_stream_file(struct httpd_request *hreq, int id)
|
||||||
}
|
}
|
||||||
|
|
||||||
param = httpd_header_find(hreq->in_headers, "Accept-Codecs");
|
param = httpd_header_find(hreq->in_headers, "Accept-Codecs");
|
||||||
profile = transcode_needed(hreq->user_agent, param, mfi->codectype);
|
profile = httpd_xcode_profile_get(hreq->user_agent, hreq->peer_address, param, mfi->codectype);
|
||||||
if (profile == XCODE_UNKNOWN)
|
if (profile == XCODE_UNKNOWN)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_HTTPD, "Could not serve '%s' to client, unable to determine output format\n", mfi->path);
|
DPRINTF(E_LOG, L_HTTPD, "Could not serve '%s' to client, unable to determine output format\n", mfi->path);
|
||||||
|
@ -1188,6 +1188,35 @@ httpd_stream_file(struct httpd_request *hreq, int id)
|
||||||
free_mfi(mfi, 0);
|
free_mfi(mfi, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns enum transcode_profile, but is just declared with int so we don't
|
||||||
|
// need to include transcode.h in httpd_internal.h
|
||||||
|
int
|
||||||
|
httpd_xcode_profile_get(const char *user_agent, const char *address, const char *accept_codecs, const char *codec)
|
||||||
|
{
|
||||||
|
enum transcode_profile profile;
|
||||||
|
struct player_speaker_info spk;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
profile = transcode_needed(user_agent, accept_codecs, codec);
|
||||||
|
if (profile == XCODE_NONE)
|
||||||
|
return profile;
|
||||||
|
|
||||||
|
// A Roku Soundbridge may also be RCP device/speaker for which the user may
|
||||||
|
// have set a prefered streaming format
|
||||||
|
ret = player_speaker_get_byaddress(&spk, address);
|
||||||
|
if (ret < 0)
|
||||||
|
return profile;
|
||||||
|
|
||||||
|
if (spk.format == MEDIA_FORMAT_WAV)
|
||||||
|
return XCODE_WAV;
|
||||||
|
if (spk.format == MEDIA_FORMAT_MP3)
|
||||||
|
return XCODE_MP3;
|
||||||
|
if (spk.format == MEDIA_FORMAT_ALAC)
|
||||||
|
return XCODE_MP4_ALAC;
|
||||||
|
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
|
||||||
struct evbuffer *
|
struct evbuffer *
|
||||||
httpd_gzip_deflate(struct evbuffer *in)
|
httpd_gzip_deflate(struct evbuffer *in)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1146,7 +1146,7 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
|
||||||
const struct dmap_field **meta = NULL;
|
const struct dmap_field **meta = NULL;
|
||||||
struct sort_ctx *sctx;
|
struct sort_ctx *sctx;
|
||||||
const char *param;
|
const char *param;
|
||||||
const char *client_codecs;
|
const char *accept_codecs;
|
||||||
const char *tag;
|
const char *tag;
|
||||||
size_t len;
|
size_t len;
|
||||||
enum transcode_profile profile;
|
enum transcode_profile profile;
|
||||||
|
@ -1216,10 +1216,10 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
client_codecs = NULL;
|
accept_codecs = NULL;
|
||||||
if (!s->is_remote && hreq->in_headers)
|
if (!s->is_remote && hreq->in_headers)
|
||||||
{
|
{
|
||||||
client_codecs = httpd_header_find(hreq->in_headers, "Accept-Codecs");
|
accept_codecs = httpd_header_find(hreq->in_headers, "Accept-Codecs");
|
||||||
}
|
}
|
||||||
|
|
||||||
nsongs = 0;
|
nsongs = 0;
|
||||||
|
@ -1229,7 +1229,7 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
|
||||||
|
|
||||||
// Not sure if the is_remote path is really needed. Note that if you
|
// Not sure if the is_remote path is really needed. Note that if you
|
||||||
// change the below you might need to do the same in rsp_reply_playlist()
|
// change the below you might need to do the same in rsp_reply_playlist()
|
||||||
profile = s->is_remote ? XCODE_WAV : transcode_needed(hreq->user_agent, client_codecs, dbmfi.codectype);
|
profile = s->is_remote ? XCODE_WAV : httpd_xcode_profile_get(hreq->user_agent, hreq->peer_address, accept_codecs, dbmfi.codectype);
|
||||||
if (profile == XCODE_UNKNOWN)
|
if (profile == XCODE_UNKNOWN)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_DAAP, "Cannot transcode '%s', codec type is unknown\n", dbmfi.fname);
|
DPRINTF(E_LOG, L_DAAP, "Cannot transcode '%s', codec type is unknown\n", dbmfi.fname);
|
||||||
|
|
|
@ -206,6 +206,9 @@ struct httpd_request {
|
||||||
void
|
void
|
||||||
httpd_stream_file(struct httpd_request *hreq, int id);
|
httpd_stream_file(struct httpd_request *hreq, int id);
|
||||||
|
|
||||||
|
int
|
||||||
|
httpd_xcode_profile_get(const char *user_agent, const char *address, const char *accept_codecs, const char *codec);
|
||||||
|
|
||||||
void
|
void
|
||||||
httpd_request_handler_set(struct httpd_request *hreq);
|
httpd_request_handler_set(struct httpd_request *hreq);
|
||||||
|
|
||||||
|
|
|
@ -525,6 +525,7 @@ httpd_backend_output_buffer_get(httpd_backend *backend)
|
||||||
int
|
int
|
||||||
httpd_backend_peer_get(const char **addr, uint16_t *port, httpd_backend *backend, httpd_backend_data *backend_data)
|
httpd_backend_peer_get(const char **addr, uint16_t *port, httpd_backend *backend, httpd_backend_data *backend_data)
|
||||||
{
|
{
|
||||||
|
#define IPV4_MAPPED_IPV6_PREFIX "::ffff:"
|
||||||
httpd_connection *conn = evhttp_request_get_connection(backend);
|
httpd_connection *conn = evhttp_request_get_connection(backend);
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -534,6 +535,11 @@ httpd_backend_peer_get(const char **addr, uint16_t *port, httpd_backend *backend
|
||||||
#else
|
#else
|
||||||
evhttp_connection_get_peer(conn, (char **)addr, port);
|
evhttp_connection_get_peer(conn, (char **)addr, port);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Just use the pure ipv4 address if it's mapped
|
||||||
|
if (strncmp(*addr, IPV4_MAPPED_IPV6_PREFIX, strlen(IPV4_MAPPED_IPV6_PREFIX)) == 0)
|
||||||
|
*addr += strlen(IPV4_MAPPED_IPV6_PREFIX);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -415,7 +415,7 @@ rsp_reply_db(struct httpd_request *hreq)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
item_add(xml_node *parent, struct query_params *qp, const char *user_agent, const char *client_codecs, int mode)
|
item_add(xml_node *parent, struct query_params *qp, const char *user_agent, const char *address, const char *accept_codecs, int mode)
|
||||||
{
|
{
|
||||||
struct media_quality quality = { 0 };
|
struct media_quality quality = { 0 };
|
||||||
struct db_media_file_info dbmfi;
|
struct db_media_file_info dbmfi;
|
||||||
|
@ -432,7 +432,7 @@ item_add(xml_node *parent, struct query_params *qp, const char *user_agent, cons
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
profile = transcode_needed(user_agent, client_codecs, dbmfi.codectype);
|
profile = httpd_xcode_profile_get(user_agent, address, accept_codecs, dbmfi.codectype);
|
||||||
if (profile == XCODE_UNKNOWN)
|
if (profile == XCODE_UNKNOWN)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_DAAP, "Cannot transcode '%s', codec type is unknown\n", dbmfi.fname);
|
DPRINTF(E_LOG, L_DAAP, "Cannot transcode '%s', codec type is unknown\n", dbmfi.fname);
|
||||||
|
@ -484,7 +484,7 @@ rsp_reply_playlist(struct httpd_request *hreq)
|
||||||
{
|
{
|
||||||
struct query_params qp;
|
struct query_params qp;
|
||||||
const char *param;
|
const char *param;
|
||||||
const char *client_codecs;
|
const char *accept_codecs;
|
||||||
xml_node *response;
|
xml_node *response;
|
||||||
xml_node *items;
|
xml_node *items;
|
||||||
int mode;
|
int mode;
|
||||||
|
@ -493,7 +493,7 @@ rsp_reply_playlist(struct httpd_request *hreq)
|
||||||
|
|
||||||
memset(&qp, 0, sizeof(struct query_params));
|
memset(&qp, 0, sizeof(struct query_params));
|
||||||
|
|
||||||
client_codecs = httpd_header_find(hreq->in_headers, "Accept-Codecs");
|
accept_codecs = httpd_header_find(hreq->in_headers, "Accept-Codecs");
|
||||||
|
|
||||||
ret = safe_atoi32(hreq->path_parts[2], &qp.id);
|
ret = safe_atoi32(hreq->path_parts[2], &qp.id);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -555,7 +555,7 @@ rsp_reply_playlist(struct httpd_request *hreq)
|
||||||
items = xml_new_node(response, "items", NULL);
|
items = xml_new_node(response, "items", NULL);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
ret = item_add(items, &qp, hreq->user_agent, client_codecs, mode);
|
ret = item_add(items, &qp, hreq->user_agent, hreq->peer_address, accept_codecs, mode);
|
||||||
}
|
}
|
||||||
while (ret == 0);
|
while (ret == 0);
|
||||||
|
|
||||||
|
|
39
src/player.c
39
src/player.c
|
@ -164,6 +164,7 @@ struct speaker_get_param
|
||||||
{
|
{
|
||||||
uint64_t spk_id;
|
uint64_t spk_id;
|
||||||
uint32_t active_remote;
|
uint32_t active_remote;
|
||||||
|
const char *address;
|
||||||
struct player_speaker_info *spk_info;
|
struct player_speaker_info *spk_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2606,6 +2607,31 @@ speaker_get_byactiveremote(void *arg, int *retval)
|
||||||
return COMMAND_END;
|
return COMMAND_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum command_state
|
||||||
|
speaker_get_byaddress(void *arg, int *retval)
|
||||||
|
{
|
||||||
|
struct speaker_get_param *spk_param = arg;
|
||||||
|
struct output_device *device;
|
||||||
|
bool match_v4;
|
||||||
|
bool match_v6;
|
||||||
|
|
||||||
|
for (device = outputs_list(); device; device = device->next)
|
||||||
|
{
|
||||||
|
match_v4 = device->v4_address && (strcmp(spk_param->address, device->v4_address) == 0);
|
||||||
|
match_v6 = device->v6_address && (strcmp(spk_param->address, device->v6_address) == 0);
|
||||||
|
if (match_v4 || match_v6)
|
||||||
|
{
|
||||||
|
device_to_speaker_info(spk_param->spk_info, device);
|
||||||
|
*retval = 0;
|
||||||
|
return COMMAND_END;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No output device found with matching id
|
||||||
|
*retval = -1;
|
||||||
|
return COMMAND_END;
|
||||||
|
}
|
||||||
|
|
||||||
static enum command_state
|
static enum command_state
|
||||||
speaker_set(void *arg, int *retval)
|
speaker_set(void *arg, int *retval)
|
||||||
{
|
{
|
||||||
|
@ -3444,6 +3470,19 @@ player_speaker_get_byactiveremote(struct player_speaker_info *spk, uint32_t acti
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
player_speaker_get_byaddress(struct player_speaker_info *spk, const char *address)
|
||||||
|
{
|
||||||
|
struct speaker_get_param param;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
param.address = address;
|
||||||
|
param.spk_info = spk;
|
||||||
|
|
||||||
|
ret = commands_exec_sync(cmdbase, speaker_get_byaddress, NULL, ¶m);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
player_speaker_enable(uint64_t id)
|
player_speaker_enable(uint64_t id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -103,6 +103,9 @@ player_speaker_get_byid(struct player_speaker_info *spk, uint64_t id);
|
||||||
int
|
int
|
||||||
player_speaker_get_byactiveremote(struct player_speaker_info *spk, uint32_t active_remote);
|
player_speaker_get_byactiveremote(struct player_speaker_info *spk, uint32_t active_remote);
|
||||||
|
|
||||||
|
int
|
||||||
|
player_speaker_get_byaddress(struct player_speaker_info *spk, const char *address);
|
||||||
|
|
||||||
int
|
int
|
||||||
player_speaker_enable(uint64_t id);
|
player_speaker_enable(uint64_t id);
|
||||||
|
|
||||||
|
|
|
@ -2097,7 +2097,7 @@ transcode_decode_setup_raw(enum transcode_profile profile, struct media_quality
|
||||||
}
|
}
|
||||||
|
|
||||||
enum transcode_profile
|
enum transcode_profile
|
||||||
transcode_needed(const char *user_agent, const char *client_codecs, char *file_codectype)
|
transcode_needed(const char *user_agent, const char *client_codecs, const char *file_codectype)
|
||||||
{
|
{
|
||||||
const char *codectype;
|
const char *codectype;
|
||||||
const char *prefer_format;
|
const char *prefer_format;
|
||||||
|
|
|
@ -112,7 +112,7 @@ struct decode_ctx *
|
||||||
transcode_decode_setup_raw(enum transcode_profile profile, struct media_quality *quality);
|
transcode_decode_setup_raw(enum transcode_profile profile, struct media_quality *quality);
|
||||||
|
|
||||||
enum transcode_profile
|
enum transcode_profile
|
||||||
transcode_needed(const char *user_agent, const char *client_codecs, char *file_codectype);
|
transcode_needed(const char *user_agent, const char *client_codecs, const char *file_codectype);
|
||||||
|
|
||||||
// Cleaning up
|
// Cleaning up
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in New Issue