[streaming/xcode] configurable MP3 streaming bitrate
This commit is contained in:
parent
cae790ed7e
commit
554799ebc3
|
@ -367,3 +367,16 @@ sqlite {
|
||||||
# but may reduce database size). Default is yes.
|
# but may reduce database size). Default is yes.
|
||||||
# vacuum = yes
|
# vacuum = yes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Streaming audio settings for remote connections (ie stream.mp3)
|
||||||
|
streaming {
|
||||||
|
# Sample rate, typically 44100 or 48000
|
||||||
|
# sample_rate = 44100
|
||||||
|
|
||||||
|
# Channels
|
||||||
|
# channels = 2
|
||||||
|
|
||||||
|
# Set the MP3 streaming bit rate (in kbps), valid options: 64 / 96 / 128 / 192 / 320
|
||||||
|
# bit_rate = 192
|
||||||
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ static cfg_opt_t sec_general[] =
|
||||||
#else
|
#else
|
||||||
CFG_BOOL("high_resolution_clock", cfg_true, CFGF_NONE),
|
CFG_BOOL("high_resolution_clock", cfg_true, CFGF_NONE),
|
||||||
#endif
|
#endif
|
||||||
|
CFG_INT("streaming_bitrate", 192, CFGF_NONE),
|
||||||
// Hidden options
|
// Hidden options
|
||||||
CFG_INT("db_pragma_cache_size", -1, CFGF_NONE),
|
CFG_INT("db_pragma_cache_size", -1, CFGF_NONE),
|
||||||
CFG_STR("db_pragma_journal_mode", NULL, CFGF_NONE),
|
CFG_STR("db_pragma_journal_mode", NULL, CFGF_NONE),
|
||||||
|
@ -186,6 +187,15 @@ static cfg_opt_t sec_mpd[] =
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* streaming section structure */
|
||||||
|
static cfg_opt_t sec_streaming[] =
|
||||||
|
{
|
||||||
|
CFG_INT("sample_rate", 44100, CFGF_NONE),
|
||||||
|
CFG_INT("channels", 2, CFGF_NONE),
|
||||||
|
CFG_INT("bit_rate", 192, CFGF_NONE),
|
||||||
|
CFG_END()
|
||||||
|
};
|
||||||
|
|
||||||
/* Config file structure */
|
/* Config file structure */
|
||||||
static cfg_opt_t toplvl_cfg[] =
|
static cfg_opt_t toplvl_cfg[] =
|
||||||
{
|
{
|
||||||
|
@ -198,6 +208,7 @@ static cfg_opt_t toplvl_cfg[] =
|
||||||
CFG_SEC("spotify", sec_spotify, CFGF_NONE),
|
CFG_SEC("spotify", sec_spotify, CFGF_NONE),
|
||||||
CFG_SEC("sqlite", sec_sqlite, CFGF_NONE),
|
CFG_SEC("sqlite", sec_sqlite, CFGF_NONE),
|
||||||
CFG_SEC("mpd", sec_mpd, CFGF_NONE),
|
CFG_SEC("mpd", sec_mpd, CFGF_NONE),
|
||||||
|
CFG_SEC("streaming", sec_streaming, CFGF_NONE),
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1034,7 +1034,7 @@ httpd_request_parse(struct evhttp_request *req, struct httpd_uri_parsed *uri_par
|
||||||
void
|
void
|
||||||
httpd_stream_file(struct evhttp_request *req, int id)
|
httpd_stream_file(struct evhttp_request *req, int id)
|
||||||
{
|
{
|
||||||
struct media_quality quality = { HTTPD_STREAM_SAMPLE_RATE, HTTPD_STREAM_BPS, HTTPD_STREAM_CHANNELS };
|
struct media_quality quality = { HTTPD_STREAM_SAMPLE_RATE, HTTPD_STREAM_BPS, HTTPD_STREAM_CHANNELS, 0 };
|
||||||
struct media_file_info *mfi;
|
struct media_file_info *mfi;
|
||||||
struct stream_ctx *st;
|
struct stream_ctx *st;
|
||||||
void (*stream_cb)(int fd, short event, void *arg);
|
void (*stream_cb)(int fd, short event, void *arg);
|
||||||
|
|
|
@ -52,6 +52,8 @@ extern struct event_base *evbase_httpd;
|
||||||
#define STREAMING_MP3_SAMPLE_RATE 44100
|
#define STREAMING_MP3_SAMPLE_RATE 44100
|
||||||
#define STREAMING_MP3_BPS 16
|
#define STREAMING_MP3_BPS 16
|
||||||
#define STREAMING_MP3_CHANNELS 2
|
#define STREAMING_MP3_CHANNELS 2
|
||||||
|
#define STREAMING_MP3_BIT_RATE 192000
|
||||||
|
static int streaming_mp3_bit_rate = STREAMING_MP3_BIT_RATE;
|
||||||
|
|
||||||
|
|
||||||
// Linked list of mp3 streaming requests
|
// Linked list of mp3 streaming requests
|
||||||
|
@ -182,7 +184,7 @@ streaming_end(void)
|
||||||
static void
|
static void
|
||||||
streaming_meta_cb(evutil_socket_t fd, short event, void *arg)
|
streaming_meta_cb(evutil_socket_t fd, short event, void *arg)
|
||||||
{
|
{
|
||||||
struct media_quality mp3_quality = { STREAMING_MP3_SAMPLE_RATE, STREAMING_MP3_BPS, STREAMING_MP3_CHANNELS };
|
struct media_quality mp3_quality = { STREAMING_MP3_SAMPLE_RATE, STREAMING_MP3_BPS, STREAMING_MP3_CHANNELS, streaming_mp3_bit_rate };
|
||||||
struct media_quality quality;
|
struct media_quality quality;
|
||||||
struct decode_ctx *decode_ctx;
|
struct decode_ctx *decode_ctx;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -204,6 +206,9 @@ streaming_meta_cb(evutil_socket_t fd, short event, void *arg)
|
||||||
if (!decode_ctx)
|
if (!decode_ctx)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
if (quality.bit_rate)
|
||||||
|
mp3_quality.bit_rate = quality.bit_rate;
|
||||||
|
|
||||||
streaming_encode_ctx = transcode_encode_setup(XCODE_MP3, &mp3_quality, decode_ctx, NULL, 0, 0);
|
streaming_encode_ctx = transcode_encode_setup(XCODE_MP3, &mp3_quality, decode_ctx, NULL, 0, 0);
|
||||||
transcode_decode_cleanup(&decode_ctx);
|
transcode_decode_cleanup(&decode_ctx);
|
||||||
if (!streaming_encode_ctx)
|
if (!streaming_encode_ctx)
|
||||||
|
@ -618,6 +623,23 @@ streaming_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
streaming_mp3_bit_rate = cfg_getint(cfg_getsec(cfg, "streaming"), "bit_rate");
|
||||||
|
switch (streaming_mp3_bit_rate)
|
||||||
|
{
|
||||||
|
case 64:
|
||||||
|
case 96:
|
||||||
|
case 128:
|
||||||
|
case 192:
|
||||||
|
case 320:
|
||||||
|
streaming_mp3_bit_rate *= 1000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DPRINTF(E_WARN, L_STREAMING, "streaming bit_rate=%d not 128/192/320, defaulting\n", streaming_mp3_bit_rate);
|
||||||
|
streaming_mp3_bit_rate = STREAMING_MP3_BIT_RATE;
|
||||||
|
}
|
||||||
|
DPRINTF(E_INFO, L_STREAMING, "streaming bit_rate=%d\n", streaming_mp3_bit_rate);
|
||||||
|
|
||||||
pthread_mutex_init(&streaming_sessions_lck, NULL);
|
pthread_mutex_init(&streaming_sessions_lck, NULL);
|
||||||
|
|
||||||
// Non-blocking because otherwise httpd and player thread may deadlock
|
// Non-blocking because otherwise httpd and player thread may deadlock
|
||||||
|
|
|
@ -31,6 +31,7 @@ struct media_quality {
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
int bits_per_sample;
|
int bits_per_sample;
|
||||||
int channels;
|
int channels;
|
||||||
|
int bit_rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct onekeyval {
|
struct onekeyval {
|
||||||
|
|
|
@ -140,7 +140,7 @@ static int alsa_latency_history_size;
|
||||||
|
|
||||||
// We will try to play the music with the source quality, but if the card
|
// We will try to play the music with the source quality, but if the card
|
||||||
// doesn't support that we resample to the fallback quality
|
// doesn't support that we resample to the fallback quality
|
||||||
static struct media_quality alsa_fallback_quality = { 44100, 16, 2 };
|
static struct media_quality alsa_fallback_quality = { 44100, 16, 2, 0 };
|
||||||
static struct media_quality alsa_last_quality;
|
static struct media_quality alsa_last_quality;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -446,7 +446,7 @@ static struct cast_session *cast_sessions;
|
||||||
static struct cast_master_session *cast_master_session;
|
static struct cast_master_session *cast_master_session;
|
||||||
//static struct timeval heartbeat_timeout = { HEARTBEAT_TIMEOUT, 0 };
|
//static struct timeval heartbeat_timeout = { HEARTBEAT_TIMEOUT, 0 };
|
||||||
static struct timeval reply_timeout = { REPLY_TIMEOUT, 0 };
|
static struct timeval reply_timeout = { REPLY_TIMEOUT, 0 };
|
||||||
static struct media_quality cast_quality_default = { CAST_QUALITY_SAMPLE_RATE_DEFAULT, CAST_QUALITY_BITS_PER_SAMPLE_DEFAULT, CAST_QUALITY_CHANNELS_DEFAULT };
|
static struct media_quality cast_quality_default = { CAST_QUALITY_SAMPLE_RATE_DEFAULT, CAST_QUALITY_BITS_PER_SAMPLE_DEFAULT, CAST_QUALITY_CHANNELS_DEFAULT, 0 };
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------- MISC HELPERS ----------------------------- */
|
/* ------------------------------- MISC HELPERS ----------------------------- */
|
||||||
|
|
|
@ -61,7 +61,7 @@ struct fifo_buffer
|
||||||
|
|
||||||
static struct fifo_buffer buffer;
|
static struct fifo_buffer buffer;
|
||||||
|
|
||||||
static struct media_quality fifo_quality = { 44100, 16, 2 };
|
static struct media_quality fifo_quality = { 44100, 16, 2, 0 };
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -86,7 +86,7 @@ static struct pulse_session *sessions;
|
||||||
static uint32_t pulse_known_devices[PULSE_MAX_DEVICES];
|
static uint32_t pulse_known_devices[PULSE_MAX_DEVICES];
|
||||||
|
|
||||||
static struct media_quality pulse_last_quality;
|
static struct media_quality pulse_last_quality;
|
||||||
static struct media_quality pulse_fallback_quality = { 44100, 16, 2 };
|
static struct media_quality pulse_fallback_quality = { 44100, 16, 2, 0 };
|
||||||
|
|
||||||
// Converts from 0 - 100 to Pulseaudio's scale
|
// Converts from 0 - 100 to Pulseaudio's scale
|
||||||
static inline pa_volume_t
|
static inline pa_volume_t
|
||||||
|
|
|
@ -79,6 +79,7 @@ struct settings_ctx
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
uint64_t channel_layout;
|
uint64_t channel_layout;
|
||||||
int channels;
|
int channels;
|
||||||
|
int bit_rate;
|
||||||
enum AVSampleFormat sample_format;
|
enum AVSampleFormat sample_format;
|
||||||
bool wavheader;
|
bool wavheader;
|
||||||
bool icy;
|
bool icy;
|
||||||
|
@ -262,6 +263,11 @@ init_settings(struct settings_ctx *settings, enum transcode_profile profile, str
|
||||||
settings->channel_layout = av_get_default_channel_layout(quality->channels);
|
settings->channel_layout = av_get_default_channel_layout(quality->channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (quality && quality->bit_rate)
|
||||||
|
{
|
||||||
|
settings->bit_rate = quality->bit_rate;
|
||||||
|
}
|
||||||
|
|
||||||
if (quality && quality->bits_per_sample && (quality->bits_per_sample != 8 * av_get_bytes_per_sample(settings->sample_format)))
|
if (quality && quality->bits_per_sample && (quality->bits_per_sample != 8 * av_get_bytes_per_sample(settings->sample_format)))
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_XCODE, "Bug! Mismatch between profile and media quality\n");
|
DPRINTF(E_LOG, L_XCODE, "Bug! Mismatch between profile and media quality\n");
|
||||||
|
@ -281,6 +287,7 @@ stream_settings_set(struct stream_ctx *s, struct settings_ctx *settings, enum AV
|
||||||
s->codec->channels = settings->channels;
|
s->codec->channels = settings->channels;
|
||||||
s->codec->sample_fmt = settings->sample_format;
|
s->codec->sample_fmt = settings->sample_format;
|
||||||
s->codec->time_base = (AVRational){1, settings->sample_rate};
|
s->codec->time_base = (AVRational){1, settings->sample_rate};
|
||||||
|
s->codec->bit_rate = settings->bit_rate;
|
||||||
}
|
}
|
||||||
else if (type == AVMEDIA_TYPE_VIDEO)
|
else if (type == AVMEDIA_TYPE_VIDEO)
|
||||||
{
|
{
|
||||||
|
@ -731,7 +738,7 @@ open_decoder(unsigned int *stream_index, struct decode_ctx *ctx, enum AVMediaTyp
|
||||||
if ((*stream_index < 0) || (!decoder))
|
if ((*stream_index < 0) || (!decoder))
|
||||||
{
|
{
|
||||||
if (!ctx->settings.silent)
|
if (!ctx->settings.silent)
|
||||||
DPRINTF(E_LOG, L_XCODE, "No stream data or decoder for stream #%d\n", *stream_index);
|
DPRINTF(E_LOG, L_XCODE, "No stream data or decoder for stream #%d\n", *stream_index);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue