OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef CONTENT_RENDERER_MEDIA_MEDIA_STREAM_AUDIO_DELIVERER_H_ | |
6 #define CONTENT_RENDERER_MEDIA_MEDIA_STREAM_AUDIO_DELIVERER_H_ | |
7 | |
8 #include <algorithm> | |
9 #include <vector> | |
10 | |
11 #include "base/synchronization/lock.h" | |
12 #include "base/threading/thread_checker.h" | |
13 #include "media/audio/audio_parameters.h" | |
14 | |
15 namespace content { | |
16 | |
17 // Template containing functionality common to both MediaStreamAudioSource and | |
18 // MediaStreamAudioTrack. This is used for managing the connections between | |
19 // objects through which audio data flows, and doing so in a thread-safe manner. | |
20 // | |
21 // The Consumer parameter of the template is the type of the objects to which | |
22 // audio data is delivered: MediaStreamAudioTrack or MediaStreamAudioSink. It's | |
23 // assumed the Consumer class defines methods named OnSetFormat() and OnData() | |
24 // that have the same signature as the ones defined in this template. | |
25 // MediaStreamAudioDeliverer will always guarantee the Consumer's OnSetFormat() | |
26 // and OnData() methods are called sequentially. | |
27 template <typename Consumer> | |
28 class MediaStreamAudioDeliverer { | |
29 public: | |
30 MediaStreamAudioDeliverer() {} | |
31 ~MediaStreamAudioDeliverer() {} | |
32 | |
33 // Returns the current audio parameters. These will be invalid before the | |
34 // first call to OnSetFormat(). This method is thread-safe. | |
35 media::AudioParameters GetAudioParameters() const { | |
36 base::AutoLock auto_lock(params_lock_); | |
37 return params_; | |
38 } | |
39 | |
40 // Begin delivering audio to |consumer|. The caller must guarantee |consumer| | |
perkj_chrome
2016/04/20 13:34:54
nit: Remove extra space
miu
2016/04/20 22:04:52
Done.
| |
41 // is not destroyed until after calling RemoveConsumer(consumer). This method | |
42 // must be called on the main thread. | |
43 void AddConsumer(Consumer* consumer) { | |
44 DCHECK(thread_checker_.CalledOnValidThread()); | |
45 DCHECK(consumer); | |
46 base::AutoLock auto_lock(consumers_lock_); | |
47 DCHECK(std::find(consumers_.begin(), consumers_.end(), consumer) == | |
48 consumers_.end()); | |
49 DCHECK(std::find(pending_consumers_.begin(), pending_consumers_.end(), | |
50 consumer) == pending_consumers_.end()); | |
51 pending_consumers_.push_back(consumer); | |
52 } | |
53 | |
54 // Stop delivering audio to |consumer|. Returns true if |consumer| was the | |
55 // last consumer removed, false otherwise. When this method returns, no | |
56 // further calls will be made to OnSetFormat() or OnData() on any thread. | |
57 // This method must be called on the main thread. | |
58 bool RemoveConsumer(Consumer* consumer) { | |
59 DCHECK(thread_checker_.CalledOnValidThread()); | |
60 base::AutoLock auto_lock(consumers_lock_); | |
61 const bool had_consumers = | |
62 !consumers_.empty() || !pending_consumers_.empty(); | |
63 auto it = std::find(consumers_.begin(), consumers_.end(), consumer); | |
64 if (it != consumers_.end()) { | |
65 consumers_.erase(it); | |
66 } else { | |
67 it = std::find(pending_consumers_.begin(), pending_consumers_.end(), | |
68 consumer); | |
69 if (it != pending_consumers_.end()) | |
70 pending_consumers_.erase(it); | |
71 } | |
72 return had_consumers && consumers_.empty() && pending_consumers_.empty(); | |
73 } | |
74 | |
75 // Returns the current list of connected Consumers. This is normally used to | |
76 // send a notification to all consumers. This method must be called on the | |
77 // main thread. | |
78 void GetConsumerList(std::vector<Consumer*>* consumer_list) const { | |
79 DCHECK(thread_checker_.CalledOnValidThread()); | |
80 base::AutoLock auto_lock(consumers_lock_); | |
81 *consumer_list = consumers_; | |
82 consumer_list->insert(consumer_list->end(), | |
83 pending_consumers_.begin(), pending_consumers_.end()); | |
84 } | |
85 | |
86 // Change the format of the audio passed in the next call to OnData(). This | |
87 // method may be called on any thread but, logically, should only be called | |
88 // between calls to OnData(). | |
89 void OnSetFormat(const media::AudioParameters& params) { | |
90 DCHECK(params.IsValid()); | |
91 base::AutoLock auto_lock(consumers_lock_); | |
92 { | |
93 base::AutoLock auto_params_lock(params_lock_); | |
94 if (params_.Equals(params)) | |
95 return; | |
96 params_ = params; | |
97 } | |
98 pending_consumers_.insert(pending_consumers_.end(), | |
99 consumers_.begin(), consumers_.end()); | |
100 consumers_.clear(); | |
101 } | |
102 | |
103 // Deliver data to all consumers. This method may be called on any thread. | |
104 void OnData(const media::AudioBus& audio_bus, | |
105 base::TimeTicks reference_time) { | |
106 base::AutoLock auto_lock(consumers_lock_); | |
107 | |
108 // Call OnSetFormat() for all pending consumers and move them to the | |
109 // active-delivery list. | |
110 if (!pending_consumers_.empty()) { | |
111 const media::AudioParameters params = GetAudioParameters(); | |
112 DCHECK(params.IsValid()); | |
113 for (Consumer* consumer : pending_consumers_) | |
114 consumer->OnSetFormat(params); | |
115 consumers_.insert(consumers_.end(), | |
116 pending_consumers_.begin(), pending_consumers_.end()); | |
117 pending_consumers_.clear(); | |
118 } | |
119 | |
120 // Deliver the audio data to each consumer. | |
121 for (Consumer* consumer : consumers_) | |
122 consumer->OnData(audio_bus, reference_time); | |
123 } | |
124 | |
125 private: | |
126 // In debug builds, check that all methods that could cause object graph or | |
127 // data flow changes are being called on the main thread. | |
128 base::ThreadChecker thread_checker_; | |
129 | |
130 // Protects concurrent access to |pending_consumers_| and |consumers_|. | |
131 mutable base::Lock consumers_lock_; | |
132 | |
133 // Any consumers needing a call to OnSetFormat(), to be notified of the | |
134 // changed audio format, are placed in this list. This includes consumers | |
perkj_chrome
2016/04/20 13:34:53
nit: remove extra space
miu
2016/04/20 22:04:52
Done.
| |
135 // added via AddConsumer() that need to have an initial OnSetFormat() call | |
136 // before audio data is first delivered. Consumers are moved from this list | |
perkj_chrome
2016/04/20 13:34:54
dito
miu
2016/04/20 22:04:52
Done.
| |
137 // to |consumers_| on the audio thread. | |
138 std::vector<Consumer*> pending_consumers_; | |
139 | |
140 // Consumers that are up-to-date on the current audio format and are receiving | |
141 // audio data are placed in this list. | |
142 std::vector<Consumer*> consumers_; | |
143 | |
144 // Protects concurrent access to |params_|. | |
145 mutable base::Lock params_lock_; | |
146 | |
147 // Specifies the current format of the audio passing through this | |
148 // MediaStreamAudioDeliverer. | |
149 media::AudioParameters params_; | |
150 | |
151 DISALLOW_COPY_AND_ASSIGN(MediaStreamAudioDeliverer); | |
152 }; | |
153 | |
154 } // namespace content | |
155 | |
156 #endif // CONTENT_RENDERER_MEDIA_MEDIA_STREAM_AUDIO_DELIVERER_H_ | |
OLD | NEW |