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
6ead9750
Commit
6ead9750
authored
Nov 02, 2016
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
output/pulse: migrate from class Error to C++ exceptions
parent
6532c7e0
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
100 additions
and
148 deletions
+100
-148
Error.cxx
src/lib/pulse/Error.cxx
+4
-5
Error.hxx
src/lib/pulse/Error.hxx
+4
-3
PulseOutputPlugin.cxx
src/output/plugins/PulseOutputPlugin.cxx
+92
-140
No files found.
src/lib/pulse/Error.cxx
View file @
6ead9750
...
...
@@ -19,15 +19,14 @@
#include "config.h"
#include "Error.hxx"
#include "Domain.hxx"
#include "util/Error.hxx"
#include "util/RuntimeError.hxx"
#include <pulse/context.h>
#include <pulse/error.h>
void
SetPulseError
(
Error
&
error
,
pa_context
*
context
,
const
char
*
prefix
)
std
::
runtime_error
MakePulseError
(
pa_context
*
context
,
const
char
*
prefix
)
{
const
int
e
=
pa_context_errno
(
context
);
error
.
Format
(
pulse_domain
,
e
,
"%s: %s"
,
prefix
,
pa_strerror
(
e
));
return
FormatRuntimeError
(
"%s: %s"
,
prefix
,
pa_strerror
(
e
));
}
src/lib/pulse/Error.hxx
View file @
6ead9750
...
...
@@ -20,10 +20,11 @@
#ifndef MPD_PULSE_ERROR_HXX
#define MPD_PULSE_ERROR_HXX
class
Error
;
#include <stdexcept>
struct
pa_context
;
void
SetPulseError
(
Error
&
error
,
pa_context
*
context
,
const
char
*
prefix
);
std
::
runtime_error
MakePulseError
(
pa_context
*
context
,
const
char
*
prefix
);
#endif
src/output/plugins/PulseOutputPlugin.cxx
View file @
6ead9750
...
...
@@ -27,7 +27,6 @@
#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
#include "mixer/plugins/PulseMixerPlugin.hxx"
#include "util/Error.hxx"
#include "Log.hxx"
#include <pulse/thread-mainloop.h>
...
...
@@ -62,8 +61,7 @@ class PulseOutput {
size_t
writable
;
PulseOutput
()
:
base
(
pulse_output_plugin
)
{}
explicit
PulseOutput
(
const
ConfigBlock
&
block
);
public
:
void
SetMixer
(
PulseMixer
&
_mixer
);
...
...
@@ -95,7 +93,6 @@ public:
gcc_const
static
bool
TestDefaultDevice
();
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
static
PulseOutput
*
Create
(
const
ConfigBlock
&
block
,
Error
&
error
);
bool
Enable
(
Error
&
error
);
...
...
@@ -113,18 +110,18 @@ private:
/**
* Attempt to connect asynchronously to the PulseAudio server.
*
*
@return true on success, false on error
*
Throws #std::runtime_error on error.
*/
bool
Connect
(
Error
&
error
);
void
Connect
(
);
/**
* Create, set up and connect a context.
*
* Caller must lock the main loop.
*
*
@return true on success, false on error
*
Throws #std::runtime_error on error.
*/
bool
SetupContext
(
Error
&
error
);
void
SetupContext
(
);
/**
* Frees and clears the context.
...
...
@@ -144,18 +141,18 @@ private:
*
* Caller must lock the main loop.
*
*
@return true on success, false on error
*
Throws #std::runtime_error on error.
*/
bool
WaitConnection
(
Error
&
error
);
void
WaitConnection
(
);
/**
* Create, set up and connect a context.
*
* Caller must lock the main loop.
*
*
@return true on success, false on error
*
Throws #std::runtime_error on error.
*/
bool
SetupStream
(
const
pa_sample_spec
&
ss
,
Error
&
error
);
void
SetupStream
(
const
pa_sample_spec
&
ss
);
/**
* Frees and clears the stream.
...
...
@@ -167,16 +164,28 @@ private:
* not. The mainloop must be locked before calling this
* function.
*
*
@return true on success, false on error
*
Throws #std::runtime_error on error.
*/
bool
WaitStream
(
Error
&
error
);
void
WaitStream
(
);
/**
* Sets cork mode on the stream.
*
* Throws #std::runtime_error on error.
*/
bool
StreamPause
(
bool
pause
,
Error
&
error
);
void
StreamPause
(
bool
pause
);
};
PulseOutput
::
PulseOutput
(
const
ConfigBlock
&
block
)
:
base
(
pulse_output_plugin
,
block
),
name
(
block
.
GetBlockValue
(
"name"
,
"mpd_pulse"
)),
server
(
block
.
GetBlockValue
(
"server"
)),
sink
(
block
.
GetBlockValue
(
"sink"
))
{
setenv
(
"PULSE_PROP_media.role"
,
"music"
,
true
);
setenv
(
"PULSE_PROP_application.icon_name"
,
"mpd"
,
true
);
}
struct
pa_threaded_mainloop
*
pulse_output_get_mainloop
(
PulseOutput
&
po
)
{
...
...
@@ -343,19 +352,15 @@ pulse_output_subscribe_cb(gcc_unused pa_context *context,
po
.
OnServerLayoutChanged
(
t
,
idx
);
}
inline
bool
PulseOutput
::
Connect
(
Error
&
error
)
inline
void
PulseOutput
::
Connect
()
{
assert
(
context
!=
nullptr
);
if
(
pa_context_connect
(
context
,
server
,
(
pa_context_flags_t
)
0
,
nullptr
)
<
0
)
{
SetPulseError
(
error
,
context
,
(
pa_context_flags_t
)
0
,
nullptr
)
<
0
)
throw
MakePulseError
(
context
,
"pa_context_connect() has failed"
);
return
false
;
}
return
true
;
}
void
...
...
@@ -386,72 +391,45 @@ PulseOutput::DeleteContext()
context
=
nullptr
;
}
bool
PulseOutput
::
SetupContext
(
Error
&
error
)
void
PulseOutput
::
SetupContext
()
{
assert
(
mainloop
!=
nullptr
);
context
=
pa_context_new
(
pa_threaded_mainloop_get_api
(
mainloop
),
MPD_PULSE_NAME
);
if
(
context
==
nullptr
)
{
error
.
Set
(
pulse_domain
,
"pa_context_new() has failed"
);
return
false
;
}
if
(
context
==
nullptr
)
throw
std
::
runtime_error
(
"pa_context_new() has failed"
);
pa_context_set_state_callback
(
context
,
pulse_output_context_state_cb
,
this
);
pa_context_set_subscribe_callback
(
context
,
pulse_output_subscribe_cb
,
this
);
if
(
!
Connect
(
error
))
{
try
{
Connect
();
}
catch
(...)
{
DeleteContext
();
return
false
;
throw
;
}
return
true
;
}
inline
bool
PulseOutput
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
if
(
!
base
.
Configure
(
block
,
error
))
return
false
;
name
=
block
.
GetBlockValue
(
"name"
,
"mpd_pulse"
);
server
=
block
.
GetBlockValue
(
"server"
);
sink
=
block
.
GetBlockValue
(
"sink"
);
return
true
;
}
PulseOutput
*
PulseOutput
::
Create
(
const
ConfigBlock
&
block
,
Error
&
error
)
PulseOutput
::
Create
(
const
ConfigBlock
&
block
,
gcc_unused
Error
&
error
)
{
setenv
(
"PULSE_PROP_media.role"
,
"music"
,
true
);
setenv
(
"PULSE_PROP_application.icon_name"
,
"mpd"
,
true
);
auto
*
po
=
new
PulseOutput
();
if
(
!
po
->
Configure
(
block
,
error
))
{
delete
po
;
return
nullptr
;
}
return
po
;
return
new
PulseOutput
(
block
);
}
inline
bool
PulseOutput
::
Enable
(
Error
&
error
)
PulseOutput
::
Enable
(
gcc_unused
Error
&
error
)
{
assert
(
mainloop
==
nullptr
);
/* create the libpulse mainloop and start the thread */
mainloop
=
pa_threaded_mainloop_new
();
if
(
mainloop
==
nullptr
)
{
error
.
Set
(
pulse_domain
,
"pa_threaded_mainloop_new() has failed"
);
return
false
;
}
if
(
mainloop
==
nullptr
)
throw
std
::
runtime_error
(
"pa_threaded_mainloop_new() has failed"
);
pa_threaded_mainloop_lock
(
mainloop
);
...
...
@@ -460,19 +438,19 @@ PulseOutput::Enable(Error &error)
pa_threaded_mainloop_free
(
mainloop
);
mainloop
=
nullptr
;
error
.
Set
(
pulse_domain
,
"pa_threaded_mainloop_start() has failed"
);
return
false
;
throw
std
::
runtime_error
(
"pa_threaded_mainloop_start() has failed"
);
}
/* create the libpulse context and connect it */
if
(
!
SetupContext
(
error
))
{
try
{
SetupContext
();
}
catch
(...)
{
pa_threaded_mainloop_unlock
(
mainloop
);
pa_threaded_mainloop_stop
(
mainloop
);
pa_threaded_mainloop_free
(
mainloop
);
mainloop
=
nullptr
;
return
false
;
throw
;
}
pa_threaded_mainloop_unlock
(
mainloop
);
...
...
@@ -492,30 +470,33 @@ PulseOutput::Disable()
mainloop
=
nullptr
;
}
bool
PulseOutput
::
WaitConnection
(
Error
&
error
)
void
PulseOutput
::
WaitConnection
()
{
assert
(
mainloop
!=
nullptr
);
pa_context_state_t
state
;
if
(
context
==
nullptr
&&
!
SetupContext
(
error
)
)
return
false
;
if
(
context
==
nullptr
)
SetupContext
()
;
while
(
true
)
{
state
=
pa_context_get_state
(
context
);
switch
(
state
)
{
case
PA_CONTEXT_READY
:
/* nothing to do */
return
true
;
return
;
case
PA_CONTEXT_UNCONNECTED
:
case
PA_CONTEXT_TERMINATED
:
case
PA_CONTEXT_FAILED
:
/* failure */
SetPulseError
(
error
,
context
,
"failed to connect"
);
{
auto
e
=
MakePulseError
(
context
,
"failed to connect"
);
DeleteContext
();
return
false
;
throw
e
;
}
case
PA_CONTEXT_CONNECTING
:
case
PA_CONTEXT_AUTHORIZING
:
...
...
@@ -602,8 +583,8 @@ pulse_output_stream_write_cb(gcc_unused pa_stream *stream, size_t nbytes,
return
po
.
OnStreamWrite
(
nbytes
);
}
inline
bool
PulseOutput
::
SetupStream
(
const
pa_sample_spec
&
ss
,
Error
&
error
)
inline
void
PulseOutput
::
SetupStream
(
const
pa_sample_spec
&
ss
)
{
assert
(
context
!=
nullptr
);
...
...
@@ -612,11 +593,9 @@ PulseOutput::SetupStream(const pa_sample_spec &ss, Error &error)
pa_channel_map_init_auto
(
&
chan_map
,
ss
.
channels
,
PA_CHANNEL_MAP_WAVEEX
);
stream
=
pa_stream_new
(
context
,
name
,
&
ss
,
&
chan_map
);
if
(
stream
==
nullptr
)
{
SetPulseError
(
error
,
context
,
if
(
stream
==
nullptr
)
throw
MakePulseError
(
context
,
"pa_stream_new() has failed"
);
return
false
;
}
pa_stream_set_suspended_callback
(
stream
,
pulse_output_stream_suspended_cb
,
...
...
@@ -626,12 +605,10 @@ PulseOutput::SetupStream(const pa_sample_spec &ss, Error &error)
pulse_output_stream_state_cb
,
this
);
pa_stream_set_write_callback
(
stream
,
pulse_output_stream_write_cb
,
this
);
return
true
;
}
inline
bool
PulseOutput
::
Open
(
AudioFormat
&
audio_format
,
Error
&
error
)
PulseOutput
::
Open
(
AudioFormat
&
audio_format
,
gcc_unused
Error
&
error
)
{
assert
(
mainloop
!=
nullptr
);
...
...
@@ -656,8 +633,7 @@ PulseOutput::Open(AudioFormat &audio_format, Error &error)
}
}
if
(
!
WaitConnection
(
error
))
return
false
;
WaitConnection
();
/* Use the sample formats that our version of PulseAudio and MPD
have in common, otherwise force MPD to send 16 bit */
...
...
@@ -688,8 +664,7 @@ PulseOutput::Open(AudioFormat &audio_format, Error &error)
/* create a stream .. */
if
(
!
SetupStream
(
ss
,
error
))
return
false
;
SetupStream
(
ss
);
/* .. and connect it (asynchronously) */
...
...
@@ -698,9 +673,8 @@ PulseOutput::Open(AudioFormat &audio_format, Error &error)
nullptr
,
nullptr
)
<
0
)
{
DeleteStream
();
SetPulseError
(
error
,
context
,
throw
MakePulseError
(
context
,
"pa_stream_connect_playback() has failed"
);
return
false
;
}
return
true
;
...
...
@@ -731,20 +705,19 @@ PulseOutput::Close()
DeleteContext
();
}
bool
PulseOutput
::
WaitStream
(
Error
&
error
)
void
PulseOutput
::
WaitStream
()
{
while
(
true
)
{
switch
(
pa_stream_get_state
(
stream
))
{
case
PA_STREAM_READY
:
return
true
;
return
;
case
PA_STREAM_FAILED
:
case
PA_STREAM_TERMINATED
:
case
PA_STREAM_UNCONNECTED
:
SetPulseError
(
error
,
context
,
throw
MakePulseError
(
context
,
"failed to connect the stream"
);
return
false
;
case
PA_STREAM_CREATING
:
pa_threaded_mainloop_wait
(
mainloop
);
...
...
@@ -753,8 +726,8 @@ PulseOutput::WaitStream(Error &error)
}
}
bool
PulseOutput
::
StreamPause
(
bool
pause
,
Error
&
error
)
void
PulseOutput
::
StreamPause
(
bool
pause
)
{
assert
(
mainloop
!=
nullptr
);
assert
(
context
!=
nullptr
);
...
...
@@ -762,19 +735,13 @@ PulseOutput::StreamPause(bool pause, Error &error)
pa_operation
*
o
=
pa_stream_cork
(
stream
,
pause
,
pulse_output_stream_success_cb
,
this
);
if
(
o
==
nullptr
)
{
SetPulseError
(
error
,
context
,
if
(
o
==
nullptr
)
throw
MakePulseError
(
context
,
"pa_stream_cork() has failed"
);
return
false
;
}
if
(
!
pulse_wait_for_operation
(
mainloop
,
o
))
{
SetPulseError
(
error
,
context
,
if
(
!
pulse_wait_for_operation
(
mainloop
,
o
))
throw
MakePulseError
(
context
,
"pa_stream_cork() has failed"
);
return
false
;
}
return
true
;
}
inline
unsigned
...
...
@@ -792,7 +759,7 @@ PulseOutput::Delay()
}
inline
size_t
PulseOutput
::
Play
(
const
void
*
chunk
,
size_t
size
,
Error
&
error
)
PulseOutput
::
Play
(
const
void
*
chunk
,
size_t
size
,
gcc_unused
Error
&
error
)
{
assert
(
mainloop
!=
nullptr
);
assert
(
stream
!=
nullptr
);
...
...
@@ -801,30 +768,25 @@ PulseOutput::Play(const void *chunk, size_t size, Error &error)
/* check if the stream is (already) connected */
if
(
!
WaitStream
(
error
))
return
0
;
WaitStream
();
assert
(
context
!=
nullptr
);
/* unpause if previously paused */
if
(
pa_stream_is_corked
(
stream
)
&&
!
StreamPause
(
false
,
error
)
)
return
0
;
if
(
pa_stream_is_corked
(
stream
))
StreamPause
(
false
)
;
/* wait until the server allows us to write */
while
(
writable
==
0
)
{
if
(
pa_stream_is_suspended
(
stream
))
{
error
.
Set
(
pulse_domain
,
"suspended"
);
return
0
;
}
if
(
pa_stream_is_suspended
(
stream
))
throw
std
::
runtime_error
(
"suspended"
);
pa_threaded_mainloop_wait
(
mainloop
);
if
(
pa_stream_get_state
(
stream
)
!=
PA_STREAM_READY
)
{
error
.
Set
(
pulse_domain
,
"disconnected"
);
return
0
;
}
if
(
pa_stream_get_state
(
stream
)
!=
PA_STREAM_READY
)
throw
std
::
runtime_error
(
"disconnected"
);
}
/* now write */
...
...
@@ -837,10 +799,8 @@ PulseOutput::Play(const void *chunk, size_t size, Error &error)
int
result
=
pa_stream_write
(
stream
,
chunk
,
size
,
nullptr
,
0
,
PA_SEEK_RELATIVE
);
if
(
result
<
0
)
{
SetPulseError
(
error
,
context
,
"pa_stream_write() failed"
);
return
0
;
}
if
(
result
<
0
)
throw
MakePulseError
(
context
,
"pa_stream_write() failed"
);
return
size
;
}
...
...
@@ -882,35 +842,27 @@ PulseOutput::Pause()
/* check if the stream is (already/still) connected */
Error
error
;
if
(
!
WaitStream
(
error
))
{
LogError
(
error
);
return
false
;
}
WaitStream
();
assert
(
context
!=
nullptr
);
/* cork the stream */
if
(
!
pa_stream_is_corked
(
stream
)
&&
!
StreamPause
(
true
,
error
))
{
LogError
(
error
);
return
false
;
}
if
(
!
pa_stream_is_corked
(
stream
))
StreamPause
(
true
);
return
true
;
}
inline
bool
PulseOutput
::
TestDefaultDevice
()
{
try
{
const
ConfigBlock
empty
;
PulseOutput
*
po
=
PulseOutput
::
Create
(
empty
,
IgnoreError
());
if
(
po
==
nullptr
)
PulseOutput
po
(
empty
);
po
.
WaitConnection
();
return
true
;
}
catch
(
const
std
::
runtime_error
&
e
)
{
return
false
;
bool
success
=
po
->
WaitConnection
(
IgnoreError
());
delete
po
;
return
success
;
}
static
bool
...
...
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