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

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 JavaScript. 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 void StoreComponentMetadata(int component_id, base::DictionaryValue* dict);
55 std::string FormatCacheKey(int component_id);
56
57 const int owner_id_;
58 const media::AudioLogFactory::AudioComponent component_;
59 content::MediaInternals* const media_internals_;
60
61 DISALLOW_COPY_AND_ASSIGN(AudioLogImpl);
62 };
63
64 AudioLogImpl::AudioLogImpl(int owner_id,
65 media::AudioLogFactory::AudioComponent component,
66 content::MediaInternals* media_internals)
67 : owner_id_(owner_id),
68 component_(component),
69 media_internals_(media_internals) {}
70
71 AudioLogImpl::~AudioLogImpl() {}
72
73 void AudioLogImpl::OnCreated(int component_id,
74 const media::AudioParameters& params,
75 const std::string& input_device_id,
76 const std::string& output_device_id) {
77 base::DictionaryValue dict;
78 StoreComponentMetadata(component_id, &dict);
79
80 dict.SetString(kAudioLogStatusKey, "created");
81 dict.SetString("input_device_id", input_device_id);
82 dict.SetInteger("input_channels", params.input_channels());
83 dict.SetInteger("frames_per_buffer", params.frames_per_buffer());
84 dict.SetInteger("sample_rate", params.sample_rate());
85 dict.SetString("output_device_id", output_device_id);
86 dict.SetInteger("output_channels", params.channels());
87 dict.SetString("output_channel_layout",
88 ChannelLayoutToString(params.channel_layout()));
89
90 media_internals_->SendUpdateAndCache(
91 FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
20 } 92 }
21 93
22 MediaInternals::~MediaInternals() {} 94 void AudioLogImpl::OnStarted(int component_id) {
23 95 SendSingleStringUpdate(component_id, kAudioLogStatusKey, "started");
24 namespace {
25 std::string FormatAudioStreamName(void* host, int stream_id) {
26 return base::StringPrintf("audio_streams.%p:%d", host, stream_id);
27 }
28 } 96 }
29 97
30 void MediaInternals::OnDeleteAudioStream(void* host, int stream_id) { 98 void AudioLogImpl::OnStopped(int component_id) {
31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 99 SendSingleStringUpdate(component_id, kAudioLogStatusKey, "stopped");
32 DeleteItem(FormatAudioStreamName(host, stream_id));
33 } 100 }
34 101
35 void MediaInternals::OnSetAudioStreamPlaying( 102 void AudioLogImpl::OnClosed(int component_id) {
36 void* host, int stream_id, bool playing) { 103 base::DictionaryValue dict;
37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 104 StoreComponentMetadata(component_id, &dict);
38 UpdateAudioStream(host, stream_id, 105 dict.SetString(kAudioLogStatusKey, "closed");
39 "playing", new base::FundamentalValue(playing)); 106 media_internals_->SendUpdateAndPurgeCache(
107 FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
40 } 108 }
41 109
42 void MediaInternals::OnAudioStreamCreated(void* host, 110 void AudioLogImpl::OnError(int component_id) {
43 int stream_id, 111 SendSingleStringUpdate(component_id, "error_occurred", "true");
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 } 112 }
87 113
88 void MediaInternals::OnSetAudioStreamStatus(void* host, 114 void AudioLogImpl::OnSetVolume(int component_id, double volume) {
89 int stream_id, 115 base::DictionaryValue dict;
90 const std::string& status) { 116 StoreComponentMetadata(component_id, &dict);
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 117 dict.SetDouble("volume", volume);
92 UpdateAudioStream(host, stream_id, 118 media_internals_->SendUpdateAndCache(
93 "status", new base::StringValue(status)); 119 FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
94 } 120 }
95 121
96 void MediaInternals::OnSetAudioStreamVolume( 122 std::string AudioLogImpl::FormatCacheKey(int component_id) {
97 void* host, int stream_id, double volume) { 123 return base::StringPrintf("%d:%d:%d", owner_id_, component_, component_id);
98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
99 UpdateAudioStream(host, stream_id,
100 "volume", new base::FundamentalValue(volume));
101 } 124 }
102 125
126 void AudioLogImpl::SendSingleStringUpdate(int component_id,
127 const std::string& key,
128 const std::string& value) {
129 base::DictionaryValue dict;
130 StoreComponentMetadata(component_id, &dict);
131 dict.SetString(key, value);
132 media_internals_->SendUpdateAndCache(
133 FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
134 }
135
136 void AudioLogImpl::StoreComponentMetadata(int component_id,
137 base::DictionaryValue* dict) {
138 dict->SetInteger("owner_id", owner_id_);
139 dict->SetInteger("component_id", component_id);
140 dict->SetInteger("component_type", component_);
141 }
142
143 MediaInternals* MediaInternals::GetInstance() {
144 return g_media_internals.Pointer();
145 }
146
147 MediaInternals::MediaInternals() : owner_ids_() {}
148 MediaInternals::~MediaInternals() {}
149
103 void MediaInternals::OnMediaEvents( 150 void MediaInternals::OnMediaEvents(
104 int render_process_id, const std::vector<media::MediaLogEvent>& events) { 151 int render_process_id, const std::vector<media::MediaLogEvent>& events) {
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
106 153 // Notify observers that |event| has occurred.
107 // Notify observers that |event| has occured.
108 for (std::vector<media::MediaLogEvent>::const_iterator event = events.begin(); 154 for (std::vector<media::MediaLogEvent>::const_iterator event = events.begin();
109 event != events.end(); ++event) { 155 event != events.end(); ++event) {
110 base::DictionaryValue dict; 156 base::DictionaryValue dict;
111 dict.SetInteger("renderer", render_process_id); 157 dict.SetInteger("renderer", render_process_id);
112 dict.SetInteger("player", event->id); 158 dict.SetInteger("player", event->id);
113 dict.SetString("type", media::MediaLog::EventTypeToString(event->type)); 159 dict.SetString("type", media::MediaLog::EventTypeToString(event->type));
114 160
115 int64 ticks = event->time.ToInternalValue(); 161 // TODO(dalecurtis): This is technically not correct. TimeTicks "can't" be
116 double ticks_millis = 162 // converted to to a human readable time format. See base/time/time.h.
117 ticks / static_cast<double>(base::Time::kMicrosecondsPerMillisecond); 163 const double ticks = event->time.ToInternalValue();
118 164 const double ticks_millis = ticks / base::Time::kMicrosecondsPerMillisecond;
119 dict.SetDouble("ticksMillis", ticks_millis); 165 dict.SetDouble("ticksMillis", ticks_millis);
120 dict.Set("params", event->params.DeepCopy()); 166 dict.Set("params", event->params.DeepCopy());
121 SendUpdate("media.onMediaEvent", &dict); 167 SendUpdate(SerializeUpdate("media.onMediaEvent", &dict));
122 } 168 }
123 } 169 }
124 170
125 void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) { 171 void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) {
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
126 update_callbacks_.push_back(callback); 173 update_callbacks_.push_back(callback);
127 } 174 }
128 175
129 void MediaInternals::RemoveUpdateCallback(const UpdateCallback& callback) { 176 void MediaInternals::RemoveUpdateCallback(const UpdateCallback& callback) {
177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
130 for (size_t i = 0; i < update_callbacks_.size(); ++i) { 178 for (size_t i = 0; i < update_callbacks_.size(); ++i) {
131 if (update_callbacks_[i].Equals(callback)) { 179 if (update_callbacks_[i].Equals(callback)) {
132 update_callbacks_.erase(update_callbacks_.begin() + i); 180 update_callbacks_.erase(update_callbacks_.begin() + i);
133 return; 181 return;
134 } 182 }
135 } 183 }
136 NOTREACHED(); 184 NOTREACHED();
137 } 185 }
138 186
139 void MediaInternals::SendEverything() { 187 void MediaInternals::SendEverything() {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 188 base::AutoLock auto_lock(cache_lock_);
141 SendUpdate("media.onReceiveEverything", &data_); 189 SendUpdate(SerializeUpdate("media.onReceiveEverything", &cached_data_));
142 } 190 }
143 191
144 MediaInternals::MediaInternals() { 192 void MediaInternals::SendUpdate(const string16& update) {
145 } 193 // SendUpdate() may be called from any thread, but must run on the IO thread.
194 // TODO(dalecurtis): This is pretty silly since the update callbacks simply
195 // forward the calls to the UI thread. We should avoid the extra hop.
196 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
197 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
198 &MediaInternals::SendUpdate, base::Unretained(this), update));
199 return;
200 }
146 201
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++) 202 for (size_t i = 0; i < update_callbacks_.size(); i++)
201 update_callbacks_[i].Run(update); 203 update_callbacks_[i].Run(update);
202 } 204 }
203 205
206 scoped_ptr<media::AudioLog> MediaInternals::CreateAudioLog(
207 AudioComponent component) {
208 base::AutoLock auto_lock(cache_lock_);
209 return scoped_ptr<media::AudioLog>(new AudioLogImpl(
210 owner_ids_[component]++, component, this));
211 }
212
213 void MediaInternals::SendUpdateAndCache(const std::string& cache_key,
214 const std::string& function,
215 const base::DictionaryValue* value) {
216 base::AutoLock auto_lock(cache_lock_);
217 SendUpdate(SerializeUpdate(function, value));
acolwell GONE FROM CHROMIUM 2013/11/26 01:33:17 This holds the lock while dispatching to arbitrary
DaleCurtis 2013/11/26 03:02:21 Done.
218
219 if (!cached_data_.HasKey(cache_key)) {
220 cached_data_.Set(cache_key, value->DeepCopy());
221 return;
222 }
223
224 base::DictionaryValue* existing_dict = NULL;
225 CHECK(cached_data_.GetDictionary(cache_key, &existing_dict));
226 existing_dict->MergeDictionary(value);
227 }
228
229 void MediaInternals::SendUpdateAndPurgeCache(
230 const std::string& cache_key,
231 const std::string& function,
232 const base::DictionaryValue* value) {
233 base::AutoLock auto_lock(cache_lock_);
234 SendUpdate(SerializeUpdate(function, value));
235
236 scoped_ptr<base::Value> out_value;
237 CHECK(cached_data_.Remove(cache_key, &out_value));
238 }
239
204 } // namespace content 240 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698