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
f12fa7e2
Commit
f12fa7e2
authored
Nov 08, 2016
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
output/shout: migrate from class Error to C++ exceptions
parent
96f8f1da
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
99 additions
and
174 deletions
+99
-174
ShoutOutputPlugin.cxx
src/output/plugins/ShoutOutputPlugin.cxx
+99
-174
No files found.
src/output/plugins/ShoutOutputPlugin.cxx
View file @
f12fa7e2
...
@@ -24,10 +24,8 @@
...
@@ -24,10 +24,8 @@
#include "encoder/EncoderInterface.hxx"
#include "encoder/EncoderInterface.hxx"
#include "encoder/EncoderPlugin.hxx"
#include "encoder/EncoderPlugin.hxx"
#include "encoder/EncoderList.hxx"
#include "encoder/EncoderList.hxx"
#include "config/ConfigError.hxx"
#include "util/RuntimeError.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "util/Domain.hxx"
#include "system/FatalError.hxx"
#include "Log.hxx"
#include "Log.hxx"
#include <shout/shout.h>
#include <shout/shout.h>
...
@@ -57,18 +55,9 @@ struct ShoutOutput final {
...
@@ -57,18 +55,9 @@ struct ShoutOutput final {
uint8_t
buffer
[
32768
];
uint8_t
buffer
[
32768
];
ShoutOutput
()
explicit
ShoutOutput
(
const
ConfigBlock
&
block
);
:
base
(
shout_output_plugin
),
shout_conn
(
shout_new
()),
shout_meta
(
shout_metadata_new
())
{}
~
ShoutOutput
();
~
ShoutOutput
();
bool
Initialize
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
return
base
.
Configure
(
block
,
error
);
}
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
static
ShoutOutput
*
Create
(
const
ConfigBlock
&
block
,
Error
&
error
);
static
ShoutOutput
*
Create
(
const
ConfigBlock
&
block
,
Error
&
error
);
bool
Open
(
AudioFormat
&
audio_format
,
Error
&
error
);
bool
Open
(
AudioFormat
&
audio_format
,
Error
&
error
);
...
@@ -85,18 +74,16 @@ static int shout_init_count;
...
@@ -85,18 +74,16 @@ static int shout_init_count;
static
constexpr
Domain
shout_output_domain
(
"shout_output"
);
static
constexpr
Domain
shout_output_domain
(
"shout_output"
);
ShoutOutput
::~
ShoutOutput
()
gcc_pure
static
const
char
*
require_block_string
(
const
ConfigBlock
&
block
,
const
char
*
name
)
{
{
if
(
shout_meta
!=
nullptr
)
const
char
*
value
=
block
.
GetBlockValue
(
name
);
shout_metadata_free
(
shout_meta
);
if
(
value
==
nullptr
)
if
(
shout_conn
!=
nullptr
)
throw
FormatRuntimeError
(
"no
\"
%s
\"
defined for shout device defined "
shout_free
(
shout_conn
);
"at line %d
\n
"
,
name
,
block
.
line
);
shout_init_count
--
;
if
(
shout_init_count
==
0
)
shout_shutdown
();
delete
prepared_encoder
;
return
value
;
}
}
static
const
EncoderPlugin
*
static
const
EncoderPlugin
*
...
@@ -110,36 +97,20 @@ shout_encoder_plugin_get(const char *name)
...
@@ -110,36 +97,20 @@ shout_encoder_plugin_get(const char *name)
return
encoder_plugin_get
(
name
);
return
encoder_plugin_get
(
name
);
}
}
gcc_pure
ShoutOutput
::
ShoutOutput
(
const
ConfigBlock
&
block
)
static
const
char
*
:
base
(
shout_output_plugin
,
block
),
require_block_string
(
const
ConfigBlock
&
block
,
const
char
*
name
)
shout_conn
(
shout_new
()),
shout_meta
(
shout_metadata_new
())
{
{
const
char
*
value
=
block
.
GetBlockValue
(
name
);
if
(
value
==
nullptr
)
FormatFatalError
(
"no
\"
%s
\"
defined for shout device defined "
"at line %d
\n
"
,
name
,
block
.
line
);
return
value
;
}
inline
bool
ShoutOutput
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
const
AudioFormat
audio_format
=
base
.
config_audio_format
;
const
AudioFormat
audio_format
=
base
.
config_audio_format
;
if
(
!
audio_format
.
IsFullyDefined
())
{
if
(
!
audio_format
.
IsFullyDefined
())
error
.
Set
(
config_domain
,
throw
std
::
runtime_error
(
"Need full audio format specification"
);
"Need full audio format specification"
);
return
false
;
}
const
char
*
host
=
require_block_string
(
block
,
"host"
);
const
char
*
host
=
require_block_string
(
block
,
"host"
);
const
char
*
mount
=
require_block_string
(
block
,
"mount"
);
const
char
*
mount
=
require_block_string
(
block
,
"mount"
);
unsigned
port
=
block
.
GetBlockValue
(
"port"
,
0u
);
unsigned
port
=
block
.
GetBlockValue
(
"port"
,
0u
);
if
(
port
==
0
)
{
if
(
port
==
0
)
error
.
Set
(
config_domain
,
"shout port must be configured"
);
throw
std
::
runtime_error
(
"shout port must be configured"
);
return
false
;
}
const
char
*
passwd
=
require_block_string
(
block
,
"password"
);
const
char
*
passwd
=
require_block_string
(
block
,
"password"
);
const
char
*
name
=
require_block_string
(
block
,
"name"
);
const
char
*
name
=
require_block_string
(
block
,
"name"
);
...
@@ -153,48 +124,33 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error)
...
@@ -153,48 +124,33 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error)
char
*
test
;
char
*
test
;
quality
=
strtod
(
value
,
&
test
);
quality
=
strtod
(
value
,
&
test
);
if
(
*
test
!=
'\0'
||
quality
<
-
1.0
||
quality
>
10.0
)
{
if
(
*
test
!=
'\0'
||
quality
<
-
1.0
||
quality
>
10.0
)
error
.
Format
(
config_domain
,
throw
FormatRuntimeError
(
"shout quality
\"
%s
\"
is not a number in the "
"shout quality
\"
%s
\"
is not a number in the "
"range -1 to 10"
,
"range -1 to 10"
,
value
);
value
);
return
false
;
}
if
(
block
.
GetBlockValue
(
"bitrate"
)
!=
nullptr
)
{
if
(
block
.
GetBlockValue
(
"bitrate"
)
!=
nullptr
)
error
.
Set
(
config_domain
,
throw
std
::
runtime_error
(
"quality and bitrate are "
"quality and bitrate are "
"both defined"
);
"both defined"
);
return
false
;
}
}
else
{
}
else
{
value
=
block
.
GetBlockValue
(
"bitrate"
);
value
=
block
.
GetBlockValue
(
"bitrate"
);
if
(
value
==
nullptr
)
{
if
(
value
==
nullptr
)
error
.
Set
(
config_domain
,
throw
std
::
runtime_error
(
"neither bitrate nor quality defined"
);
"neither bitrate nor quality defined"
);
return
false
;
}
char
*
test
;
char
*
test
;
bitrate
=
strtol
(
value
,
&
test
,
10
);
bitrate
=
strtol
(
value
,
&
test
,
10
);
if
(
*
test
!=
'\0'
||
bitrate
<=
0
)
{
if
(
*
test
!=
'\0'
||
bitrate
<=
0
)
error
.
Set
(
config_domain
,
throw
std
::
runtime_error
(
"bitrate must be a positive integer"
);
"bitrate must be a positive integer"
);
return
false
;
}
}
}
const
char
*
encoding
=
block
.
GetBlockValue
(
"encoder"
,
nullptr
);
const
char
*
encoding
=
block
.
GetBlockValue
(
"encoder"
,
nullptr
);
if
(
encoding
==
nullptr
)
if
(
encoding
==
nullptr
)
encoding
=
block
.
GetBlockValue
(
"encoding"
,
"vorbis"
);
encoding
=
block
.
GetBlockValue
(
"encoding"
,
"vorbis"
);
const
auto
encoder_plugin
=
shout_encoder_plugin_get
(
encoding
);
const
auto
encoder_plugin
=
shout_encoder_plugin_get
(
encoding
);
if
(
encoder_plugin
==
nullptr
)
{
if
(
encoder_plugin
==
nullptr
)
error
.
Format
(
config_domain
,
throw
FormatRuntimeError
(
"couldn't find shout encoder plugin
\"
%s
\"
"
,
"couldn't find shout encoder plugin
\"
%s
\"
"
,
encoding
);
encoding
);
return
false
;
}
prepared_encoder
=
encoder_init
(
*
encoder_plugin
,
block
);
prepared_encoder
=
encoder_init
(
*
encoder_plugin
,
block
);
...
@@ -208,24 +164,19 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error)
...
@@ -208,24 +164,19 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error)
value
=
block
.
GetBlockValue
(
"protocol"
);
value
=
block
.
GetBlockValue
(
"protocol"
);
if
(
value
!=
nullptr
)
{
if
(
value
!=
nullptr
)
{
if
(
0
==
strcmp
(
value
,
"shoutcast"
)
&&
if
(
0
==
strcmp
(
value
,
"shoutcast"
)
&&
0
!=
strcmp
(
encoding
,
"mp3"
))
{
0
!=
strcmp
(
encoding
,
"mp3"
))
error
.
Format
(
config_domain
,
throw
FormatRuntimeError
(
"you cannot stream
\"
%s
\"
to shoutcast, use mp3"
,
"you cannot stream
\"
%s
\"
to shoutcast, use mp3"
,
encoding
);
encoding
);
else
if
(
0
==
strcmp
(
value
,
"shoutcast"
))
return
false
;
}
else
if
(
0
==
strcmp
(
value
,
"shoutcast"
))
protocol
=
SHOUT_PROTOCOL_ICY
;
protocol
=
SHOUT_PROTOCOL_ICY
;
else
if
(
0
==
strcmp
(
value
,
"icecast1"
))
else
if
(
0
==
strcmp
(
value
,
"icecast1"
))
protocol
=
SHOUT_PROTOCOL_XAUDIOCAST
;
protocol
=
SHOUT_PROTOCOL_XAUDIOCAST
;
else
if
(
0
==
strcmp
(
value
,
"icecast2"
))
else
if
(
0
==
strcmp
(
value
,
"icecast2"
))
protocol
=
SHOUT_PROTOCOL_HTTP
;
protocol
=
SHOUT_PROTOCOL_HTTP
;
else
{
else
error
.
Format
(
config_domain
,
throw
FormatRuntimeError
(
"shout protocol
\"
%s
\"
is not
\"
shoutcast
\"
or "
"shout protocol
\"
%s
\"
is not
\"
shoutcast
\"
or "
"
\"
icecast1
\"
or
\"
icecast2
\"
"
,
"
\"
icecast1
\"
or
\"
icecast2
\"
"
,
value
);
value
);
return
false
;
}
}
else
{
}
else
{
protocol
=
SHOUT_PROTOCOL_HTTP
;
protocol
=
SHOUT_PROTOCOL_HTTP
;
}
}
...
@@ -240,31 +191,23 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error)
...
@@ -240,31 +191,23 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error)
shout_set_format
(
shout_conn
,
shout_format
)
shout_set_format
(
shout_conn
,
shout_format
)
!=
SHOUTERR_SUCCESS
||
!=
SHOUTERR_SUCCESS
||
shout_set_protocol
(
shout_conn
,
protocol
)
!=
SHOUTERR_SUCCESS
||
shout_set_protocol
(
shout_conn
,
protocol
)
!=
SHOUTERR_SUCCESS
||
shout_set_agent
(
shout_conn
,
"MPD"
)
!=
SHOUTERR_SUCCESS
)
{
shout_set_agent
(
shout_conn
,
"MPD"
)
!=
SHOUTERR_SUCCESS
)
error
.
Set
(
shout_output_domain
,
shout_get_error
(
shout_conn
));
throw
std
::
runtime_error
(
shout_get_error
(
shout_conn
));
return
false
;
}
/* optional paramters */
/* optional paramters */
timeout
=
block
.
GetBlockValue
(
"timeout"
,
DEFAULT_CONN_TIMEOUT
);
timeout
=
block
.
GetBlockValue
(
"timeout"
,
DEFAULT_CONN_TIMEOUT
);
value
=
block
.
GetBlockValue
(
"genre"
);
value
=
block
.
GetBlockValue
(
"genre"
);
if
(
value
!=
nullptr
&&
shout_set_genre
(
shout_conn
,
value
))
{
if
(
value
!=
nullptr
&&
shout_set_genre
(
shout_conn
,
value
))
error
.
Set
(
shout_output_domain
,
shout_get_error
(
shout_conn
));
throw
std
::
runtime_error
(
shout_get_error
(
shout_conn
));
return
false
;
}
value
=
block
.
GetBlockValue
(
"description"
);
value
=
block
.
GetBlockValue
(
"description"
);
if
(
value
!=
nullptr
&&
shout_set_description
(
shout_conn
,
value
))
{
if
(
value
!=
nullptr
&&
shout_set_description
(
shout_conn
,
value
))
error
.
Set
(
shout_output_domain
,
shout_get_error
(
shout_conn
));
throw
std
::
runtime_error
(
shout_get_error
(
shout_conn
));
return
false
;
}
value
=
block
.
GetBlockValue
(
"url"
);
value
=
block
.
GetBlockValue
(
"url"
);
if
(
value
!=
nullptr
&&
shout_set_url
(
shout_conn
,
value
))
{
if
(
value
!=
nullptr
&&
shout_set_url
(
shout_conn
,
value
))
error
.
Set
(
shout_output_domain
,
shout_get_error
(
shout_conn
));
throw
std
::
runtime_error
(
shout_get_error
(
shout_conn
));
return
false
;
}
{
{
char
temp
[
11
];
char
temp
[
11
];
...
@@ -286,39 +229,35 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error)
...
@@ -286,39 +229,35 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error)
temp
);
temp
);
}
}
}
}
}
return
true
;
ShoutOutput
::~
ShoutOutput
()
{
if
(
shout_meta
!=
nullptr
)
shout_metadata_free
(
shout_meta
);
if
(
shout_conn
!=
nullptr
)
shout_free
(
shout_conn
);
shout_init_count
--
;
if
(
shout_init_count
==
0
)
shout_shutdown
();
delete
prepared_encoder
;
}
}
ShoutOutput
*
ShoutOutput
*
ShoutOutput
::
Create
(
const
ConfigBlock
&
block
,
Error
&
error
)
ShoutOutput
::
Create
(
const
ConfigBlock
&
block
,
Error
&
)
{
{
if
(
shout_init_count
==
0
)
if
(
shout_init_count
==
0
)
shout_init
();
shout_init
();
shout_init_count
++
;
shout_init_count
++
;
ShoutOutput
*
sd
=
new
ShoutOutput
();
return
new
ShoutOutput
(
block
);
if
(
!
sd
->
Initialize
(
block
,
error
))
{
delete
sd
;
return
nullptr
;
}
try
{
if
(
!
sd
->
Configure
(
block
,
error
))
{
delete
sd
;
return
nullptr
;
}
}
catch
(...)
{
delete
sd
;
throw
;
}
return
sd
;
}
}
static
bool
static
void
handle_shout_error
(
ShoutOutput
*
sd
,
int
err
,
Error
&
error
)
handle_shout_error
(
ShoutOutput
*
sd
,
int
err
)
{
{
switch
(
err
)
{
switch
(
err
)
{
case
SHOUTERR_SUCCESS
:
case
SHOUTERR_SUCCESS
:
...
@@ -326,27 +265,21 @@ handle_shout_error(ShoutOutput *sd, int err, Error &error)
...
@@ -326,27 +265,21 @@ handle_shout_error(ShoutOutput *sd, int err, Error &error)
case
SHOUTERR_UNCONNECTED
:
case
SHOUTERR_UNCONNECTED
:
case
SHOUTERR_SOCKET
:
case
SHOUTERR_SOCKET
:
error
.
Format
(
shout_output_domain
,
err
,
throw
FormatRuntimeError
(
"Lost shout connection to %s:%i: %s"
,
"Lost shout connection to %s:%i: %s"
,
shout_get_host
(
sd
->
shout_conn
),
shout_get_host
(
sd
->
shout_conn
),
shout_get_port
(
sd
->
shout_conn
),
shout_get_port
(
sd
->
shout_conn
),
shout_get_error
(
sd
->
shout_conn
));
shout_get_error
(
sd
->
shout_conn
));
return
false
;
default
:
default
:
error
.
Format
(
shout_output_domain
,
err
,
throw
FormatRuntimeError
(
"connection to %s:%i error: %s"
,
"connection to %s:%i error: %s"
,
shout_get_host
(
sd
->
shout_conn
),
shout_get_host
(
sd
->
shout_conn
),
shout_get_port
(
sd
->
shout_conn
),
shout_get_port
(
sd
->
shout_conn
),
shout_get_error
(
sd
->
shout_conn
));
shout_get_error
(
sd
->
shout_conn
));
return
false
;
}
}
return
true
;
}
}
static
bool
static
bool
write_page
(
ShoutOutput
*
sd
,
Error
&
error
)
write_page
(
ShoutOutput
*
sd
)
{
{
assert
(
sd
->
encoder
!=
nullptr
);
assert
(
sd
->
encoder
!=
nullptr
);
...
@@ -357,8 +290,7 @@ write_page(ShoutOutput *sd, Error &error)
...
@@ -357,8 +290,7 @@ write_page(ShoutOutput *sd, Error &error)
return
true
;
return
true
;
int
err
=
shout_send
(
sd
->
shout_conn
,
sd
->
buffer
,
nbytes
);
int
err
=
shout_send
(
sd
->
shout_conn
,
sd
->
buffer
,
nbytes
);
if
(
!
handle_shout_error
(
sd
,
err
,
error
))
handle_shout_error
(
sd
,
err
);
return
false
;
}
}
return
true
;
return
true
;
...
@@ -370,7 +302,7 @@ ShoutOutput::Close()
...
@@ -370,7 +302,7 @@ ShoutOutput::Close()
if
(
encoder
!=
nullptr
)
{
if
(
encoder
!=
nullptr
)
{
try
{
try
{
encoder
->
End
();
encoder
->
End
();
write_page
(
this
,
IgnoreError
()
);
write_page
(
this
);
}
catch
(
const
std
::
runtime_error
&
)
{
}
catch
(
const
std
::
runtime_error
&
)
{
/* ignore */
/* ignore */
}
}
...
@@ -392,39 +324,32 @@ ShoutOutput::Cancel()
...
@@ -392,39 +324,32 @@ ShoutOutput::Cancel()
/* needs to be implemented for shout */
/* needs to be implemented for shout */
}
}
static
bool
static
void
shout_connect
(
ShoutOutput
*
sd
,
Error
&
error
)
shout_connect
(
ShoutOutput
*
sd
)
{
{
switch
(
shout_open
(
sd
->
shout_conn
))
{
switch
(
shout_open
(
sd
->
shout_conn
))
{
case
SHOUTERR_SUCCESS
:
case
SHOUTERR_SUCCESS
:
case
SHOUTERR_CONNECTED
:
case
SHOUTERR_CONNECTED
:
return
true
;
break
;
default
:
default
:
error
.
Format
(
shout_output_domain
,
throw
FormatRuntimeError
(
"problem opening connection to shout server %s:%i: %s"
,
"problem opening connection to shout server %s:%i: %s"
,
shout_get_host
(
sd
->
shout_conn
),
shout_get_host
(
sd
->
shout_conn
),
shout_get_port
(
sd
->
shout_conn
),
shout_get_port
(
sd
->
shout_conn
),
shout_get_error
(
sd
->
shout_conn
));
shout_get_error
(
sd
->
shout_conn
));
return
false
;
}
}
}
}
bool
bool
ShoutOutput
::
Open
(
AudioFormat
&
audio_format
,
Error
&
error
)
ShoutOutput
::
Open
(
AudioFormat
&
audio_format
,
Error
&
)
{
{
if
(
!
shout_connect
(
this
,
error
))
shout_connect
(
this
);
return
false
;
try
{
try
{
encoder
=
prepared_encoder
->
Open
(
audio_format
);
encoder
=
prepared_encoder
->
Open
(
audio_format
);
try
{
try
{
if
(
!
write_page
(
this
,
error
))
{
write_page
(
this
);
delete
encoder
;
shout_close
(
shout_conn
);
return
false
;
}
}
catch
(
const
std
::
runtime_error
&
)
{
}
catch
(
const
std
::
runtime_error
&
)
{
delete
encoder
;
delete
encoder
;
throw
;
throw
;
...
@@ -448,12 +373,11 @@ ShoutOutput::Delay() const
...
@@ -448,12 +373,11 @@ ShoutOutput::Delay() const
}
}
size_t
size_t
ShoutOutput
::
Play
(
const
void
*
chunk
,
size_t
size
,
Error
&
error
)
ShoutOutput
::
Play
(
const
void
*
chunk
,
size_t
size
,
Error
&
)
{
{
encoder
->
Write
(
chunk
,
size
);
encoder
->
Write
(
chunk
,
size
);
return
write_page
(
this
,
error
)
write_page
(
this
);
?
size
return
size
;
:
0
;
}
}
bool
bool
...
@@ -461,7 +385,14 @@ ShoutOutput::Pause()
...
@@ -461,7 +385,14 @@ ShoutOutput::Pause()
{
{
static
char
silence
[
1020
];
static
char
silence
[
1020
];
return
Play
(
silence
,
sizeof
(
silence
),
IgnoreError
());
try
{
encoder
->
Write
(
silence
,
sizeof
(
silence
));
write_page
(
this
);
}
catch
(
const
std
::
runtime_error
&
)
{
return
false
;
}
return
true
;
}
}
static
void
static
void
...
@@ -497,13 +428,7 @@ ShoutOutput::SendTag(const Tag &tag)
...
@@ -497,13 +428,7 @@ ShoutOutput::SendTag(const Tag &tag)
/* encoder plugin supports stream tags */
/* encoder plugin supports stream tags */
encoder
->
PreTag
();
encoder
->
PreTag
();
write_page
(
this
);
Error
error
;
if
(
!
write_page
(
this
,
error
))
{
LogError
(
error
);
return
;
}
encoder
->
SendTag
(
tag
);
encoder
->
SendTag
(
tag
);
}
else
{
}
else
{
/* no stream tag support: fall back to icy-metadata */
/* no stream tag support: fall back to icy-metadata */
...
@@ -518,7 +443,7 @@ ShoutOutput::SendTag(const Tag &tag)
...
@@ -518,7 +443,7 @@ ShoutOutput::SendTag(const Tag &tag)
}
}
}
}
write_page
(
this
,
IgnoreError
()
);
write_page
(
this
);
}
}
typedef
AudioOutputWrapper
<
ShoutOutput
>
Wrapper
;
typedef
AudioOutputWrapper
<
ShoutOutput
>
Wrapper
;
...
...
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