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