1 // Copyright 2013 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.
5 #include "media/blink/webmediaplayer_util.h"
9 #include "base/metrics/histogram.h"
10 #include "media/base/bind_to_current_loop.h"
11 #include "media/base/media_client.h"
12 #include "media/base/media_keys.h"
13 #include "third_party/WebKit/public/platform/WebMediaPlayerEncryptedMediaClient.h"
17 // Compile asserts shared by all platforms.
19 #define STATIC_ASSERT_MATCHING_ENUM(name) \
20 static_assert(static_cast<int>(blink::WebMediaPlayerEncryptedMediaClient:: \
21 MediaKeyErrorCode##name) == \
22 static_cast<int>(MediaKeys::k##name##Error), \
23 "mismatching enum values: " #name)
24 STATIC_ASSERT_MATCHING_ENUM(Unknown
);
25 STATIC_ASSERT_MATCHING_ENUM(Client
);
26 #undef STATIC_ASSERT_MATCHING_ENUM
28 base::TimeDelta
ConvertSecondsToTimestamp(double seconds
) {
29 double microseconds
= seconds
* base::Time::kMicrosecondsPerSecond
;
30 return base::TimeDelta::FromMicroseconds(
31 microseconds
> 0 ? microseconds
+ 0.5 : ceil(microseconds
- 0.5));
34 blink::WebTimeRanges
ConvertToWebTimeRanges(
35 const Ranges
<base::TimeDelta
>& ranges
) {
36 blink::WebTimeRanges
result(ranges
.size());
37 for (size_t i
= 0; i
< ranges
.size(); ++i
) {
38 result
[i
].start
= ranges
.start(i
).InSecondsF();
39 result
[i
].end
= ranges
.end(i
).InSecondsF();
44 blink::WebMediaPlayer::NetworkState
PipelineErrorToNetworkState(
45 PipelineStatus error
) {
46 DCHECK_NE(error
, PIPELINE_OK
);
49 case PIPELINE_ERROR_NETWORK
:
50 case PIPELINE_ERROR_READ
:
51 return blink::WebMediaPlayer::NetworkStateNetworkError
;
53 // TODO(vrk): Because OnPipelineInitialize() directly reports the
54 // NetworkStateFormatError instead of calling OnPipelineError(), I believe
55 // this block can be deleted. Should look into it! (crbug.com/126070)
56 case PIPELINE_ERROR_INITIALIZATION_FAILED
:
57 case PIPELINE_ERROR_COULD_NOT_RENDER
:
58 case PIPELINE_ERROR_URL_NOT_FOUND
:
59 case DEMUXER_ERROR_COULD_NOT_OPEN
:
60 case DEMUXER_ERROR_COULD_NOT_PARSE
:
61 case DEMUXER_ERROR_NO_SUPPORTED_STREAMS
:
62 case DECODER_ERROR_NOT_SUPPORTED
:
63 return blink::WebMediaPlayer::NetworkStateFormatError
;
65 case PIPELINE_ERROR_DECODE
:
66 case PIPELINE_ERROR_ABORT
:
67 case PIPELINE_ERROR_OPERATION_PENDING
:
68 case PIPELINE_ERROR_INVALID_STATE
:
69 return blink::WebMediaPlayer::NetworkStateDecodeError
;
72 NOTREACHED() << "Unexpected status! " << error
;
74 return blink::WebMediaPlayer::NetworkStateFormatError
;
79 // Helper enum for reporting scheme histograms.
80 enum URLSchemeForHistogram
{
86 kChromeExtensionURLScheme
,
92 kMaxURLScheme
= kFileSystemScheme
// Must be equal to highest enum value.
95 URLSchemeForHistogram
URLScheme(const GURL
& url
) {
96 if (!url
.has_scheme()) return kMissingURLScheme
;
97 if (url
.SchemeIs("http")) return kHttpURLScheme
;
98 if (url
.SchemeIs("https")) return kHttpsURLScheme
;
99 if (url
.SchemeIs("ftp")) return kFtpURLScheme
;
100 if (url
.SchemeIs("chrome-extension")) return kChromeExtensionURLScheme
;
101 if (url
.SchemeIs("javascript")) return kJavascriptURLScheme
;
102 if (url
.SchemeIs("file")) return kFileURLScheme
;
103 if (url
.SchemeIs("blob")) return kBlobURLScheme
;
104 if (url
.SchemeIs("data")) return kDataURLScheme
;
105 if (url
.SchemeIs("filesystem")) return kFileSystemScheme
;
107 return kUnknownURLScheme
;
110 std::string
LoadTypeToString(blink::WebMediaPlayer::LoadType load_type
) {
112 case blink::WebMediaPlayer::LoadTypeURL
:
114 case blink::WebMediaPlayer::LoadTypeMediaSource
:
116 case blink::WebMediaPlayer::LoadTypeMediaStream
:
126 // TODO(xhwang): Call this from WebMediaPlayerMS to report metrics for
127 // MediaStream as well.
128 void ReportMetrics(blink::WebMediaPlayer::LoadType load_type
,
130 const GURL
& origin_url
) {
131 // Report URL scheme, such as http, https, file, blob etc.
132 UMA_HISTOGRAM_ENUMERATION("Media.URLScheme", URLScheme(url
),
135 // Report load type, such as URL, MediaSource or MediaStream.
136 UMA_HISTOGRAM_ENUMERATION("Media.LoadType", load_type
,
137 blink::WebMediaPlayer::LoadTypeMax
+ 1);
139 // Report the origin from where the media player is created.
140 if (GetMediaClient()) {
141 GetMediaClient()->RecordRapporURL(
142 "Media.OriginUrl." + LoadTypeToString(load_type
), origin_url
);
146 void RecordOriginOfHLSPlayback(const GURL
& origin_url
) {
147 if (media::GetMediaClient())
148 GetMediaClient()->RecordRapporURL("Media.OriginUrl.HLS", origin_url
);
151 EmeInitDataType
ConvertToEmeInitDataType(
152 blink::WebEncryptedMediaInitDataType init_data_type
) {
153 switch (init_data_type
) {
154 case blink::WebEncryptedMediaInitDataType::Webm
:
155 return EmeInitDataType::WEBM
;
156 case blink::WebEncryptedMediaInitDataType::Cenc
:
157 return EmeInitDataType::CENC
;
158 case blink::WebEncryptedMediaInitDataType::Keyids
:
159 return EmeInitDataType::KEYIDS
;
160 case blink::WebEncryptedMediaInitDataType::Unknown
:
161 return EmeInitDataType::UNKNOWN
;
165 return EmeInitDataType::UNKNOWN
;
168 blink::WebEncryptedMediaInitDataType
ConvertToWebInitDataType(
169 EmeInitDataType init_data_type
) {
170 switch (init_data_type
) {
171 case EmeInitDataType::WEBM
:
172 return blink::WebEncryptedMediaInitDataType::Webm
;
173 case EmeInitDataType::CENC
:
174 return blink::WebEncryptedMediaInitDataType::Cenc
;
175 case EmeInitDataType::KEYIDS
:
176 return blink::WebEncryptedMediaInitDataType::Keyids
;
177 case EmeInitDataType::UNKNOWN
:
178 return blink::WebEncryptedMediaInitDataType::Unknown
;
182 return blink::WebEncryptedMediaInitDataType::Unknown
;
186 // This class wraps a scoped WebSetSinkIdCB pointer such that
187 // copying objects of this class actually performs moving, thus
188 // maintaining clear ownership of the WebSetSinkIdCB pointer.
189 // The rationale for this class is that the SwichOutputDevice method
190 // can make a copy of its base::Callback parameter, which implies
191 // copying its bound parameters.
192 // SwitchOutputDevice actually wants to move its base::Callback
193 // parameter since only the final copy will be run, but base::Callback
194 // does not support move semantics and there is no base::MovableCallback.
195 // Since scoped pointers are not copyable, we cannot bind them directly
196 // to a base::Callback in this case. Thus, we use this helper class,
197 // whose copy constructor transfers ownership of the scoped pointer.
199 class SetSinkIdCallback
{
201 explicit SetSinkIdCallback(WebSetSinkIdCB
* web_callback
)
202 : web_callback_(web_callback
) {}
203 SetSinkIdCallback(const SetSinkIdCallback
& other
)
204 : web_callback_(other
.web_callback_
.Pass()) {}
205 ~SetSinkIdCallback() {}
206 friend void RunSetSinkIdCallback(const SetSinkIdCallback
& callback
,
207 SwitchOutputDeviceResult result
);
210 // Mutable is required so that Pass() can be called in the copy
212 mutable scoped_ptr
<WebSetSinkIdCB
> web_callback_
;
215 void RunSetSinkIdCallback(const SetSinkIdCallback
& callback
,
216 SwitchOutputDeviceResult result
) {
217 DVLOG(1) << __FUNCTION__
;
218 if (!callback
.web_callback_
)
222 case SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS
:
223 callback
.web_callback_
->onSuccess();
225 case SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_FOUND
:
226 callback
.web_callback_
->onError(new blink::WebSetSinkIdError(
227 blink::WebSetSinkIdError::ErrorTypeNotFound
, "Device not found"));
229 case SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED
:
230 callback
.web_callback_
->onError(new blink::WebSetSinkIdError(
231 blink::WebSetSinkIdError::ErrorTypeSecurity
,
232 "No permission to access device"));
234 case SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE
:
235 callback
.web_callback_
->onError(new blink::WebSetSinkIdError(
236 blink::WebSetSinkIdError::ErrorTypeAbort
,
237 "The requested operation became obsolete and was aborted"));
239 case SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_SUPPORTED
:
240 callback
.web_callback_
->onError(new blink::WebSetSinkIdError(
241 blink::WebSetSinkIdError::ErrorTypeAbort
,
242 "The requested operation cannot be performed and was aborted"));
248 callback
.web_callback_
= nullptr;
253 SwitchOutputDeviceCB
ConvertToSwitchOutputDeviceCB(
254 WebSetSinkIdCB
* web_callbacks
) {
255 return media::BindToCurrentLoop(
256 base::Bind(RunSetSinkIdCallback
, SetSinkIdCallback(web_callbacks
)));