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

Unified Diff: content/renderer/media/media_stream_audio_deliverer.h

Issue 1834323002: MediaStream audio: Refactor 3 separate "glue" implementations into one. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: REBASE + Workaround to ensure MediaStreamAudioProcessor is destroyed on the main thread. Created 4 years, 7 months 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: content/renderer/media/media_stream_audio_deliverer.h
diff --git a/content/renderer/media/media_stream_audio_deliverer.h b/content/renderer/media/media_stream_audio_deliverer.h
new file mode 100644
index 0000000000000000000000000000000000000000..80a6a1c419382d8115d40e85d7ef8b9d7af8fc92
--- /dev/null
+++ b/content/renderer/media/media_stream_audio_deliverer.h
@@ -0,0 +1,156 @@
+// Copyright 2016 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.
+
+#ifndef CONTENT_RENDERER_MEDIA_MEDIA_STREAM_AUDIO_DELIVERER_H_
+#define CONTENT_RENDERER_MEDIA_MEDIA_STREAM_AUDIO_DELIVERER_H_
+
+#include <algorithm>
+#include <vector>
+
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "media/base/audio_parameters.h"
+
+namespace content {
+
+// Template containing functionality common to both MediaStreamAudioSource and
+// MediaStreamAudioTrack. This is used for managing the connections between
+// objects through which audio data flows, and doing so in a thread-safe manner.
+//
+// The Consumer parameter of the template is the type of the objects to which
+// audio data is delivered: MediaStreamAudioTrack or MediaStreamAudioSink. It's
+// assumed the Consumer class defines methods named OnSetFormat() and OnData()
+// that have the same signature as the ones defined in this template.
+// MediaStreamAudioDeliverer will always guarantee the Consumer's OnSetFormat()
+// and OnData() methods are called sequentially.
+template <typename Consumer>
+class MediaStreamAudioDeliverer {
+ public:
+ MediaStreamAudioDeliverer() {}
+ ~MediaStreamAudioDeliverer() {}
+
+ // Returns the current audio parameters. These will be invalid before the
+ // first call to OnSetFormat(). This method is thread-safe.
+ media::AudioParameters GetAudioParameters() const {
+ base::AutoLock auto_lock(params_lock_);
+ return params_;
+ }
+
+ // Begin delivering audio to |consumer|. The caller must guarantee |consumer|
+ // is not destroyed until after calling RemoveConsumer(consumer). This method
+ // must be called on the main thread.
+ void AddConsumer(Consumer* consumer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(consumer);
+ base::AutoLock auto_lock(consumers_lock_);
+ DCHECK(std::find(consumers_.begin(), consumers_.end(), consumer) ==
+ consumers_.end());
+ DCHECK(std::find(pending_consumers_.begin(), pending_consumers_.end(),
+ consumer) == pending_consumers_.end());
+ pending_consumers_.push_back(consumer);
+ }
+
+ // Stop delivering audio to |consumer|. Returns true if |consumer| was the
+ // last consumer removed, false otherwise. When this method returns, no
+ // further calls will be made to OnSetFormat() or OnData() on any thread.
+ // This method must be called on the main thread.
+ bool RemoveConsumer(Consumer* consumer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ base::AutoLock auto_lock(consumers_lock_);
+ const bool had_consumers =
+ !consumers_.empty() || !pending_consumers_.empty();
+ auto it = std::find(consumers_.begin(), consumers_.end(), consumer);
+ if (it != consumers_.end()) {
+ consumers_.erase(it);
+ } else {
+ it = std::find(pending_consumers_.begin(), pending_consumers_.end(),
+ consumer);
+ if (it != pending_consumers_.end())
+ pending_consumers_.erase(it);
+ }
+ return had_consumers && consumers_.empty() && pending_consumers_.empty();
+ }
+
+ // Returns the current list of connected Consumers. This is normally used to
+ // send a notification to all consumers. This method must be called on the
+ // main thread.
+ void GetConsumerList(std::vector<Consumer*>* consumer_list) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ base::AutoLock auto_lock(consumers_lock_);
+ *consumer_list = consumers_;
+ consumer_list->insert(consumer_list->end(),
+ pending_consumers_.begin(), pending_consumers_.end());
+ }
+
+ // Change the format of the audio passed in the next call to OnData(). This
+ // method may be called on any thread but, logically, should only be called
+ // between calls to OnData().
+ void OnSetFormat(const media::AudioParameters& params) {
+ DCHECK(params.IsValid());
+ base::AutoLock auto_lock(consumers_lock_);
+ {
+ base::AutoLock auto_params_lock(params_lock_);
+ if (params_.Equals(params))
+ return;
+ params_ = params;
+ }
+ pending_consumers_.insert(pending_consumers_.end(),
+ consumers_.begin(), consumers_.end());
+ consumers_.clear();
+ }
+
+ // Deliver data to all consumers. This method may be called on any thread.
+ void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks reference_time) {
+ base::AutoLock auto_lock(consumers_lock_);
+
+ // Call OnSetFormat() for all pending consumers and move them to the
+ // active-delivery list.
+ if (!pending_consumers_.empty()) {
+ const media::AudioParameters params = GetAudioParameters();
+ DCHECK(params.IsValid());
+ for (Consumer* consumer : pending_consumers_)
+ consumer->OnSetFormat(params);
+ consumers_.insert(consumers_.end(),
+ pending_consumers_.begin(), pending_consumers_.end());
+ pending_consumers_.clear();
+ }
+
+ // Deliver the audio data to each consumer.
+ for (Consumer* consumer : consumers_)
+ consumer->OnData(audio_bus, reference_time);
+ }
+
+ private:
+ // In debug builds, check that all methods that could cause object graph or
+ // data flow changes are being called on the main thread.
+ base::ThreadChecker thread_checker_;
+
+ // Protects concurrent access to |pending_consumers_| and |consumers_|.
+ mutable base::Lock consumers_lock_;
+
+ // Any consumers needing a call to OnSetFormat(), to be notified of the
+ // changed audio format, are placed in this list. This includes consumers
+ // added via AddConsumer() that need to have an initial OnSetFormat() call
+ // before audio data is first delivered. Consumers are moved from this list to
+ // |consumers_| on the audio thread.
+ std::vector<Consumer*> pending_consumers_;
+
+ // Consumers that are up-to-date on the current audio format and are receiving
+ // audio data are placed in this list.
+ std::vector<Consumer*> consumers_;
+
+ // Protects concurrent access to |params_|.
+ mutable base::Lock params_lock_;
+
+ // Specifies the current format of the audio passing through this
+ // MediaStreamAudioDeliverer.
+ media::AudioParameters params_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaStreamAudioDeliverer);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MEDIA_MEDIA_STREAM_AUDIO_DELIVERER_H_
« no previous file with comments | « content/renderer/media/external_media_stream_audio_source.cc ('k') | content/renderer/media/media_stream_audio_processor.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698