Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(605)

Unified Diff: services/media/audio/audio_track_to_output_link.cc

Issue 1424933002: Add an initial revision of an audio server. (Closed) Base URL: https://github.com/domokit/mojo.git@change4
Patch Set: refactor MixerKernel into a class to prepare for the addition of a linear interpolation sampler Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: services/media/audio/audio_track_to_output_link.cc
diff --git a/services/media/audio/audio_track_to_output_link.cc b/services/media/audio/audio_track_to_output_link.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9d400421fece47f648367d0b2299a316a4520e50
--- /dev/null
+++ b/services/media/audio/audio_track_to_output_link.cc
@@ -0,0 +1,144 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "services/media/audio/audio_track_to_output_link.h"
+
+namespace mojo {
+namespace media {
+namespace audio {
+
+AudioTrackToOutputLink::Bookkeeping::~Bookkeeping() {}
+
+AudioTrackToOutputLink::AudioTrackToOutputLink(AudioTrackImplWeakPtr track,
+ AudioOutputWeakPtr output)
+ : track_(track),
+ output_(output),
+ pending_queue_(new PacketQueue) {
+#if !(defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON))
+ flush_lock_held_ = false;
+#endif
+}
+
+AudioTrackToOutputLink::~AudioTrackToOutputLink() {
+ ReleaseQueue(pending_queue_);
+}
+
+AudioTrackToOutputLinkPtr AudioTrackToOutputLink::New(
+ AudioTrackImplWeakPtr track,
+ AudioOutputWeakPtr output) {
+ return AudioTrackToOutputLinkPtr(new AudioTrackToOutputLink(track, output));
+}
+
+void AudioTrackToOutputLink::PushToPendingQueue(
+ const AudioPipe::AudioPacketRefPtr& pkt) {
+ base::AutoLock lock(pending_queue_lock_);
+ pending_queue_->emplace_back(pkt);
+}
+
+void AudioTrackToOutputLink::FlushPendingQueue() {
+ // Create a new (empty) queue before obtaining any locks. This will allow us
+ // to quickly swap the empty queue for the current queue and get out of all
+ // the locks, and then release the packets at our leisure instead of
+ // potentially holding off a high priority mixing thread while releasing
+ // packets.
+ //
+ // Note: the safety of this technique depends on Flush only ever being called
+ // from the AudioTrack, and the AudioTrack's actions being serialized on the
+ // AudioServer's message loop thread. If multiple flushes are allowed to be
+ // invoked simultaniously, or if a packet is permitted to be added to the
+ // queue while a flush operation is in progress, it is possible to return
+ // packets to the user in an order different than the one that they were
+ // queued in.
jeffbrown 2015/11/04 23:43:34 FWIW, we might actually find it worthwhile to push
johngro 2015/11/06 02:20:26 As discussed F2F yesterday, this will add a ton of
+ PacketQueuePtr new_queue(new PacketQueue);
+
+ {
+ base::AutoLock lock(flush_lock_);
+ {
+ // TODO(johngro): Assuming that it is impossible to push a new packet
+ // while a flush is in progress, it's pretty easy to show that this lock
+ // can never be contended. Because of this, we could consider removing
+ // this lock operation (although, flush is a relatively rare operation, so
+ // the extra overhead is pretty insignificant.
+ base::AutoLock lock(pending_queue_lock_);
+ pending_queue_.swap(new_queue);
+ }
+ flushed_ = true;
+ }
+
+ ReleaseQueue(new_queue);
+}
+
+AudioPipe::AudioPacketRefPtr AudioTrackToOutputLink::LockPendingQueueFront(
+ bool* was_flushed) {
+#if !(defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON))
+ // No one had better be holding the flush lock right now. If someone is, then
+ // we either have multiple threads hitting this operation at the same time
+ // (should be impossible), or an audio output forgot to unlock the front of
+ // the queue before attempting to lock it again.
+ bool was_held = false;
+ flush_lock_held_.compare_exchange_strong(was_held, true);
+ DCHECK(!was_held);
+#endif
+ flush_lock_.Acquire();
+
+ DCHECK(was_flushed);
+ *was_flushed = flushed_;
+ flushed_ = false;
+
+ {
+ base::AutoLock lock(pending_queue_lock_);
+ if (pending_queue_->size()) {
+ return pending_queue_->front();
+ } else {
+ return nullptr;
+ }
+ }
+}
+
+void AudioTrackToOutputLink::UnlockPendingQueueFront(
+ AudioPipe::AudioPacketRefPtr* pkt,
+ bool release_packet) {
+ {
+ base::AutoLock lock(pending_queue_lock_);
+
+ // Assert that the user either got no packet when they locked the queue
+ // (because the queue was empty), or that they got the front of the queue
+ // and that the front of the queue has not changed.
+ DCHECK(pkt);
+ DCHECK((*pkt == nullptr) ||
+ (pending_queue_->size() && (*pkt == pending_queue_->front())));
+
+ if (*pkt) {
+ *pkt = nullptr;
+ if (release_packet) {
+ pending_queue_->pop_front();
+ }
+ }
+ }
+
+ flush_lock_.Release();
+#if !(defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON))
+ bool was_held = true;
+ flush_lock_held_.compare_exchange_strong(was_held, false);
+ DCHECK(was_held);
+#endif
+}
+
+void AudioTrackToOutputLink::ReleaseQueue(const PacketQueuePtr& queue) {
+ if (!queue) {
+ return;
+ }
+
+ for (auto iter = queue->begin(); iter != queue->end(); ++iter) {
+ (*iter).reset();
+ }
+
+ queue->clear();
+}
+
+} // namespace audio
+} // namespace media
+} // namespace mojo
+

Powered by Google App Engine
This is Rietveld 408576698