Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
e4eb5b79
Commit
e4eb5b79
authored
3 years ago
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
output/shout: move shout_new() call to Enable()
Don't allocate any memory until the output is really enabled.
parent
1cfea20b
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
164 additions
and
96 deletions
+164
-96
ShoutOutputPlugin.cxx
src/output/plugins/ShoutOutputPlugin.cxx
+164
-96
No files found.
src/output/plugins/ShoutOutputPlugin.cxx
View file @
e4eb5b79
...
...
@@ -36,10 +36,39 @@
#include <stdio.h>
class
ShoutConfig
{
const
char
*
const
host
;
const
char
*
const
mount
;
const
char
*
const
user
,
*
const
passwd
;
const
char
*
const
name
;
const
char
*
const
genre
,
*
const
description
;
const
char
*
const
url
;
const
char
*
const
quality
,
*
const
bitrate
;
const
unsigned
port
;
const
unsigned
format
;
const
unsigned
protocol
;
#ifdef SHOUT_TLS
const
int
tls
;
#endif
const
bool
is_public
;
public
:
ShoutConfig
(
const
ConfigBlock
&
block
,
const
char
*
mime_type
);
void
Setup
(
shout_t
*
connection
)
const
;
};
struct
ShoutOutput
final
:
AudioOutput
{
shout_t
*
shout_conn
;
std
::
unique_ptr
<
PreparedEncoder
>
prepared_encoder
;
const
ShoutConfig
config
;
Encoder
*
encoder
;
uint8_t
buffer
[
32768
];
...
...
@@ -53,6 +82,9 @@ struct ShoutOutput final : AudioOutput {
static
AudioOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
void
Enable
()
override
;
void
Disable
()
noexcept
override
;
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
...
...
@@ -91,118 +123,96 @@ ShoutSetAudioInfo(shout_t *shout_conn, const AudioFormat &audio_format)
StringFormat
<
11
>
(
"%u"
,
audio_format
.
sample_rate
));
}
ShoutOutput
::
ShoutOutput
(
const
ConfigBlock
&
block
)
:
AudioOutput
(
FLAG_PAUSE
|
FLAG_NEED_FULLY_DEFINED_AUDIO_FORMAT
),
shout_conn
(
shout_new
()),
prepared_encoder
(
CreateConfiguredEncoder
(
block
,
true
))
{
const
char
*
host
=
require_block_string
(
block
,
"host"
);
const
char
*
mount
=
require_block_string
(
block
,
"mount"
);
unsigned
port
=
block
.
GetBlockValue
(
"port"
,
0U
);
if
(
port
==
0
)
throw
std
::
runtime_error
(
"shout port must be configured"
);
const
char
*
passwd
=
require_block_string
(
block
,
"password"
);
const
char
*
name
=
require_block_string
(
block
,
"name"
);
bool
is_public
=
block
.
GetBlockValue
(
"public"
,
false
);
#ifdef SHOUT_TLS
const
char
*
user
=
block
.
GetBlockValue
(
"user"
,
"source"
);
static
int
ParseShoutTls
(
const
char
*
value
)
{
if
(
value
==
nullptr
)
return
SHOUT_TLS_DISABLED
;
if
(
StringIsEqual
(
value
,
"disabled"
))
return
SHOUT_TLS_DISABLED
;
else
if
(
StringIsEqual
(
value
,
"auto"
))
return
SHOUT_TLS_AUTO
;
else
if
(
StringIsEqual
(
value
,
"auto_no_plain"
))
return
SHOUT_TLS_AUTO_NO_PLAIN
;
else
if
(
StringIsEqual
(
value
,
"rfc2818"
))
return
SHOUT_TLS_RFC2818
;
else
if
(
StringIsEqual
(
value
,
"rfc2817"
))
return
SHOUT_TLS_RFC2817
;
else
throw
FormatRuntimeError
(
"invalid shout TLS option
\"
%s
\"
"
,
value
);
}
const
char
*
const
mime_type
=
prepared_encoder
->
GetMimeType
();
#endif
unsigned
shout_format
;
static
unsigned
ParseShoutFormat
(
const
char
*
mime_type
)
{
if
(
StringIsEqual
(
mime_type
,
"audio/mpeg"
))
shout_format
=
SHOUT_FORMAT_MP3
;
return
SHOUT_FORMAT_MP3
;
else
shout_format
=
SHOUT_FORMAT_OGG
;
return
SHOUT_FORMAT_OGG
;
}
static
unsigned
ParseShoutProtocol
(
const
char
*
value
,
const
char
*
mime_type
)
{
if
(
value
==
nullptr
)
return
SHOUT_PROTOCOL_HTTP
;
unsigned
protocol
;
const
char
*
value
=
block
.
GetBlockValue
(
"protocol"
);
if
(
value
!=
nullptr
)
{
if
(
StringIsEqual
(
value
,
"shoutcast"
)
&&
!
StringIsEqual
(
mime_type
,
"audio/mpeg"
))
if
(
StringIsEqual
(
value
,
"shoutcast"
))
{
if
(
!
StringIsEqual
(
mime_type
,
"audio/mpeg"
))
throw
FormatRuntimeError
(
"you cannot stream
\"
%s
\"
to shoutcast, use mp3"
,
mime_type
);
else
if
(
StringIsEqual
(
value
,
"shoutcast"
))
protocol
=
SHOUT_PROTOCOL_ICY
;
else
if
(
StringIsEqual
(
value
,
"icecast1"
))
protocol
=
SHOUT_PROTOCOL_XAUDIOCAST
;
else
if
(
StringIsEqual
(
value
,
"icecast2"
))
protocol
=
SHOUT_PROTOCOL_HTTP
;
else
throw
FormatRuntimeError
(
"shout protocol
\"
%s
\"
is not
\"
shoutcast
\"
or "
"
\"
icecast1
\"
or
\"
icecast2
\"
"
,
value
);
}
else
{
protocol
=
SHOUT_PROTOCOL_HTTP
;
}
#ifdef SHOUT_TLS
unsigned
tls
;
value
=
block
.
GetBlockValue
(
"tls"
);
if
(
value
!=
nullptr
)
{
if
(
StringIsEqual
(
value
,
"disabled"
))
tls
=
SHOUT_TLS_DISABLED
;
else
if
(
StringIsEqual
(
value
,
"auto"
))
tls
=
SHOUT_TLS_AUTO
;
else
if
(
StringIsEqual
(
value
,
"auto_no_plain"
))
tls
=
SHOUT_TLS_AUTO_NO_PLAIN
;
else
if
(
StringIsEqual
(
value
,
"rfc2818"
))
tls
=
SHOUT_TLS_RFC2818
;
else
if
(
StringIsEqual
(
value
,
"rfc2817"
))
tls
=
SHOUT_TLS_RFC2817
;
else
throw
FormatRuntimeError
(
"invalid shout TLS option
\"
%s
\"
"
,
value
);
}
else
{
tls
=
SHOUT_TLS_DISABLED
;
}
#endif
return
SHOUT_PROTOCOL_ICY
;
}
else
if
(
StringIsEqual
(
value
,
"icecast1"
))
return
SHOUT_PROTOCOL_XAUDIOCAST
;
else
if
(
StringIsEqual
(
value
,
"icecast2"
))
return
SHOUT_PROTOCOL_HTTP
;
else
throw
FormatRuntimeError
(
"shout protocol
\"
%s
\"
is not
\"
shoutcast
\"
or "
"
\"
icecast1
\"
or
\"
icecast2
\"
"
,
value
);
}
if
(
shout_set_host
(
shout_conn
,
host
)
!=
SHOUTERR_SUCCESS
||
shout_set_port
(
shout_conn
,
port
)
!=
SHOUTERR_SUCCESS
||
shout_set_password
(
shout_conn
,
passwd
)
!=
SHOUTERR_SUCCESS
||
shout_set_mount
(
shout_conn
,
mount
)
!=
SHOUTERR_SUCCESS
||
shout_set_name
(
shout_conn
,
name
)
!=
SHOUTERR_SUCCESS
||
shout_set_user
(
shout_conn
,
user
)
!=
SHOUTERR_SUCCESS
||
shout_set_public
(
shout_conn
,
is_public
)
!=
SHOUTERR_SUCCESS
||
shout_set_format
(
shout_conn
,
shout_format
)
!=
SHOUTERR_SUCCESS
||
shout_set_protocol
(
shout_conn
,
protocol
)
!=
SHOUTERR_SUCCESS
||
inline
ShoutConfig
::
ShoutConfig
(
const
ConfigBlock
&
block
,
const
char
*
mime_type
)
:
host
(
require_block_string
(
block
,
"host"
)),
mount
(
require_block_string
(
block
,
"mount"
)),
user
(
block
.
GetBlockValue
(
"user"
,
"source"
)),
passwd
(
require_block_string
(
block
,
"password"
)),
name
(
require_block_string
(
block
,
"name"
)),
genre
(
block
.
GetBlockValue
(
"genre"
)),
description
(
block
.
GetBlockValue
(
"description"
)),
url
(
block
.
GetBlockValue
(
"url"
)),
quality
(
block
.
GetBlockValue
(
"quality"
)),
bitrate
(
block
.
GetBlockValue
(
"bitrate"
)),
port
(
block
.
GetBlockValue
(
"port"
,
0U
)),
format
(
ParseShoutFormat
(
mime_type
)),
protocol
(
ParseShoutProtocol
(
block
.
GetBlockValue
(
"protocol"
),
mime_type
)),
#ifdef SHOUT_TLS
shout_set_tls
(
shout_conn
,
tls
)
!=
SHOUTERR_SUCCESS
||
tls
(
ParseShoutTls
(
block
.
GetBlockValue
(
"tls"
))),
#endif
shout_set_agent
(
shout_conn
,
"MPD"
)
!=
SHOUTERR_SUCCESS
)
throw
std
::
runtime_error
(
shout_get_error
(
shout_conn
));
/* optional paramters */
value
=
block
.
GetBlockValue
(
"genre"
);
if
(
value
!=
nullptr
&&
shout_set_genre
(
shout_conn
,
value
))
throw
std
::
runtime_error
(
shout_get_error
(
shout_conn
));
value
=
block
.
GetBlockValue
(
"description"
);
if
(
value
!=
nullptr
&&
shout_set_description
(
shout_conn
,
value
))
throw
std
::
runtime_error
(
shout_get_error
(
shout_conn
));
value
=
block
.
GetBlockValue
(
"url"
);
if
(
value
!=
nullptr
&&
shout_set_url
(
shout_conn
,
value
))
throw
std
::
runtime_error
(
shout_get_error
(
shout_conn
));
value
=
block
.
GetBlockValue
(
"quality"
);
if
(
value
!=
nullptr
)
shout_set_audio_info
(
shout_conn
,
SHOUT_AI_QUALITY
,
value
);
is_public
(
block
.
GetBlockValue
(
"public"
,
false
))
{
if
(
port
==
0
)
throw
std
::
runtime_error
(
"shout port must be configured"
);
}
value
=
block
.
GetBlockValue
(
"bitrate"
);
if
(
value
!=
nullptr
)
shout_set_audio_info
(
shout_conn
,
SHOUT_AI_BITRATE
,
value
);
ShoutOutput
::
ShoutOutput
(
const
ConfigBlock
&
block
)
:
AudioOutput
(
FLAG_PAUSE
|
FLAG_NEED_FULLY_DEFINED_AUDIO_FORMAT
|
FLAG_ENABLE_DISABLE
),
prepared_encoder
(
CreateConfiguredEncoder
(
block
,
true
)),
config
(
block
,
prepared_encoder
->
GetMimeType
())
{
}
ShoutOutput
::~
ShoutOutput
()
{
if
(
shout_conn
!=
nullptr
)
shout_free
(
shout_conn
);
shout_init_count
--
;
if
(
shout_init_count
==
0
)
shout_shutdown
();
...
...
@@ -219,6 +229,64 @@ ShoutOutput::Create(EventLoop &, const ConfigBlock &block)
return
new
ShoutOutput
(
block
);
}
inline
void
ShoutConfig
::
Setup
(
shout_t
*
connection
)
const
{
if
(
shout_set_host
(
connection
,
host
)
!=
SHOUTERR_SUCCESS
||
shout_set_port
(
connection
,
port
)
!=
SHOUTERR_SUCCESS
||
shout_set_password
(
connection
,
passwd
)
!=
SHOUTERR_SUCCESS
||
shout_set_mount
(
connection
,
mount
)
!=
SHOUTERR_SUCCESS
||
shout_set_name
(
connection
,
name
)
!=
SHOUTERR_SUCCESS
||
shout_set_user
(
connection
,
user
)
!=
SHOUTERR_SUCCESS
||
shout_set_public
(
connection
,
is_public
)
!=
SHOUTERR_SUCCESS
||
shout_set_format
(
connection
,
format
)
!=
SHOUTERR_SUCCESS
||
shout_set_protocol
(
connection
,
protocol
)
!=
SHOUTERR_SUCCESS
||
#ifdef SHOUT_TLS
shout_set_tls
(
connection
,
tls
)
!=
SHOUTERR_SUCCESS
||
#endif
shout_set_agent
(
connection
,
"MPD"
)
!=
SHOUTERR_SUCCESS
)
throw
std
::
runtime_error
(
shout_get_error
(
connection
));
/* optional paramters */
if
(
genre
!=
nullptr
&&
shout_set_genre
(
connection
,
genre
))
throw
std
::
runtime_error
(
shout_get_error
(
connection
));
if
(
description
!=
nullptr
&&
shout_set_description
(
connection
,
description
))
throw
std
::
runtime_error
(
shout_get_error
(
connection
));
if
(
url
!=
nullptr
&&
shout_set_url
(
connection
,
url
))
throw
std
::
runtime_error
(
shout_get_error
(
connection
));
if
(
quality
!=
nullptr
)
shout_set_audio_info
(
connection
,
SHOUT_AI_QUALITY
,
quality
);
if
(
bitrate
!=
nullptr
)
shout_set_audio_info
(
connection
,
SHOUT_AI_BITRATE
,
bitrate
);
}
void
ShoutOutput
::
Enable
()
{
shout_conn
=
shout_new
();
if
(
shout_conn
==
nullptr
)
throw
std
::
bad_alloc
{};
try
{
config
.
Setup
(
shout_conn
);
}
catch
(...)
{
shout_free
(
shout_conn
);
throw
;
}
}
void
ShoutOutput
::
Disable
()
noexcept
{
shout_free
(
shout_conn
);
}
static
void
HandleShoutError
(
shout_t
*
shout_conn
,
int
err
)
{
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment