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
86d3b25a
Commit
86d3b25a
authored
Dec 26, 2016
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
output/Source: add Fill(), ReadTag(), PeekData(), ConsumeData()
Don't expose MusicChunk instances, provide higher-level access to chunk contents.
parent
8a407bfb
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
130 additions
and
44 deletions
+130
-44
Internal.hxx
src/output/Internal.hxx
+3
-2
OutputThread.cxx
src/output/OutputThread.cxx
+35
-32
Source.cxx
src/output/Source.cxx
+35
-0
Source.hxx
src/output/Source.hxx
+57
-10
No files found.
src/output/Internal.hxx
View file @
86d3b25a
...
...
@@ -30,7 +30,6 @@
#include "system/PeriodClock.hxx"
class
PreparedFilter
;
class
Filter
;
class
MusicPipe
;
class
EventLoop
;
class
Mixer
;
...
...
@@ -455,7 +454,9 @@ private:
*/
bool
WaitForDelay
();
bool
PlayChunk
(
const
MusicChunk
&
chunk
);
bool
FillSourceOrClose
();
bool
PlayChunk
();
/**
* Plays all remaining chunks, until the tail of the pipe has
...
...
src/output/OutputThread.cxx
View file @
86d3b25a
...
...
@@ -261,36 +261,43 @@ AudioOutput::WaitForDelay()
}
}
bool
AudioOutput
::
FillSourceOrClose
()
try
{
return
source
.
Fill
();
}
catch
(
const
std
::
runtime_error
&
e
)
{
FormatError
(
e
,
"Failed to filter for output
\"
%s
\"
[%s]"
,
name
,
plugin
.
name
);
Close
(
false
);
/* don't automatically reopen this device for 10
seconds */
fail_timer
.
Update
();
return
false
;
}
inline
bool
AudioOutput
::
PlayChunk
(
const
MusicChunk
&
chunk
)
AudioOutput
::
PlayChunk
()
{
if
(
tags
&&
gcc_unlikely
(
chunk
.
tag
!=
nullptr
))
{
const
ScopeUnlock
unlock
(
mutex
);
try
{
ao_plugin_send_tag
(
this
,
*
chunk
.
tag
);
}
catch
(
const
std
::
runtime_error
&
e
)
{
FormatError
(
e
,
"Failed to send tag to
\"
%s
\"
[%s]"
,
name
,
plugin
.
name
);
if
(
tags
)
{
const
auto
*
tag
=
source
.
ReadTag
();
if
(
tag
!=
nullptr
)
{
const
ScopeUnlock
unlock
(
mutex
);
try
{
ao_plugin_send_tag
(
this
,
*
tag
);
}
catch
(
const
std
::
runtime_error
&
e
)
{
FormatError
(
e
,
"Failed to send tag to
\"
%s
\"
[%s]"
,
name
,
plugin
.
name
);
}
}
}
ConstBuffer
<
uint8_t
>
data
;
try
{
data
=
data
.
FromVoid
(
source
.
FilterChunk
(
chunk
));
}
catch
(
const
std
::
runtime_error
&
e
)
{
FormatError
(
e
,
"Failed to filter for output
\"
%s
\"
[%s]"
,
name
,
plugin
.
name
);
Close
(
false
);
/* don't automatically reopen this device for 10
seconds */
fail_timer
.
Update
();
return
false
;
}
while
(
command
==
Command
::
NONE
)
{
const
auto
data
=
source
.
PeekData
();
if
(
data
.
IsEmpty
())
break
;
while
(
!
data
.
IsEmpty
()
&&
command
==
Command
::
NONE
)
{
if
(
!
WaitForDelay
())
break
;
...
...
@@ -319,7 +326,7 @@ AudioOutput::PlayChunk(const MusicChunk &chunk)
assert
(
nbytes
%
out_audio_format
.
GetFrameSize
()
==
0
);
data
.
skip_front
(
nbytes
);
source
.
ConsumeData
(
nbytes
);
}
return
true
;
...
...
@@ -328,8 +335,7 @@ AudioOutput::PlayChunk(const MusicChunk &chunk)
inline
bool
AudioOutput
::
Play
()
{
const
MusicChunk
*
chunk
=
source
.
Get
();
if
(
chunk
==
nullptr
)
if
(
!
FillSourceOrClose
())
/* no chunk available */
return
false
;
...
...
@@ -356,12 +362,9 @@ AudioOutput::Play()
n
=
0
;
}
if
(
!
PlayChunk
(
*
chunk
))
if
(
!
PlayChunk
())
break
;
source
.
Consume
(
*
chunk
);
chunk
=
source
.
Get
();
}
while
(
chunk
!=
nullptr
);
}
while
(
FillSourceOrClose
());
const
ScopeUnlock
unlock
(
mutex
);
client
->
ChunksConsumed
();
...
...
src/output/Source.cxx
View file @
86d3b25a
...
...
@@ -185,3 +185,38 @@ AudioOutputSource::FilterChunk(const MusicChunk &chunk)
return
filter_instance
->
FilterPCM
(
data
);
}
bool
AudioOutputSource
::
Fill
()
{
if
(
current_chunk
!=
nullptr
&&
pending_tag
==
nullptr
&&
pending_data
.
IsEmpty
())
pipe
.
Consume
(
*
std
::
exchange
(
current_chunk
,
nullptr
));
if
(
current_chunk
!=
nullptr
)
return
true
;
current_chunk
=
pipe
.
Get
();
if
(
current_chunk
==
nullptr
)
return
false
;
pending_tag
=
current_chunk
->
tag
;
try
{
pending_data
=
pending_data
.
FromVoid
(
FilterChunk
(
*
current_chunk
));
}
catch
(...)
{
current_chunk
=
nullptr
;
throw
;
}
return
true
;
}
void
AudioOutputSource
::
ConsumeData
(
size_t
nbytes
)
noexcept
{
pending_data
.
skip_front
(
nbytes
);
if
(
pending_data
.
IsEmpty
())
pipe
.
Consume
(
*
std
::
exchange
(
current_chunk
,
nullptr
));
}
src/output/Source.hxx
View file @
86d3b25a
...
...
@@ -27,11 +27,15 @@
#include "ReplayGainMode.hxx"
#include "pcm/PcmBuffer.hxx"
#include "pcm/PcmDither.hxx"
#include "util/ConstBuffer.hxx"
#include <utility>
#include <assert.h>
#include <stdint.h>
template
<
typename
T
>
struct
ConstBuffer
;
struct
MusicChunk
;
struct
Tag
;
class
Filter
;
class
PreparedFilter
;
...
...
@@ -96,6 +100,23 @@ class AudioOutputSource {
*/
Filter
*
filter_instance
=
nullptr
;
/**
* The #MusicChunk currently being processed (see
* #pending_tag, #pending_data).
*/
const
MusicChunk
*
current_chunk
=
nullptr
;
/**
* The #Tag to be processed by the #AudioOutput.
*/
const
Tag
*
pending_tag
;
/**
* Filtered #MusicChunk PCM data to be processed by the
* #AudioOutput.
*/
ConstBuffer
<
uint8_t
>
pending_data
;
public
:
void
SetReplayGainMode
(
ReplayGainMode
_mode
)
{
replay_gain_mode
=
_mode
;
...
...
@@ -117,21 +138,47 @@ public:
void
Close
();
void
Cancel
()
{
current_chunk
=
nullptr
;
pipe
.
Cancel
();
}
const
MusicChunk
*
Get
()
{
assert
(
IsOpen
());
/**
* Ensure that ReadTag() or PeekData() return any input.
*
* Throws std::runtime_error on error
*
* @return true if any input is available, false if the source
* has (temporarily?) run empty
*/
bool
Fill
();
return
pipe
.
Get
();
}
/**
* Reads the #Tag to be processed. Be sure to call Fill()
* successfully before calling this metohd.
*/
const
Tag
*
ReadTag
()
noexcept
{
assert
(
current_chunk
!=
nullptr
);
void
Consume
(
const
MusicChunk
&
chunk
)
{
assert
(
IsOpen
());
return
std
::
exchange
(
pending_tag
,
nullptr
);
}
pipe
.
Consume
(
chunk
);
/**
* Returns the remaining filtered PCM data be played. The
* caller shall use ConsumeData() to mark portions of the
* return value as "consumed".
*
* Be sure to call Fill() successfully before calling this
* metohd.
*/
ConstBuffer
<
void
>
PeekData
()
const
noexcept
{
return
pending_data
.
ToVoid
();
}
/**
* Mark portions of the PeekData() return value as "consumed".
*/
void
ConsumeData
(
size_t
nbytes
)
noexcept
;
bool
IsChunkConsumed
(
const
MusicChunk
&
chunk
)
const
{
assert
(
IsOpen
());
...
...
@@ -142,8 +189,6 @@ public:
pipe
.
ClearTail
(
chunk
);
}
ConstBuffer
<
void
>
FilterChunk
(
const
MusicChunk
&
chunk
);
private
:
void
OpenFilter
(
AudioFormat
audio_format
,
PreparedFilter
*
prepared_replay_gain_filter
,
...
...
@@ -155,6 +200,8 @@ private:
ConstBuffer
<
void
>
GetChunkData
(
const
MusicChunk
&
chunk
,
Filter
*
replay_gain_filter
,
unsigned
*
replay_gain_serial_p
);
ConstBuffer
<
void
>
FilterChunk
(
const
MusicChunk
&
chunk
);
};
#endif
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