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

Side by Side Diff: content/browser/media/media_internals.cc

Issue 68173025: Introduce new interface for MediaInternals updates. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add impl. Maintain sanity? Created 7 years 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/media/media_internals.h" 5 #include "content/browser/media/media_internals.h"
6 6
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/string16.h" 7 #include "base/strings/string16.h"
9 #include "base/strings/stringprintf.h" 8 #include "base/strings/stringprintf.h"
10 #include "content/public/browser/browser_thread.h" 9 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/web_ui.h" 10 #include "content/public/browser/web_ui.h"
12 #include "media/audio/audio_parameters.h" 11 #include "media/audio/audio_parameters.h"
13 #include "media/base/media_log.h" 12 #include "media/base/media_log.h"
14 #include "media/base/media_log_event.h" 13 #include "media/base/media_log_event.h"
15 14
15 namespace {
16
17 static base::LazyInstance<content::MediaInternals>::Leaky g_media_internals =
18 LAZY_INSTANCE_INITIALIZER;
19
20 string16 SerializeUpdate(const std::string& function,
21 const base::Value* value) {
22 return content::WebUI::GetJavascriptCall(
23 function, std::vector<const base::Value*>(1, value));
24 }
25
26 const char kAudioLogStatusKey[] = "status";
27 const char kAudioLogUpdateFunction[] = "media.updateAudioComponent";
28
29 } // namespace
30
16 namespace content { 31 namespace content {
17 32
18 MediaInternals* MediaInternals::GetInstance() { 33 class AudioLogImpl : public media::AudioLog {
19 return Singleton<MediaInternals>::get(); 34 public:
35 AudioLogImpl(int owner_id,
36 media::AudioLogFactory::AudioComponent component,
37 content::MediaInternals* media_internals);
38 virtual ~AudioLogImpl();
39
40 virtual void OnCreated(int component_id,
41 const media::AudioParameters& params,
42 const std::string& input_device_id,
43 const std::string& output_device_id) OVERRIDE;
44 virtual void OnStarted(int component_id) OVERRIDE;
45 virtual void OnStopped(int component_id) OVERRIDE;
46 virtual void OnClosed(int component_id) OVERRIDE;
47 virtual void OnError(int component_id) OVERRIDE;
48 virtual void OnSetVolume(int component_id, double volume) OVERRIDE;
49
50 private:
51 void SendSingleStringUpdate(int component_id,
52 const std::string& key,
53 const std::string& value,
54 bool purge_cache);
55 void StoreComponentMetadata(int component_id, base::DictionaryValue* dict);
56 std::string FormatCacheKey(int component_id);
57
58 const int owner_id_;
59 const media::AudioLogFactory::AudioComponent component_;
60 content::MediaInternals* const media_internals_;
61
62 DISALLOW_COPY_AND_ASSIGN(AudioLogImpl);
63 };
64
65 AudioLogImpl::AudioLogImpl(int owner_id,
66 media::AudioLogFactory::AudioComponent component,
67 content::MediaInternals* media_internals)
68 : owner_id_(owner_id),
69 component_(component),
70 media_internals_(media_internals) {}
71
72 AudioLogImpl::~AudioLogImpl() {}
73
74 void AudioLogImpl::OnCreated(int component_id,
75 const media::AudioParameters& params,
76 const std::string& input_device_id,
77 const std::string& output_device_id) {
78 base::DictionaryValue dict;
79 StoreComponentMetadata(component_id, &dict);
80
81 dict.SetString(kAudioLogStatusKey, "created");
82 dict.SetString("input_device_id", input_device_id);
83 dict.SetInteger("input_channels", params.input_channels());
84 dict.SetInteger("frames_per_buffer", params.frames_per_buffer());
85 dict.SetInteger("sample_rate", params.sample_rate());
86 dict.SetString("output_device_id", output_device_id);
87 dict.SetInteger("output_channels", params.channels());
88 dict.SetString("output_channel_layout",
89 ChannelLayoutToString(params.channel_layout()));
90
91 media_internals_->SendUpdateAndCache(
92 FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
20 } 93 }
21 94
22 MediaInternals::~MediaInternals() {} 95 void AudioLogImpl::OnStarted(int component_id) {
23 96 SendSingleStringUpdate(component_id, kAudioLogStatusKey, "started", false);
24 namespace {
25 std::string FormatAudioStreamName(void* host, int stream_id) {
26 return base::StringPrintf("audio_streams.%p:%d", host, stream_id);
27 }
28 } 97 }
29 98
30 void MediaInternals::OnDeleteAudioStream(void* host, int stream_id) { 99 void AudioLogImpl::OnStopped(int component_id) {
31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 100 SendSingleStringUpdate(component_id, kAudioLogStatusKey, "stopped", false);
32 DeleteItem(FormatAudioStreamName(host, stream_id));
33 } 101 }
34 102
35 void MediaInternals::OnSetAudioStreamPlaying( 103 void AudioLogImpl::OnClosed(int component_id) {
36 void* host, int stream_id, bool playing) { 104 SendSingleStringUpdate(component_id, kAudioLogStatusKey, "closed", true);
acolwell GONE FROM CHROMIUM 2013/11/22 21:01:21 Since this is the only instance where purge_cache
DaleCurtis 2013/11/22 21:16:03 Fair enough, I originally had it that way, but it
37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
38 UpdateAudioStream(host, stream_id,
39 "playing", new base::FundamentalValue(playing));
40 } 105 }
41 106
42 void MediaInternals::OnAudioStreamCreated(void* host, 107 void AudioLogImpl::OnError(int component_id) {
43 int stream_id, 108 SendSingleStringUpdate(component_id, "error_occurred", "true", false);
44 const media::AudioParameters& params,
45 const std::string& input_device_id) {
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
47
48 StoreAudioStream(host,
49 stream_id,
50 "input_device_id",
51 Value::CreateStringValue(input_device_id));
52
53 StoreAudioStream(
54 host, stream_id, "status", Value::CreateStringValue("created"));
55
56 StoreAudioStream(
57 host, stream_id, "stream_id", Value::CreateIntegerValue(stream_id));
58
59 StoreAudioStream(host,
60 stream_id,
61 "input_channels",
62 Value::CreateIntegerValue(params.input_channels()));
63
64 StoreAudioStream(host,
65 stream_id,
66 "frames_per_buffer",
67 Value::CreateIntegerValue(params.frames_per_buffer()));
68
69 StoreAudioStream(host,
70 stream_id,
71 "sample_rate",
72 Value::CreateIntegerValue(params.sample_rate()));
73
74 StoreAudioStream(host,
75 stream_id,
76 "output_channels",
77 Value::CreateIntegerValue(params.channels()));
78
79 StoreAudioStream(
80 host,
81 stream_id,
82 "channel_layout",
83 Value::CreateStringValue(ChannelLayoutToString(params.channel_layout())));
84
85 SendEverything();
86 } 109 }
87 110
88 void MediaInternals::OnSetAudioStreamStatus(void* host, 111 void AudioLogImpl::OnSetVolume(int component_id, double volume) {
89 int stream_id, 112 base::DictionaryValue dict;
90 const std::string& status) { 113 StoreComponentMetadata(component_id, &dict);
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 114 dict.SetDouble("volume", volume);
92 UpdateAudioStream(host, stream_id, 115 media_internals_->SendUpdateAndCache(
93 "status", new base::StringValue(status)); 116 FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
94 } 117 }
95 118
96 void MediaInternals::OnSetAudioStreamVolume( 119 std::string AudioLogImpl::FormatCacheKey(int component_id) {
97 void* host, int stream_id, double volume) { 120 return base::StringPrintf("%d:%d", owner_id_, component_id);
98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
99 UpdateAudioStream(host, stream_id,
100 "volume", new base::FundamentalValue(volume));
101 } 121 }
102 122
123 void AudioLogImpl::SendSingleStringUpdate(int component_id,
124 const std::string& key,
125 const std::string& value,
126 bool purge_cache) {
127 base::DictionaryValue dict;
128 StoreComponentMetadata(component_id, &dict);
129 dict.SetString(key, value);
130
131 if (purge_cache) {
132 media_internals_->SendUpdateAndPurgeCache(
133 FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
134 } else {
135 media_internals_->SendUpdateAndCache(
136 FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
137 }
138 }
139
140 void AudioLogImpl::StoreComponentMetadata(int component_id,
141 base::DictionaryValue* dict) {
142 dict->SetInteger("owner_id", owner_id_);
143 dict->SetInteger("component_id", component_id);
144 dict->SetInteger("component_type", component_);
145 }
146
147 MediaInternals* MediaInternals::GetInstance() {
148 return g_media_internals.Pointer();
149 }
150
151 MediaInternals::MediaInternals() : owner_ids_() {}
152 MediaInternals::~MediaInternals() {}
153
103 void MediaInternals::OnMediaEvents( 154 void MediaInternals::OnMediaEvents(
104 int render_process_id, const std::vector<media::MediaLogEvent>& events) { 155 int render_process_id, const std::vector<media::MediaLogEvent>& events) {
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
106
107 // Notify observers that |event| has occured. 157 // Notify observers that |event| has occured.
108 for (std::vector<media::MediaLogEvent>::const_iterator event = events.begin(); 158 for (std::vector<media::MediaLogEvent>::const_iterator event = events.begin();
109 event != events.end(); ++event) { 159 event != events.end(); ++event) {
110 base::DictionaryValue dict; 160 base::DictionaryValue dict;
111 dict.SetInteger("renderer", render_process_id); 161 dict.SetInteger("renderer", render_process_id);
112 dict.SetInteger("player", event->id); 162 dict.SetInteger("player", event->id);
113 dict.SetString("type", media::MediaLog::EventTypeToString(event->type)); 163 dict.SetString("type", media::MediaLog::EventTypeToString(event->type));
114 164
115 int64 ticks = event->time.ToInternalValue(); 165 // TODO(dalecurtis): This is technically not correct. TimeTicks "can't" be
116 double ticks_millis = 166 // converted to to a human readable time format. See base/time/time.h.
117 ticks / static_cast<double>(base::Time::kMicrosecondsPerMillisecond); 167 const double ticks = event->time.ToInternalValue();
118 168 const double ticks_millis = ticks / base::Time::kMicrosecondsPerMillisecond;
119 dict.SetDouble("ticksMillis", ticks_millis); 169 dict.SetDouble("ticksMillis", ticks_millis);
120 dict.Set("params", event->params.DeepCopy()); 170 dict.Set("params", event->params.DeepCopy());
121 SendUpdate("media.onMediaEvent", &dict); 171 SendUpdate(SerializeUpdate("media.onMediaEvent", &dict));
122 } 172 }
123 } 173 }
124 174
125 void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) { 175 void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) {
176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
126 update_callbacks_.push_back(callback); 177 update_callbacks_.push_back(callback);
127 } 178 }
128 179
129 void MediaInternals::RemoveUpdateCallback(const UpdateCallback& callback) { 180 void MediaInternals::RemoveUpdateCallback(const UpdateCallback& callback) {
181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
130 for (size_t i = 0; i < update_callbacks_.size(); ++i) { 182 for (size_t i = 0; i < update_callbacks_.size(); ++i) {
131 if (update_callbacks_[i].Equals(callback)) { 183 if (update_callbacks_[i].Equals(callback)) {
132 update_callbacks_.erase(update_callbacks_.begin() + i); 184 update_callbacks_.erase(update_callbacks_.begin() + i);
133 return; 185 return;
134 } 186 }
135 } 187 }
136 NOTREACHED(); 188 NOTREACHED();
137 } 189 }
138 190
139 void MediaInternals::SendEverything() { 191 void MediaInternals::SendEverything() {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 192 base::AutoLock auto_lock(cache_lock_);
141 SendUpdate("media.onReceiveEverything", &data_); 193 SendUpdate(SerializeUpdate("media.onReceiveEverything", &cached_data_));
142 } 194 }
143 195
144 MediaInternals::MediaInternals() { 196 void MediaInternals::SendUpdate(const string16& update) {
145 } 197 // SendUpdate() may be called from any thread, but must run on the IO thread.
198 // TODO(dalecurtis): This is pretty silly since the update callbacks simply
199 // forward the calls to the UI thread. We should avoid the extra hop.
200 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
201 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
202 &MediaInternals::SendUpdate, base::Unretained(this), update));
203 return;
204 }
146 205
147 void MediaInternals::StoreAudioStream(void* host,
148 int stream_id,
149 const std::string& property,
150 base::Value* value) {
151 StoreItem(FormatAudioStreamName(host, stream_id), property, value);
152 }
153
154 void MediaInternals::UpdateAudioStream(void* host,
155 int stream_id,
156 const std::string& property,
157 base::Value* value) {
158 UpdateItem("media.updateAudioStream",
159 FormatAudioStreamName(host, stream_id),
160 property,
161 value);
162 }
163
164 void MediaInternals::DeleteItem(const std::string& item) {
165 data_.Remove(item, NULL);
166 scoped_ptr<base::Value> value(new base::StringValue(item));
167 SendUpdate("media.onItemDeleted", value.get());
168 }
169
170 base::DictionaryValue* MediaInternals::StoreItem(const std::string& id,
171 const std::string& property,
172 base::Value* value) {
173 base::DictionaryValue* item_properties;
174 if (!data_.GetDictionary(id, &item_properties)) {
175 item_properties = new base::DictionaryValue();
176 data_.Set(id, item_properties);
177 item_properties->SetString("id", id);
178 }
179 item_properties->Set(property, value);
180 return item_properties;
181 }
182
183 void MediaInternals::UpdateItem(const std::string& update_fn,
184 const std::string& id,
185 const std::string& property,
186 base::Value* value) {
187 base::DictionaryValue* item_properties = StoreItem(id, property, value);
188 SendUpdate(update_fn, item_properties);
189 }
190
191 void MediaInternals::SendUpdate(const std::string& function,
192 base::Value* value) {
193 // Only bother serializing the update to JSON if someone is watching.
194 if (update_callbacks_.empty())
195 return;
196
197 std::vector<const base::Value*> args;
198 args.push_back(value);
199 string16 update = WebUI::GetJavascriptCall(function, args);
200 for (size_t i = 0; i < update_callbacks_.size(); i++) 206 for (size_t i = 0; i < update_callbacks_.size(); i++)
201 update_callbacks_[i].Run(update); 207 update_callbacks_[i].Run(update);
202 } 208 }
203 209
210 scoped_ptr<media::AudioLog> MediaInternals::CreateAudioLog(
211 AudioComponent component) {
212 base::AutoLock auto_lock(cache_lock_);
213 return scoped_ptr<media::AudioLog>(new AudioLogImpl(
214 owner_ids_[component]++, component, this));
215 }
216
217 void MediaInternals::SendUpdateAndCache(const std::string& cache_key,
218 const std::string& function,
219 const base::DictionaryValue* value) {
220 base::AutoLock auto_lock(cache_lock_);
221 SendUpdate(SerializeUpdate(function, value));
222
223 if (!cached_data_.HasKey(cache_key)) {
224 cached_data_.Set(cache_key, value->DeepCopy());
225 return;
226 }
227
228 base::DictionaryValue* existing_dict = NULL;
229 CHECK(cached_data_.GetDictionary(cache_key, &existing_dict));
230 existing_dict->MergeDictionary(value);
231 }
232
233 void MediaInternals::SendUpdateAndPurgeCache(
234 const std::string& cache_key,
235 const std::string& function,
236 const base::DictionaryValue* value) {
237 base::AutoLock auto_lock(cache_lock_);
238 SendUpdate(SerializeUpdate(function, value));
239
240 scoped_ptr<base::Value> out_value;
241 CHECK(cached_data_.Remove(cache_key, &out_value));
242 }
243
204 } // namespace content 244 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698