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
970e3388
Commit
970e3388
authored
Dec 29, 2014
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
output/pulse: move code into the struct
parent
0b9f650f
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
298 additions
and
285 deletions
+298
-285
PipeOutputPlugin.cxx
src/output/plugins/PipeOutputPlugin.cxx
+1
-1
PulseOutputPlugin.cxx
src/output/plugins/PulseOutputPlugin.cxx
+296
-283
SlesOutputPlugin.cxx
src/output/plugins/sles/SlesOutputPlugin.cxx
+1
-1
No files found.
src/output/plugins/PipeOutputPlugin.cxx
View file @
970e3388
...
@@ -30,7 +30,7 @@
...
@@ -30,7 +30,7 @@
#include <stdio.h>
#include <stdio.h>
class
PipeOutput
{
class
PipeOutput
{
friend
AudioOutputWrapper
<
PipeOutput
>
;
friend
struct
AudioOutputWrapper
<
PipeOutput
>
;
AudioOutput
base
;
AudioOutput
base
;
...
...
src/output/plugins/PulseOutputPlugin.cxx
View file @
970e3388
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include "lib/pulse/Error.hxx"
#include "lib/pulse/Error.hxx"
#include "lib/pulse/LogError.hxx"
#include "lib/pulse/LogError.hxx"
#include "../OutputAPI.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
#include "mixer/MixerList.hxx"
#include "mixer/plugins/PulseMixerPlugin.hxx"
#include "mixer/plugins/PulseMixerPlugin.hxx"
#include "util/Error.hxx"
#include "util/Error.hxx"
...
@@ -60,6 +61,85 @@ struct PulseOutput {
...
@@ -60,6 +61,85 @@ struct PulseOutput {
:
base
(
pulse_output_plugin
),
:
base
(
pulse_output_plugin
),
mixer
(
nullptr
),
mixer
(
nullptr
),
mainloop
(
nullptr
),
stream
(
nullptr
)
{}
mainloop
(
nullptr
),
stream
(
nullptr
)
{}
gcc_const
static
bool
TestDefaultDevice
();
bool
Configure
(
const
config_param
&
param
,
Error
&
error
);
bool
Enable
(
Error
&
error
);
void
Disable
();
bool
Open
(
AudioFormat
&
audio_format
,
Error
&
error
);
void
Close
();
unsigned
Delay
();
size_t
Play
(
const
void
*
chunk
,
size_t
size
,
Error
&
error
);
void
Cancel
();
bool
Pause
();
private
:
/**
* Attempt to connect asynchronously to the PulseAudio server.
*
* @return true on success, false on error
*/
bool
Connect
(
Error
&
error
);
/**
* Create, set up and connect a context.
*
* Caller must lock the main loop.
*
* @return true on success, false on error
*/
bool
SetupContext
(
Error
&
error
);
/**
* Frees and clears the context.
*
* Caller must lock the main loop.
*/
void
DeleteContext
();
/**
* Check if the context is (already) connected, and waits if
* not. If the context has been disconnected, retry to
* connect.
*
* Caller must lock the main loop.
*
* @return true on success, false on error
*/
bool
WaitConnection
(
Error
&
error
);
/**
* Create, set up and connect a context.
*
* Caller must lock the main loop.
*
* @return true on success, false on error
*/
bool
SetupStream
(
const
pa_sample_spec
&
ss
,
Error
&
error
);
/**
* Frees and clears the stream.
*/
void
DeleteStream
();
/**
* Check if the stream is (already) connected, and waits if
* not. The mainloop must be locked before calling this
* function.
*
* @return true on success, false on error
*/
bool
WaitStream
(
Error
&
error
);
/**
* Sets cork mode on the stream.
*/
bool
StreamPause
(
bool
pause
,
Error
&
error
);
};
};
void
void
...
@@ -220,20 +300,14 @@ pulse_output_subscribe_cb(pa_context *context,
...
@@ -220,20 +300,14 @@ pulse_output_subscribe_cb(pa_context *context,
pulse_mixer_on_change
(
*
po
->
mixer
,
context
,
po
->
stream
);
pulse_mixer_on_change
(
*
po
->
mixer
,
context
,
po
->
stream
);
}
}
/**
inline
bool
* Attempt to connect asynchronously to the PulseAudio server.
PulseOutput
::
Connect
(
Error
&
error
)
*
* @return true on success, false on error
*/
static
bool
pulse_output_connect
(
PulseOutput
*
po
,
Error
&
error
)
{
{
assert
(
po
!=
nullptr
);
assert
(
context
!=
nullptr
);
assert
(
po
->
context
!=
nullptr
);
if
(
pa_context_connect
(
po
->
context
,
po
->
server
,
if
(
pa_context_connect
(
context
,
server
,
(
pa_context_flags_t
)
0
,
nullptr
)
<
0
)
{
(
pa_context_flags_t
)
0
,
nullptr
)
<
0
)
{
SetPulseError
(
error
,
po
->
context
,
SetPulseError
(
error
,
context
,
"pa_context_connect() has failed"
);
"pa_context_connect() has failed"
);
return
false
;
return
false
;
}
}
...
@@ -241,77 +315,72 @@ pulse_output_connect(PulseOutput *po, Error &error)
...
@@ -241,77 +315,72 @@ pulse_output_connect(PulseOutput *po, Error &error)
return
true
;
return
true
;
}
}
/**
void
* Frees and clears the stream.
PulseOutput
::
DeleteStream
()
*/
static
void
pulse_output_delete_stream
(
PulseOutput
*
po
)
{
{
assert
(
po
!=
nullptr
);
assert
(
stream
!=
nullptr
);
assert
(
po
->
stream
!=
nullptr
);
pa_stream_set_suspended_callback
(
po
->
stream
,
nullptr
,
nullptr
);
pa_stream_set_suspended_callback
(
stream
,
nullptr
,
nullptr
);
pa_stream_set_state_callback
(
po
->
stream
,
nullptr
,
nullptr
);
pa_stream_set_state_callback
(
stream
,
nullptr
,
nullptr
);
pa_stream_set_write_callback
(
po
->
stream
,
nullptr
,
nullptr
);
pa_stream_set_write_callback
(
stream
,
nullptr
,
nullptr
);
pa_stream_disconnect
(
po
->
stream
);
pa_stream_disconnect
(
stream
);
pa_stream_unref
(
po
->
stream
);
pa_stream_unref
(
stream
);
po
->
stream
=
nullptr
;
stream
=
nullptr
;
}
}
/**
void
* Frees and clears the context.
PulseOutput
::
DeleteContext
()
*
* Caller must lock the main loop.
*/
static
void
pulse_output_delete_context
(
PulseOutput
*
po
)
{
{
assert
(
po
!=
nullptr
);
assert
(
context
!=
nullptr
);
assert
(
po
->
context
!=
nullptr
);
pa_context_set_state_callback
(
po
->
context
,
nullptr
,
nullptr
);
pa_context_set_state_callback
(
context
,
nullptr
,
nullptr
);
pa_context_set_subscribe_callback
(
po
->
context
,
nullptr
,
nullptr
);
pa_context_set_subscribe_callback
(
context
,
nullptr
,
nullptr
);
pa_context_disconnect
(
po
->
context
);
pa_context_disconnect
(
context
);
pa_context_unref
(
po
->
context
);
pa_context_unref
(
context
);
po
->
context
=
nullptr
;
context
=
nullptr
;
}
}
/**
bool
* Create, set up and connect a context.
PulseOutput
::
SetupContext
(
Error
&
error
)
*
* Caller must lock the main loop.
*
* @return true on success, false on error
*/
static
bool
pulse_output_setup_context
(
PulseOutput
*
po
,
Error
&
error
)
{
{
assert
(
po
!=
nullptr
);
assert
(
mainloop
!=
nullptr
);
assert
(
po
->
mainloop
!=
nullptr
);
po
->
context
=
pa_context_new
(
pa_threaded_mainloop_get_api
(
po
->
mainloop
),
context
=
pa_context_new
(
pa_threaded_mainloop_get_api
(
mainloop
),
MPD_PULSE_NAME
);
MPD_PULSE_NAME
);
if
(
po
->
context
==
nullptr
)
{
if
(
context
==
nullptr
)
{
error
.
Set
(
pulse_domain
,
"pa_context_new() has failed"
);
error
.
Set
(
pulse_domain
,
"pa_context_new() has failed"
);
return
false
;
return
false
;
}
}
pa_context_set_state_callback
(
po
->
context
,
pa_context_set_state_callback
(
context
,
pulse_output_context_state_cb
,
po
);
pulse_output_context_state_cb
,
this
);
pa_context_set_subscribe_callback
(
po
->
context
,
pa_context_set_subscribe_callback
(
context
,
pulse_output_subscribe_cb
,
po
);
pulse_output_subscribe_cb
,
this
);
if
(
!
pulse_output_connect
(
po
,
error
))
{
if
(
!
Connect
(
error
))
{
pulse_output_delete_context
(
po
);
DeleteContext
(
);
return
false
;
return
false
;
}
}
return
true
;
return
true
;
}
}
inline
bool
PulseOutput
::
Configure
(
const
config_param
&
param
,
Error
&
error
)
{
if
(
!
base
.
Configure
(
param
,
error
))
return
false
;
name
=
param
.
GetBlockValue
(
"name"
,
"mpd_pulse"
);
server
=
param
.
GetBlockValue
(
"server"
);
sink
=
param
.
GetBlockValue
(
"sink"
);
return
true
;
}
static
AudioOutput
*
static
AudioOutput
*
pulse_output_init
(
const
config_param
&
param
,
Error
&
error
)
pulse_output_init
(
const
config_param
&
param
,
Error
&
error
)
{
{
...
@@ -321,48 +390,34 @@ pulse_output_init(const config_param ¶m, Error &error)
...
@@ -321,48 +390,34 @@ pulse_output_init(const config_param ¶m, Error &error)
setenv
(
"PULSE_PROP_application.icon_name"
,
"mpd"
,
true
);
setenv
(
"PULSE_PROP_application.icon_name"
,
"mpd"
,
true
);
po
=
new
PulseOutput
();
po
=
new
PulseOutput
();
if
(
!
po
->
base
.
Configure
(
param
,
error
))
{
if
(
!
po
->
Configure
(
param
,
error
))
{
delete
po
;
delete
po
;
return
nullptr
;
return
nullptr
;
}
}
po
->
name
=
param
.
GetBlockValue
(
"name"
,
"mpd_pulse"
);
po
->
server
=
param
.
GetBlockValue
(
"server"
);
po
->
sink
=
param
.
GetBlockValue
(
"sink"
);
return
&
po
->
base
;
return
&
po
->
base
;
}
}
static
void
inline
bool
pulse_output_finish
(
AudioOutput
*
ao
)
PulseOutput
::
Enable
(
Error
&
error
)
{
PulseOutput
*
po
=
(
PulseOutput
*
)
ao
;
delete
po
;
}
static
bool
pulse_output_enable
(
AudioOutput
*
ao
,
Error
&
error
)
{
{
PulseOutput
*
po
=
(
PulseOutput
*
)
ao
;
assert
(
mainloop
==
nullptr
);
assert
(
po
->
mainloop
==
nullptr
);
/* create the libpulse mainloop and start the thread */
/* create the libpulse mainloop and start the thread */
po
->
mainloop
=
pa_threaded_mainloop_new
();
mainloop
=
pa_threaded_mainloop_new
();
if
(
po
->
mainloop
==
nullptr
)
{
if
(
mainloop
==
nullptr
)
{
error
.
Set
(
pulse_domain
,
error
.
Set
(
pulse_domain
,
"pa_threaded_mainloop_new() has failed"
);
"pa_threaded_mainloop_new() has failed"
);
return
false
;
return
false
;
}
}
pa_threaded_mainloop_lock
(
po
->
mainloop
);
pa_threaded_mainloop_lock
(
mainloop
);
if
(
pa_threaded_mainloop_start
(
po
->
mainloop
)
<
0
)
{
if
(
pa_threaded_mainloop_start
(
mainloop
)
<
0
)
{
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
pa_threaded_mainloop_free
(
po
->
mainloop
);
pa_threaded_mainloop_free
(
mainloop
);
po
->
mainloop
=
nullptr
;
mainloop
=
nullptr
;
error
.
Set
(
pulse_domain
,
error
.
Set
(
pulse_domain
,
"pa_threaded_mainloop_start() has failed"
);
"pa_threaded_mainloop_start() has failed"
);
...
@@ -371,53 +426,43 @@ pulse_output_enable(AudioOutput *ao, Error &error)
...
@@ -371,53 +426,43 @@ pulse_output_enable(AudioOutput *ao, Error &error)
/* create the libpulse context and connect it */
/* create the libpulse context and connect it */
if
(
!
pulse_output_setup_context
(
po
,
error
))
{
if
(
!
SetupContext
(
error
))
{
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
pa_threaded_mainloop_stop
(
po
->
mainloop
);
pa_threaded_mainloop_stop
(
mainloop
);
pa_threaded_mainloop_free
(
po
->
mainloop
);
pa_threaded_mainloop_free
(
mainloop
);
po
->
mainloop
=
nullptr
;
mainloop
=
nullptr
;
return
false
;
return
false
;
}
}
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
return
true
;
return
true
;
}
}
static
void
inline
void
pulse_output_disable
(
AudioOutput
*
ao
)
PulseOutput
::
Disable
(
)
{
{
PulseOutput
*
po
=
(
PulseOutput
*
)
ao
;
assert
(
mainloop
!=
nullptr
);
assert
(
po
->
mainloop
!=
nullptr
);
pa_threaded_mainloop_stop
(
po
->
mainloop
);
pa_threaded_mainloop_stop
(
mainloop
);
if
(
po
->
context
!=
nullptr
)
if
(
context
!=
nullptr
)
pulse_output_delete_context
(
po
);
DeleteContext
(
);
pa_threaded_mainloop_free
(
po
->
mainloop
);
pa_threaded_mainloop_free
(
mainloop
);
po
->
mainloop
=
nullptr
;
mainloop
=
nullptr
;
}
}
/**
bool
* Check if the context is (already) connected, and waits if not. If
PulseOutput
::
WaitConnection
(
Error
&
error
)
* the context has been disconnected, retry to connect.
*
* Caller must lock the main loop.
*
* @return true on success, false on error
*/
static
bool
pulse_output_wait_connection
(
PulseOutput
*
po
,
Error
&
error
)
{
{
assert
(
po
->
mainloop
!=
nullptr
);
assert
(
mainloop
!=
nullptr
);
pa_context_state_t
state
;
pa_context_state_t
state
;
if
(
po
->
context
==
nullptr
&&
!
pulse_output_setup_context
(
po
,
error
))
if
(
context
==
nullptr
&&
!
SetupContext
(
error
))
return
false
;
return
false
;
while
(
true
)
{
while
(
true
)
{
state
=
pa_context_get_state
(
po
->
context
);
state
=
pa_context_get_state
(
context
);
switch
(
state
)
{
switch
(
state
)
{
case
PA_CONTEXT_READY
:
case
PA_CONTEXT_READY
:
/* nothing to do */
/* nothing to do */
...
@@ -427,15 +472,15 @@ pulse_output_wait_connection(PulseOutput *po, Error &error)
...
@@ -427,15 +472,15 @@ pulse_output_wait_connection(PulseOutput *po, Error &error)
case
PA_CONTEXT_TERMINATED
:
case
PA_CONTEXT_TERMINATED
:
case
PA_CONTEXT_FAILED
:
case
PA_CONTEXT_FAILED
:
/* failure */
/* failure */
SetPulseError
(
error
,
po
->
context
,
"failed to connect"
);
SetPulseError
(
error
,
context
,
"failed to connect"
);
pulse_output_delete_context
(
po
);
DeleteContext
(
);
return
false
;
return
false
;
case
PA_CONTEXT_CONNECTING
:
case
PA_CONTEXT_CONNECTING
:
case
PA_CONTEXT_AUTHORIZING
:
case
PA_CONTEXT_AUTHORIZING
:
case
PA_CONTEXT_SETTING_NAME
:
case
PA_CONTEXT_SETTING_NAME
:
/* wait some more */
/* wait some more */
pa_threaded_mainloop_wait
(
po
->
mainloop
);
pa_threaded_mainloop_wait
(
mainloop
);
break
;
break
;
}
}
}
}
...
@@ -497,62 +542,50 @@ pulse_output_stream_write_cb(gcc_unused pa_stream *stream, size_t nbytes,
...
@@ -497,62 +542,50 @@ pulse_output_stream_write_cb(gcc_unused pa_stream *stream, size_t nbytes,
pa_threaded_mainloop_signal
(
po
->
mainloop
,
0
);
pa_threaded_mainloop_signal
(
po
->
mainloop
,
0
);
}
}
/**
inline
bool
* Create, set up and connect a context.
PulseOutput
::
SetupStream
(
const
pa_sample_spec
&
ss
,
Error
&
error
)
*
* Caller must lock the main loop.
*
* @return true on success, false on error
*/
static
bool
pulse_output_setup_stream
(
PulseOutput
*
po
,
const
pa_sample_spec
*
ss
,
Error
&
error
)
{
{
assert
(
po
!=
nullptr
);
assert
(
context
!=
nullptr
);
assert
(
po
->
context
!=
nullptr
);
/* WAVE-EX is been adopted as the speaker map for most media files */
/* WAVE-EX is been adopted as the speaker map for most media files */
pa_channel_map
chan_map
;
pa_channel_map
chan_map
;
pa_channel_map_init_auto
(
&
chan_map
,
ss
->
channels
,
pa_channel_map_init_auto
(
&
chan_map
,
ss
.
channels
,
PA_CHANNEL_MAP_WAVEEX
);
PA_CHANNEL_MAP_WAVEEX
);
po
->
stream
=
pa_stream_new
(
po
->
context
,
po
->
name
,
ss
,
&
chan_map
);
stream
=
pa_stream_new
(
context
,
name
,
&
ss
,
&
chan_map
);
if
(
po
->
stream
==
nullptr
)
{
if
(
stream
==
nullptr
)
{
SetPulseError
(
error
,
po
->
context
,
SetPulseError
(
error
,
context
,
"pa_stream_new() has failed"
);
"pa_stream_new() has failed"
);
return
false
;
return
false
;
}
}
pa_stream_set_suspended_callback
(
po
->
stream
,
pa_stream_set_suspended_callback
(
stream
,
pulse_output_stream_suspended_cb
,
po
);
pulse_output_stream_suspended_cb
,
this
);
pa_stream_set_state_callback
(
po
->
stream
,
pa_stream_set_state_callback
(
stream
,
pulse_output_stream_state_cb
,
po
);
pulse_output_stream_state_cb
,
this
);
pa_stream_set_write_callback
(
po
->
stream
,
pa_stream_set_write_callback
(
stream
,
pulse_output_stream_write_cb
,
po
);
pulse_output_stream_write_cb
,
this
);
return
true
;
return
true
;
}
}
static
bool
inline
bool
pulse_output_open
(
AudioOutput
*
ao
,
AudioFormat
&
audio_format
,
PulseOutput
::
Open
(
AudioFormat
&
audio_format
,
Error
&
error
)
Error
&
error
)
{
{
PulseOutput
*
po
=
(
PulseOutput
*
)
ao
;
assert
(
mainloop
!=
nullptr
);
pa_sample_spec
ss
;
assert
(
po
->
mainloop
!=
nullptr
);
pa_threaded_mainloop_lock
(
po
->
mainloop
);
pa_threaded_mainloop_lock
(
mainloop
);
if
(
po
->
context
!=
nullptr
)
{
if
(
context
!=
nullptr
)
{
switch
(
pa_context_get_state
(
po
->
context
))
{
switch
(
pa_context_get_state
(
context
))
{
case
PA_CONTEXT_UNCONNECTED
:
case
PA_CONTEXT_UNCONNECTED
:
case
PA_CONTEXT_TERMINATED
:
case
PA_CONTEXT_TERMINATED
:
case
PA_CONTEXT_FAILED
:
case
PA_CONTEXT_FAILED
:
/* the connection was closed meanwhile; delete
/* the connection was closed meanwhile; delete
it, and pulse_output_wait_connection() will
it, and pulse_output_wait_connection() will
reopen it */
reopen it */
pulse_output_delete_context
(
po
);
DeleteContext
(
);
break
;
break
;
case
PA_CONTEXT_READY
:
case
PA_CONTEXT_READY
:
...
@@ -563,8 +596,8 @@ pulse_output_open(AudioOutput *ao, AudioFormat &audio_format,
...
@@ -563,8 +596,8 @@ pulse_output_open(AudioOutput *ao, AudioFormat &audio_format,
}
}
}
}
if
(
!
pulse_output_wait_connection
(
po
,
error
))
{
if
(
!
WaitConnection
(
error
))
{
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
return
false
;
return
false
;
}
}
...
@@ -572,115 +605,101 @@ pulse_output_open(AudioOutput *ao, AudioFormat &audio_format,
...
@@ -572,115 +605,101 @@ pulse_output_open(AudioOutput *ao, AudioFormat &audio_format,
we just force MPD to send us everything as 16 bit */
we just force MPD to send us everything as 16 bit */
audio_format
.
format
=
SampleFormat
::
S16
;
audio_format
.
format
=
SampleFormat
::
S16
;
pa_sample_spec
ss
;
ss
.
format
=
PA_SAMPLE_S16NE
;
ss
.
format
=
PA_SAMPLE_S16NE
;
ss
.
rate
=
audio_format
.
sample_rate
;
ss
.
rate
=
audio_format
.
sample_rate
;
ss
.
channels
=
audio_format
.
channels
;
ss
.
channels
=
audio_format
.
channels
;
/* create a stream .. */
/* create a stream .. */
if
(
!
pulse_output_setup_stream
(
po
,
&
ss
,
error
))
{
if
(
!
SetupStream
(
ss
,
error
))
{
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
return
false
;
return
false
;
}
}
/* .. and connect it (asynchronously) */
/* .. and connect it (asynchronously) */
if
(
pa_stream_connect_playback
(
po
->
stream
,
po
->
sink
,
if
(
pa_stream_connect_playback
(
stream
,
sink
,
nullptr
,
pa_stream_flags_t
(
0
),
nullptr
,
pa_stream_flags_t
(
0
),
nullptr
,
nullptr
)
<
0
)
{
nullptr
,
nullptr
)
<
0
)
{
pulse_output_delete_stream
(
po
);
DeleteStream
(
);
SetPulseError
(
error
,
po
->
context
,
SetPulseError
(
error
,
context
,
"pa_stream_connect_playback() has failed"
);
"pa_stream_connect_playback() has failed"
);
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
return
false
;
return
false
;
}
}
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
return
true
;
return
true
;
}
}
static
void
inline
void
pulse_output_close
(
AudioOutput
*
ao
)
PulseOutput
::
Close
(
)
{
{
PulseOutput
*
po
=
(
PulseOutput
*
)
ao
;
assert
(
mainloop
!=
nullptr
);
pa_operation
*
o
;
assert
(
po
->
mainloop
!=
nullptr
);
pa_threaded_mainloop_lock
(
po
->
mainloop
);
pa_threaded_mainloop_lock
(
mainloop
);
if
(
pa_stream_get_state
(
po
->
stream
)
==
PA_STREAM_READY
)
{
if
(
pa_stream_get_state
(
stream
)
==
PA_STREAM_READY
)
{
o
=
pa_stream_drain
(
po
->
stream
,
pa_operation
*
o
=
pulse_output_stream_success_cb
,
po
);
pa_stream_drain
(
stream
,
pulse_output_stream_success_cb
,
this
);
if
(
o
==
nullptr
)
{
if
(
o
==
nullptr
)
{
LogPulseError
(
po
->
context
,
LogPulseError
(
context
,
"pa_stream_drain() has failed"
);
"pa_stream_drain() has failed"
);
}
else
}
else
pulse_wait_for_operation
(
po
->
mainloop
,
o
);
pulse_wait_for_operation
(
mainloop
,
o
);
}
}
pulse_output_delete_stream
(
po
);
DeleteStream
(
);
if
(
po
->
context
!=
nullptr
&&
if
(
context
!=
nullptr
&&
pa_context_get_state
(
po
->
context
)
!=
PA_CONTEXT_READY
)
pa_context_get_state
(
context
)
!=
PA_CONTEXT_READY
)
pulse_output_delete_context
(
po
);
DeleteContext
(
);
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
}
}
/**
bool
* Check if the stream is (already) connected, and waits if not. The
PulseOutput
::
WaitStream
(
Error
&
error
)
* mainloop must be locked before calling this function.
*
* @return true on success, false on error
*/
static
bool
pulse_output_wait_stream
(
PulseOutput
*
po
,
Error
&
error
)
{
{
while
(
true
)
{
while
(
true
)
{
switch
(
pa_stream_get_state
(
po
->
stream
))
{
switch
(
pa_stream_get_state
(
stream
))
{
case
PA_STREAM_READY
:
case
PA_STREAM_READY
:
return
true
;
return
true
;
case
PA_STREAM_FAILED
:
case
PA_STREAM_FAILED
:
case
PA_STREAM_TERMINATED
:
case
PA_STREAM_TERMINATED
:
case
PA_STREAM_UNCONNECTED
:
case
PA_STREAM_UNCONNECTED
:
SetPulseError
(
error
,
po
->
context
,
SetPulseError
(
error
,
context
,
"failed to connect the stream"
);
"failed to connect the stream"
);
return
false
;
return
false
;
case
PA_STREAM_CREATING
:
case
PA_STREAM_CREATING
:
pa_threaded_mainloop_wait
(
po
->
mainloop
);
pa_threaded_mainloop_wait
(
mainloop
);
break
;
break
;
}
}
}
}
}
}
/**
bool
* Sets cork mode on the stream.
PulseOutput
::
StreamPause
(
bool
pause
,
Error
&
error
)
*/
static
bool
pulse_output_stream_pause
(
PulseOutput
*
po
,
bool
pause
,
Error
&
error
)
{
{
pa_operation
*
o
;
assert
(
mainloop
!=
nullptr
);
assert
(
context
!=
nullptr
);
assert
(
po
->
mainloop
!=
nullptr
);
assert
(
stream
!=
nullptr
);
assert
(
po
->
context
!=
nullptr
);
assert
(
po
->
stream
!=
nullptr
);
o
=
pa_stream_cork
(
po
->
stream
,
pause
,
pa_operation
*
o
=
pa_stream_cork
(
stream
,
pause
,
pulse_output_stream_success_cb
,
po
);
pulse_output_stream_success_cb
,
this
);
if
(
o
==
nullptr
)
{
if
(
o
==
nullptr
)
{
SetPulseError
(
error
,
po
->
context
,
SetPulseError
(
error
,
context
,
"pa_stream_cork() has failed"
);
"pa_stream_cork() has failed"
);
return
false
;
return
false
;
}
}
if
(
!
pulse_wait_for_operation
(
po
->
mainloop
,
o
))
{
if
(
!
pulse_wait_for_operation
(
mainloop
,
o
))
{
SetPulseError
(
error
,
po
->
context
,
SetPulseError
(
error
,
context
,
"pa_stream_cork() has failed"
);
"pa_stream_cork() has failed"
);
return
false
;
return
false
;
}
}
...
@@ -688,65 +707,59 @@ pulse_output_stream_pause(PulseOutput *po, bool pause,
...
@@ -688,65 +707,59 @@ pulse_output_stream_pause(PulseOutput *po, bool pause,
return
true
;
return
true
;
}
}
static
unsigned
inline
unsigned
pulse_output_delay
(
AudioOutput
*
ao
)
PulseOutput
::
Delay
(
)
{
{
PulseOutput
*
po
=
(
PulseOutput
*
)
ao
;
pa_threaded_mainloop_lock
(
mainloop
);
unsigned
result
=
0
;
pa_threaded_mainloop_lock
(
po
->
mainloop
);
if
(
po
->
base
.
pause
&&
pa_stream_is_corked
(
po
->
stream
)
&&
unsigned
result
=
0
;
pa_stream_get_state
(
po
->
stream
)
==
PA_STREAM_READY
)
if
(
base
.
pause
&&
pa_stream_is_corked
(
stream
)
&&
pa_stream_get_state
(
stream
)
==
PA_STREAM_READY
)
/* idle while paused */
/* idle while paused */
result
=
1000
;
result
=
1000
;
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
return
result
;
return
result
;
}
}
static
size_t
inline
size_t
pulse_output_play
(
AudioOutput
*
ao
,
const
void
*
chunk
,
size_t
size
,
PulseOutput
::
Play
(
const
void
*
chunk
,
size_t
size
,
Error
&
error
)
Error
&
error
)
{
{
PulseOutput
*
po
=
(
PulseOutput
*
)
ao
;
assert
(
mainloop
!=
nullptr
);
assert
(
stream
!=
nullptr
);
assert
(
po
->
mainloop
!=
nullptr
);
assert
(
po
->
stream
!=
nullptr
);
pa_threaded_mainloop_lock
(
po
->
mainloop
);
pa_threaded_mainloop_lock
(
mainloop
);
/* check if the stream is (already) connected */
/* check if the stream is (already) connected */
if
(
!
pulse_output_wait_stream
(
po
,
error
))
{
if
(
!
WaitStream
(
error
))
{
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
return
0
;
return
0
;
}
}
assert
(
po
->
context
!=
nullptr
);
assert
(
context
!=
nullptr
);
/* unpause if previously paused */
/* unpause if previously paused */
if
(
pa_stream_is_corked
(
po
->
stream
)
&&
if
(
pa_stream_is_corked
(
stream
)
&&
!
StreamPause
(
false
,
error
))
{
!
pulse_output_stream_pause
(
po
,
false
,
error
))
{
pa_threaded_mainloop_unlock
(
mainloop
);
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
return
0
;
return
0
;
}
}
/* wait until the server allows us to write */
/* wait until the server allows us to write */
while
(
po
->
writable
==
0
)
{
while
(
writable
==
0
)
{
if
(
pa_stream_is_suspended
(
po
->
stream
))
{
if
(
pa_stream_is_suspended
(
stream
))
{
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
error
.
Set
(
pulse_domain
,
"suspended"
);
error
.
Set
(
pulse_domain
,
"suspended"
);
return
0
;
return
0
;
}
}
pa_threaded_mainloop_wait
(
po
->
mainloop
);
pa_threaded_mainloop_wait
(
mainloop
);
if
(
pa_stream_get_state
(
po
->
stream
)
!=
PA_STREAM_READY
)
{
if
(
pa_stream_get_state
(
stream
)
!=
PA_STREAM_READY
)
{
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
error
.
Set
(
pulse_domain
,
"disconnected"
);
error
.
Set
(
pulse_domain
,
"disconnected"
);
return
0
;
return
0
;
}
}
...
@@ -754,121 +767,121 @@ pulse_output_play(AudioOutput *ao, const void *chunk, size_t size,
...
@@ -754,121 +767,121 @@ pulse_output_play(AudioOutput *ao, const void *chunk, size_t size,
/* now write */
/* now write */
if
(
size
>
po
->
writable
)
if
(
size
>
writable
)
/* don't send more than possible */
/* don't send more than possible */
size
=
po
->
writable
;
size
=
writable
;
po
->
writable
-=
size
;
writable
-=
size
;
int
result
=
pa_stream_write
(
po
->
stream
,
chunk
,
size
,
nullptr
,
int
result
=
pa_stream_write
(
stream
,
chunk
,
size
,
nullptr
,
0
,
PA_SEEK_RELATIVE
);
0
,
PA_SEEK_RELATIVE
);
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
if
(
result
<
0
)
{
if
(
result
<
0
)
{
SetPulseError
(
error
,
po
->
context
,
"pa_stream_write() failed"
);
SetPulseError
(
error
,
context
,
"pa_stream_write() failed"
);
return
0
;
return
0
;
}
}
return
size
;
return
size
;
}
}
static
void
inline
void
pulse_output_cancel
(
AudioOutput
*
ao
)
PulseOutput
::
Cancel
(
)
{
{
PulseOutput
*
po
=
(
PulseOutput
*
)
ao
;
assert
(
mainloop
!=
nullptr
);
pa_operation
*
o
;
assert
(
stream
!=
nullptr
);
assert
(
po
->
mainloop
!=
nullptr
);
assert
(
po
->
stream
!=
nullptr
);
pa_threaded_mainloop_lock
(
po
->
mainloop
);
pa_threaded_mainloop_lock
(
mainloop
);
if
(
pa_stream_get_state
(
po
->
stream
)
!=
PA_STREAM_READY
)
{
if
(
pa_stream_get_state
(
stream
)
!=
PA_STREAM_READY
)
{
/* no need to flush when the stream isn't connected
/* no need to flush when the stream isn't connected
yet */
yet */
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
return
;
return
;
}
}
assert
(
po
->
context
!=
nullptr
);
assert
(
context
!=
nullptr
);
o
=
pa_stream_flush
(
po
->
stream
,
pulse_output_stream_success_cb
,
po
);
pa_operation
*
o
=
pa_stream_flush
(
stream
,
pulse_output_stream_success_cb
,
this
);
if
(
o
==
nullptr
)
{
if
(
o
==
nullptr
)
{
LogPulseError
(
po
->
context
,
"pa_stream_flush() has failed"
);
LogPulseError
(
context
,
"pa_stream_flush() has failed"
);
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
return
;
return
;
}
}
pulse_wait_for_operation
(
po
->
mainloop
,
o
);
pulse_wait_for_operation
(
mainloop
,
o
);
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
}
}
static
bool
inline
bool
pulse_output_pause
(
AudioOutput
*
ao
)
PulseOutput
::
Pause
(
)
{
{
PulseOutput
*
po
=
(
PulseOutput
*
)
ao
;
assert
(
mainloop
!=
nullptr
);
assert
(
stream
!=
nullptr
);
assert
(
po
->
mainloop
!=
nullptr
);
assert
(
po
->
stream
!=
nullptr
);
pa_threaded_mainloop_lock
(
po
->
mainloop
);
pa_threaded_mainloop_lock
(
mainloop
);
/* check if the stream is (already/still) connected */
/* check if the stream is (already/still) connected */
Error
error
;
Error
error
;
if
(
!
pulse_output_wait_stream
(
po
,
error
))
{
if
(
!
WaitStream
(
error
))
{
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
LogError
(
error
);
LogError
(
error
);
return
false
;
return
false
;
}
}
assert
(
po
->
context
!=
nullptr
);
assert
(
context
!=
nullptr
);
/* cork the stream */
/* cork the stream */
if
(
!
pa_stream_is_corked
(
po
->
stream
)
&&
if
(
!
pa_stream_is_corked
(
stream
)
&&
!
StreamPause
(
true
,
error
))
{
!
pulse_output_stream_pause
(
po
,
true
,
error
))
{
pa_threaded_mainloop_unlock
(
mainloop
);
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
LogError
(
error
);
LogError
(
error
);
return
false
;
return
false
;
}
}
pa_threaded_mainloop_unlock
(
po
->
mainloop
);
pa_threaded_mainloop_unlock
(
mainloop
);
return
true
;
return
true
;
}
}
static
bool
inline
bool
pulse_output_test_default_device
(
void
)
PulseOutput
::
TestDefaultDevice
(
)
{
{
bool
success
;
const
config_param
empty
;
const
config_param
empty
;
PulseOutput
*
po
=
(
PulseOutput
*
)
PulseOutput
*
po
=
(
PulseOutput
*
)
pulse_output_init
(
empty
,
IgnoreError
());
pulse_output_init
(
empty
,
IgnoreError
());
if
(
po
==
nullptr
)
if
(
po
==
nullptr
)
return
false
;
return
false
;
success
=
pulse_output_wait_connection
(
po
,
IgnoreError
());
bool
success
=
po
->
WaitConnection
(
IgnoreError
());
pulse_output_finish
(
&
po
->
base
);
delete
po
;
return
success
;
return
success
;
}
}
static
bool
pulse_output_test_default_device
(
void
)
{
return
PulseOutput
::
TestDefaultDevice
();
}
typedef
AudioOutputWrapper
<
PulseOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
pulse_output_plugin
=
{
const
struct
AudioOutputPlugin
pulse_output_plugin
=
{
"pulse"
,
"pulse"
,
pulse_output_test_default_device
,
pulse_output_test_default_device
,
pulse_output_init
,
pulse_output_init
,
pulse_output_f
inish
,
&
Wrapper
::
F
inish
,
pulse_output_e
nable
,
&
Wrapper
::
E
nable
,
pulse_output_d
isable
,
&
Wrapper
::
D
isable
,
pulse_output_o
pen
,
&
Wrapper
::
O
pen
,
pulse_output_c
lose
,
&
Wrapper
::
C
lose
,
pulse_output_d
elay
,
&
Wrapper
::
D
elay
,
nullptr
,
nullptr
,
pulse_output_p
lay
,
&
Wrapper
::
P
lay
,
nullptr
,
nullptr
,
pulse_output_c
ancel
,
&
Wrapper
::
C
ancel
,
pulse_output_p
ause
,
&
Wrapper
::
P
ause
,
&
pulse_mixer_plugin
,
&
pulse_mixer_plugin
,
};
};
src/output/plugins/sles/SlesOutputPlugin.cxx
View file @
970e3388
...
@@ -35,7 +35,7 @@
...
@@ -35,7 +35,7 @@
#include <SLES/OpenSLES_Android.h>
#include <SLES/OpenSLES_Android.h>
class
SlesOutput
{
class
SlesOutput
{
friend
AudioOutputWrapper
<
SlesOutput
>
;
friend
struct
AudioOutputWrapper
<
SlesOutput
>
;
static
constexpr
unsigned
N_BUFFERS
=
3
;
static
constexpr
unsigned
N_BUFFERS
=
3
;
static
constexpr
size_t
BUFFER_SIZE
=
65536
;
static
constexpr
size_t
BUFFER_SIZE
=
65536
;
...
...
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