summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2018-08-04 00:01:30 +0100
committerCarl Hetherington <cth@carlh.net>2018-08-04 00:01:30 +0100
commit54e6f206305d4275808cfce36987edcc61a6a779 (patch)
treeba403ce56da8c5ce5a4a1652e83bd18855a41c01 /src/lib
parent4fe1a062eb31d680b8b4ac0191b9e2fc2d6aaec3 (diff)
Timestamp audio emissions from butler and hence discard very late
audio in FilmViewer. This should help with the case where lots of video frames are rapidly discarded when they are late but the corresponding audio is not, hence audio buffers get overfilled.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/audio_ring_buffers.cc42
-rw-r--r--src/lib/audio_ring_buffers.h6
-rw-r--r--src/lib/butler.cc14
-rw-r--r--src/lib/butler.h4
4 files changed, 38 insertions, 28 deletions
diff --git a/src/lib/audio_ring_buffers.cc b/src/lib/audio_ring_buffers.cc
index 42115efa3..f51ff8a38 100644
--- a/src/lib/audio_ring_buffers.cc
+++ b/src/lib/audio_ring_buffers.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2016-2017 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2016-2018 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
@@ -26,7 +26,11 @@
using std::min;
using std::cout;
+using std::make_pair;
+using std::pair;
+using std::list;
using boost::shared_ptr;
+using boost::optional;
AudioRingBuffers::AudioRingBuffers ()
: _used_in_head (0)
@@ -35,23 +39,26 @@ AudioRingBuffers::AudioRingBuffers ()
}
void
-AudioRingBuffers::put (shared_ptr<const AudioBuffers> data)
+AudioRingBuffers::put (shared_ptr<const AudioBuffers> data, DCPTime time)
{
boost::mutex::scoped_lock lm (_mutex);
- if (!_buffers.empty ()) {
- DCPOMATIC_ASSERT (_buffers.front()->channels() == data->channels());
+ if (!_buffers.empty()) {
+ DCPOMATIC_ASSERT (_buffers.front().first->channels() == data->channels());
+ DCPOMATIC_ASSERT ((_buffers.back().second + DCPTime::from_frames(_buffers.back().first->frames(), 48000)) == time);
}
- _buffers.push_back (data);
+ _buffers.push_back(make_pair(data, time));
}
-/** @return true if there was an underrun, otherwise false */
-bool
+/** @return time of the returned data; if it's not set this indicates an underrun */
+optional<DCPTime>
AudioRingBuffers::get (float* out, int channels, int frames)
{
boost::mutex::scoped_lock lm (_mutex);
+ optional<DCPTime> time;
+
while (frames > 0) {
if (_buffers.empty ()) {
for (int i = 0; i < frames; ++i) {
@@ -60,14 +67,17 @@ AudioRingBuffers::get (float* out, int channels, int frames)
}
}
cout << "audio underrun; missing " << frames << "!\n";
- return true;
+ return time;
}
- shared_ptr<const AudioBuffers> front = _buffers.front ();
+ pair<shared_ptr<const AudioBuffers>, DCPTime> front = _buffers.front ();
+ if (!time) {
+ time = front.second + DCPTime::from_frames(_used_in_head, 48000);
+ }
- int const to_do = min (frames, front->frames() - _used_in_head);
- float** p = front->data();
- int const c = min (front->channels(), channels);
+ int const to_do = min (frames, front.first->frames() - _used_in_head);
+ float** p = front.first->data();
+ int const c = min (front.first->channels(), channels);
for (int i = 0; i < to_do; ++i) {
for (int j = 0; j < c; ++j) {
*out++ = p[j][i + _used_in_head];
@@ -79,13 +89,13 @@ AudioRingBuffers::get (float* out, int channels, int frames)
_used_in_head += to_do;
frames -= to_do;
- if (_used_in_head == front->frames()) {
+ if (_used_in_head == front.first->frames()) {
_buffers.pop_front ();
_used_in_head = 0;
}
}
- return false;
+ return time;
}
void
@@ -101,8 +111,8 @@ AudioRingBuffers::size () const
{
boost::mutex::scoped_lock lm (_mutex);
Frame s = 0;
- BOOST_FOREACH (shared_ptr<const AudioBuffers> i, _buffers) {
- s += i->frames ();
+ for (list<pair<shared_ptr<const AudioBuffers>, DCPTime> >::const_iterator i = _buffers.begin(); i != _buffers.end(); ++i) {
+ s += i->first->frames();
}
return s - _used_in_head;
}
diff --git a/src/lib/audio_ring_buffers.h b/src/lib/audio_ring_buffers.h
index 3c726425c..53236cb32 100644
--- a/src/lib/audio_ring_buffers.h
+++ b/src/lib/audio_ring_buffers.h
@@ -33,15 +33,15 @@ class AudioRingBuffers : public boost::noncopyable
public:
AudioRingBuffers ();
- void put (boost::shared_ptr<const AudioBuffers> data);
- bool get (float* out, int channels, int frames);
+ void put (boost::shared_ptr<const AudioBuffers> data, DCPTime time);
+ boost::optional<DCPTime> get (float* out, int channels, int frames);
void clear ();
Frame size () const;
private:
mutable boost::mutex _mutex;
- std::list<boost::shared_ptr<const AudioBuffers> > _buffers;
+ std::list<std::pair<boost::shared_ptr<const AudioBuffers>, DCPTime> > _buffers;
int _used_in_head;
};
diff --git a/src/lib/butler.cc b/src/lib/butler.cc
index 63fe729ae..aee584654 100644
--- a/src/lib/butler.cc
+++ b/src/lib/butler.cc
@@ -62,7 +62,7 @@ Butler::Butler (shared_ptr<Player> player, shared_ptr<Log> log, AudioMapping aud
, _disable_audio (false)
{
_player_video_connection = _player->Video.connect (bind (&Butler::video, this, _1, _2));
- _player_audio_connection = _player->Audio.connect (bind (&Butler::audio, this, _1));
+ _player_audio_connection = _player->Audio.connect (bind (&Butler::audio, this, _1, _2));
_player_changed_connection = _player->Changed.connect (bind (&Butler::player_changed, this, _1));
_thread = new boost::thread (bind (&Butler::thread, this));
#ifdef DCPOMATIC_LINUX
@@ -258,7 +258,7 @@ Butler::video (shared_ptr<PlayerVideo> video, DCPTime time)
}
void
-Butler::audio (shared_ptr<AudioBuffers> audio)
+Butler::audio (shared_ptr<AudioBuffers> audio, DCPTime time)
{
{
boost::mutex::scoped_lock lm (_mutex);
@@ -269,19 +269,19 @@ Butler::audio (shared_ptr<AudioBuffers> audio)
}
boost::mutex::scoped_lock lm2 (_video_audio_mutex);
- _audio.put (remap (audio, _audio_channels, _audio_mapping));
+ _audio.put (remap (audio, _audio_channels, _audio_mapping), time);
}
/** Try to get `frames' frames of audio and copy it into `out'. Silence
* will be filled if no audio is available.
- * @return true if there was a buffer underrun, otherwise false.
+ * @return time of this audio, or unset if there was a buffer underrun.
*/
-bool
+optional<DCPTime>
Butler::get_audio (float* out, Frame frames)
{
- bool const underrun = _audio.get (out, _audio_channels, frames);
+ optional<DCPTime> t = _audio.get (out, _audio_channels, frames);
_summon.notify_all ();
- return underrun;
+ return t;
}
void
diff --git a/src/lib/butler.h b/src/lib/butler.h
index a8b38ef2e..e6553cf8c 100644
--- a/src/lib/butler.h
+++ b/src/lib/butler.h
@@ -41,7 +41,7 @@ public:
void seek (DCPTime position, bool accurate);
std::pair<boost::shared_ptr<PlayerVideo>, DCPTime> get_video ();
- bool get_audio (float* out, Frame frames);
+ boost::optional<DCPTime> get_audio (float* out, Frame frames);
void disable_audio ();
@@ -50,7 +50,7 @@ public:
private:
void thread ();
void video (boost::shared_ptr<PlayerVideo> video, DCPTime time);
- void audio (boost::shared_ptr<AudioBuffers> audio);
+ void audio (boost::shared_ptr<AudioBuffers> audio, DCPTime time);
bool should_run () const;
void prepare (boost::weak_ptr<PlayerVideo> video) const;
void player_changed (int);