[httpd] Check speaker settings to determine DAAP/RSP stream format

This commit is contained in:
ejurgensen 2024-01-10 21:20:31 +01:00
parent 62b42ce354
commit ff2d0b4ab1
9 changed files with 92 additions and 12 deletions

View File

@ -1069,7 +1069,7 @@ httpd_stream_file(struct httpd_request *hreq, int id)
}
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)
{
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);
}
// 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 *
httpd_gzip_deflate(struct evbuffer *in)
{

View File

@ -1146,7 +1146,7 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
const struct dmap_field **meta = NULL;
struct sort_ctx *sctx;
const char *param;
const char *client_codecs;
const char *accept_codecs;
const char *tag;
size_t len;
enum transcode_profile profile;
@ -1216,10 +1216,10 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
goto error;
}
client_codecs = NULL;
accept_codecs = NULL;
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;
@ -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
// 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)
{
DPRINTF(E_LOG, L_DAAP, "Cannot transcode '%s', codec type is unknown\n", dbmfi.fname);

View File

@ -206,6 +206,9 @@ struct httpd_request {
void
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
httpd_request_handler_set(struct httpd_request *hreq);

View File

@ -525,6 +525,7 @@ httpd_backend_output_buffer_get(httpd_backend *backend)
int
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);
if (!conn)
return -1;
@ -534,6 +535,11 @@ httpd_backend_peer_get(const char **addr, uint16_t *port, httpd_backend *backend
#else
evhttp_connection_get_peer(conn, (char **)addr, port);
#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;
}

View File

@ -415,7 +415,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)
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 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)
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)
{
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;
const char *param;
const char *client_codecs;
const char *accept_codecs;
xml_node *response;
xml_node *items;
int mode;
@ -493,7 +493,7 @@ rsp_reply_playlist(struct httpd_request *hreq)
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);
if (ret < 0)
@ -555,7 +555,7 @@ rsp_reply_playlist(struct httpd_request *hreq)
items = xml_new_node(response, "items", NULL);
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);

View File

@ -164,6 +164,7 @@ struct speaker_get_param
{
uint64_t spk_id;
uint32_t active_remote;
const char *address;
struct player_speaker_info *spk_info;
};
@ -2606,6 +2607,31 @@ speaker_get_byactiveremote(void *arg, int *retval)
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
speaker_set(void *arg, int *retval)
{
@ -3444,6 +3470,19 @@ player_speaker_get_byactiveremote(struct player_speaker_info *spk, uint32_t acti
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, &param);
return ret;
}
int
player_speaker_enable(uint64_t id)
{

View File

@ -103,6 +103,9 @@ player_speaker_get_byid(struct player_speaker_info *spk, uint64_t id);
int
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
player_speaker_enable(uint64_t id);

View File

@ -2097,7 +2097,7 @@ transcode_decode_setup_raw(enum transcode_profile profile, struct media_quality
}
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 *prefer_format;

View File

@ -112,7 +112,7 @@ struct decode_ctx *
transcode_decode_setup_raw(enum transcode_profile profile, struct media_quality *quality);
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
void