Import Cobalt 20.lts.4.266393
diff --git a/src/cobalt/black_box_tests/black_box_tests.py b/src/cobalt/black_box_tests/black_box_tests.py
index 0154522..400202f 100644
--- a/src/cobalt/black_box_tests/black_box_tests.py
+++ b/src/cobalt/black_box_tests/black_box_tests.py
@@ -64,14 +64,8 @@
_device_params = None
# Binding address used to create the test server.
_binding_address = None
-
-
-def GetDeviceParams():
-
- global _device_params
- _device_params = cobalt_runner.GetDeviceParamsFromCommandLine()
- # Keep other modules from seeing these args
- sys.argv = sys.argv[:1]
+# Port used to create the web platform test http server.
+_wpt_http_port = None
class BlackBoxTestCase(unittest.TestCase):
@@ -104,9 +98,11 @@
def GetBindingAddress(self):
return _binding_address
+ def GetWptHttpPort(self):
+ return _wpt_http_port
+
def LoadTests(platform, config, device_id, out_directory):
-
launcher = abstract_launcher.LauncherFactory(
platform,
'cobalt',
@@ -134,19 +130,44 @@
class BlackBoxTests(object):
"""Helper class to run all black box tests and return results."""
- def __init__(self, test_name=None, proxy_port_number=None):
+ def __init__(self,
+ server_binding_address,
+ proxy_address=None,
+ proxy_port=None,
+ test_name=None,
+ wpt_http_port=None,
+ device_ips=None):
logging.basicConfig(level=logging.DEBUG)
- GetDeviceParams()
- # Port number used to create the proxy server. If the --proxy target param
- # is not set, a random free port is used.
- if proxy_port_number is None:
- proxy_port_number = str(self.GetUnusedPort(_binding_address))
- _device_params.target_params.append('--proxy=%s:%s' % (_binding_address,
- proxy_port_number))
+ # Setup global variables used by test cases
+ global _device_params
+ _device_params = cobalt_runner.GetDeviceParamsFromCommandLine()
+ # Keep other modules from seeing these args
+ sys.argv = sys.argv[:1]
+ global _binding_address
+ _binding_address = server_binding_address
+ # Port used to create the web platform test http server. If not specified,
+ # a random free port is used.
+ if wpt_http_port is None:
+ wpt_http_port = str(self.GetUnusedPort([server_binding_address]))
+ global _wpt_http_port
+ _wpt_http_port = wpt_http_port
+ _device_params.target_params.append(
+ '--web-platform-test-server=http://web-platform.test:%s' %
+ wpt_http_port)
+ # Port used to create the proxy server. If not specified, a random free
+ # port is used.
+ if proxy_port is None:
+ proxy_port = str(self.GetUnusedPort([server_binding_address]))
+ if proxy_address is None:
+ proxy_address = server_binding_address
+ _device_params.target_params.append('--proxy=%s:%s' %
+ (proxy_address, proxy_port))
+
+ self.proxy_port = proxy_port
self.test_name = test_name
- self.proxy_port_number = proxy_port_number
+ self.device_ips = device_ips
# Test domains used in web platform tests to be resolved to the server
# binding address.
@@ -158,15 +179,16 @@
'xn--n8j6ds53lwwkrqhv28a.web-platform.test',
'xn--lve-6lad.web-platform.test'
]
- self.host_resolve_map = dict([(host, _binding_address) for host in hosts])
+ self.host_resolve_map = dict([(host, server_binding_address) for host in hosts])
def Run(self):
- if self.proxy_port_number == '-1':
+ if self.proxy_port == '-1':
return 1
- logging.info('Using proxy port number: %s', self.proxy_port_number)
+ logging.info('Using proxy port: %s', self.proxy_port)
- with ProxyServer(port=self.proxy_port_number,
- host_resolve_map=self.host_resolve_map):
+ with ProxyServer(
+ port=self.proxy_port, host_resolve_map=self.host_resolve_map,
+ client_ips=self.device_ips):
if self.test_name:
suite = unittest.TestLoader().loadTestsFromModule(
importlib.import_module(_TEST_DIR_PATH + self.test_name))
@@ -178,42 +200,77 @@
verbosity=0, stream=sys.stdout).run(suite).wasSuccessful()
return return_code
- def GetUnusedPort(self, machine_address):
- """Find a free port on the machine address by pinging with socket."""
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ def GetUnusedPort(self, addresses):
+ """Find a free port on the list of addresses by pinging with sockets."""
+ SOCKET_SUCCESS = 0
+
+ if not addresses:
+ logging.error('Can not find unused port on invalid addresses.')
+ return -1
+
+ socks = []
+ for address in addresses:
+ socks.append((address, socket.socket(socket.AF_INET, socket.SOCK_STREAM)))
try:
- for i in range(1, _PORT_SELECTION_RETRY_LIMIT):
- port_number = random.randint(_PORT_SELECTION_RANGE[0],
- _PORT_SELECTION_RANGE[1])
- result = sock.connect_ex((machine_address, port_number))
- if result != 0:
- return port_number
- if i == _PORT_SELECTION_RETRY_LIMIT - 1:
- logging.error(
- 'Can not find unused port on target machine within %s attempts.',
- _PORT_SELECTION_RETRY_LIMIT)
- return -1
+ for _ in range(_PORT_SELECTION_RETRY_LIMIT):
+ port = random.randint(_PORT_SELECTION_RANGE[0], _PORT_SELECTION_RANGE[1])
+ unused = True
+ for sock in socks:
+ result = sock[1].connect_ex((sock[0], port))
+ if result == SOCKET_SUCCESS:
+ unused = False
+ break
+ if unused:
+ return port
+ logging.error(
+ 'Can not find unused port on addresses within %s attempts.' %
+ _PORT_SELECTION_RETRY_LIMIT)
+ return -1
finally:
- sock.close()
+ for sock in socks:
+ sock[1].close()
def main():
parser = argparse.ArgumentParser()
- parser.add_argument('--test_name',
- help=('Name of test to be run. If not specified, all '
- 'tests are run.'))
- parser.add_argument('--server_binding_address',
- default='127.0.0.1',
- help='Binding address used to create the test server.')
- parser.add_argument('--proxy_port_number',
- help=('Port number used to create the proxy http server'
- 'that all black box tests are run through. If not'
- 'specified, a random free port is used.'))
+ parser.add_argument(
+ '--server_binding_address',
+ default='127.0.0.1',
+ help='Binding address used to create the test server.')
+ parser.add_argument(
+ '--proxy_address',
+ default=None,
+ help=('Address to the proxy server that all black box'
+ 'tests are run through. If not specified, the'
+ 'server binding address is used.'))
+ parser.add_argument(
+ '--proxy_port',
+ default=None,
+ help=('Port used to create the proxy server that all'
+ 'black box tests are run through. If not'
+ 'specified, a random free port is used.'))
+ parser.add_argument(
+ '--test_name',
+ default=None,
+ help=('Name of test to be run. If not specified, all '
+ 'tests are run.'))
+ parser.add_argument(
+ '--wpt_http_port',
+ default=None,
+ help=('Port used to create the web platform test http'
+ 'server. If not specified, a random free port is'
+ 'used.'))
+ parser.add_argument(
+ '--device_ips',
+ default=None,
+ nargs='*',
+ help=('IPs of test devices that will be allowed to connect. If not'
+ 'specified, all IPs will be allowed to connect.'))
args, _ = parser.parse_known_args()
- global _binding_address
- _binding_address = args.server_binding_address
- test_object = BlackBoxTests(args.test_name, args.proxy_port_number)
+ test_object = BlackBoxTests(args.server_binding_address, args.proxy_address,
+ args.proxy_port, args.test_name,
+ args.wpt_http_port, args.device_ips)
sys.exit(test_object.Run())
diff --git a/src/cobalt/black_box_tests/proxy_server.py b/src/cobalt/black_box_tests/proxy_server.py
index ee29a39..5b51830 100644
--- a/src/cobalt/black_box_tests/proxy_server.py
+++ b/src/cobalt/black_box_tests/proxy_server.py
@@ -24,15 +24,16 @@
import os
import signal
import subprocess
-import sys
-SRC_DIR = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
import tempfile
import time
+SRC_DIR = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
+
class ProxyServer(object):
- def __init__(self, hostname='0.0.0.0', port='8000', host_resolve_map=None):
+ def __init__(self, hostname='0.0.0.0', port='8000', host_resolve_map=None,
+ client_ips=None):
self.command = [
'python',
os.path.join(SRC_DIR, 'third_party', 'proxy_py', 'proxy.py'),
@@ -42,10 +43,14 @@
self.host_resolver_path = None
if host_resolve_map:
- with tempfile.NamedTemporaryFile(delete=False) as hosts:
- json.dump(host_resolve_map, hosts)
- self.host_resolver_path = hosts.name
- self.command += ['--host_resolver', self.host_resolver_path]
+ with tempfile.NamedTemporaryFile(delete=False) as hosts:
+ json.dump(host_resolve_map, hosts)
+ self.host_resolver_path = hosts.name
+ self.command += ['--host_resolver', self.host_resolver_path]
+
+ if client_ips:
+ self.command += ['--client_ips']
+ self.command += client_ips
def __enter__(self):
self.proc = subprocess.Popen(self.command)
@@ -55,4 +60,4 @@
def __exit__(self, exc_type, exc_value, traceback):
self.proc.send_signal(signal.SIGINT)
if self.host_resolver_path:
- os.unlink(self.host_resolver_path)
+ os.unlink(self.host_resolver_path)
diff --git a/src/cobalt/black_box_tests/tests/web_platform_tests.py b/src/cobalt/black_box_tests/tests/web_platform_tests.py
index 12adcd0..2355b59 100644
--- a/src/cobalt/black_box_tests/tests/web_platform_tests.py
+++ b/src/cobalt/black_box_tests/tests/web_platform_tests.py
@@ -33,7 +33,8 @@
self.skipTest('Can only run web platform tests on debug or devel config.')
def test_simple(self):
- with WebPlatformTestServer(binding_address=self.GetBindingAddress()):
+ with WebPlatformTestServer(binding_address=self.GetBindingAddress(),
+ wpt_http_port=self.GetWptHttpPort()):
target_params = []
filters = self.cobalt_config.GetWebPlatformTestFilters()
diff --git a/src/cobalt/black_box_tests/web_platform_test_server.py b/src/cobalt/black_box_tests/web_platform_test_server.py
index 5199151..d3a9d96 100644
--- a/src/cobalt/black_box_tests/web_platform_test_server.py
+++ b/src/cobalt/black_box_tests/web_platform_test_server.py
@@ -31,12 +31,16 @@
class WebPlatformTestServer(object):
"""Runs a WPT StashServer on its own thread in a Python context manager."""
- def __init__(self, binding_address=None):
+ def __init__(self, binding_address=None, wpt_http_port=None):
# IP config['host'] should map to either through a dns or the hosts file.
if binding_address:
self._binding_address = binding_address
else:
self._binding_address = '127.0.0.1'
+ if wpt_http_port:
+ self._wpt_http_port = wpt_http_port
+ else:
+ self._wpt_http_port = '8000'
def main(self):
kwargs = vars(serve.get_parser().parse_args())
@@ -45,6 +49,7 @@
config = serve.load_config(os.path.join(WPT_DIR, 'config.default.json'),
os.path.join(WPT_DIR, 'config.json'),
**kwargs)
+ config['ports']['http'][0] = int(self._wpt_http_port)
serve.setup_logger(config['log_level'])
diff --git a/src/cobalt/browser/trace_manager.h b/src/cobalt/browser/trace_manager.h
deleted file mode 100644
index b774f11..0000000
--- a/src/cobalt/browser/trace_manager.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2016 The Cobalt Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef COBALT_BROWSER_TRACE_MANAGER_H_
-#define COBALT_BROWSER_TRACE_MANAGER_H_
-
-#include <map>
-#include <string>
-
-#include "base/threading/thread_checker.h"
-#include "cobalt/debug/console/command_manager.h"
-#include "cobalt/trace_event/event_parser.h"
-#include "cobalt/trace_event/scoped_trace_to_file.h"
-
-namespace cobalt {
-namespace browser {
-
-// Wrapper class which wraps all trace related stuff.
-class TraceManager {
- public:
- // Returns whether there's a trace that is active.
- static bool IsTracing();
-
- TraceManager();
-
- // Called by browser module when an input event is produced.
- void OnInputEventProduced();
-
- // Message handler callback for trace message from debug console.
- void OnTraceMessage(const std::string& message);
-
- // Message handler callback for input trace message from debug console.
- void OnInputTraceMessage(const std::string& message);
-
- // Called when receiving and finishing receiving parsed trace events.
- void OnReceiveTraceEvent(
- const scoped_refptr<trace_event::EventParser::ScopedEvent>& event);
- void OnFinishReceiveTraceEvent();
-
- private:
- typedef std::multimap<int64,
- scoped_refptr<trace_event::EventParser::ScopedEvent> >
- StartTimeToEventMap;
-
- // The message loop on which we'll do all our work.
- MessageLoop* const self_message_loop_;
-
- // Command handler object for trace command from the debug console.
- debug::console::ConsoleCommandManager::CommandHandler trace_command_handler_;
- // Command handler object for input trace command from the debug console.
- debug::console::ConsoleCommandManager::CommandHandler
- input_trace_command_handler_;
- // Whether input tracing is enabled.
- bool input_tracing_enabled_;
-
- THREAD_CHECKER(thread_checker_);
- // This object can be set to start a trace if a hotkey (like F3) is pressed.
- // While initialized, it means that a trace is on-going.
- scoped_ptr<trace_event::ScopedTraceToFile> trace_to_file_;
- // Record of a list of events we're interested in, ordered by starting time.
- StartTimeToEventMap start_time_to_event_map_;
-};
-
-} // namespace browser
-} // namespace cobalt
-
-#endif // COBALT_BROWSER_TRACE_MANAGER_H_
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index e912fc3..164d0dd 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-244012
\ No newline at end of file
+266393
\ No newline at end of file
diff --git a/src/cobalt/content/ssl/certs/5c44d531.0 b/src/cobalt/content/ssl/certs/5c44d531.0
deleted file mode 100644
index cedf596..0000000
--- a/src/cobalt/content/ssl/certs/5c44d531.0
+++ /dev/null
@@ -1,33 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO
-TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh
-dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX
-DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl
-ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv
-b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291
-qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp
-uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU
-Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE
-pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp
-5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M
-UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN
-GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy
-5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv
-6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK
-eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6
-B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/
-BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov
-L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV
-HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG
-SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS
-CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen
-5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897
-IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK
-gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL
-+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL
-vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm
-bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk
-N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC
-Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z
-ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ==
------END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/5e98733a.0 b/src/cobalt/content/ssl/certs/5e98733a.0
new file mode 100644
index 0000000..7ac10cc
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/5e98733a.0
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw
+gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL
+Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg
+MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw
+BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0
+MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1
+c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ
+bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg
+Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ
+2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E
+T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j
+5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM
+C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T
+DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX
+wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A
+2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm
+nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8
+dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl
+N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj
+c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS
+5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS
+Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr
+hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/
+B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI
+AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw
+H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+
+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk
+2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol
+IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk
+5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY
+n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw==
+-----END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/812e17de.0 b/src/cobalt/content/ssl/certs/812e17de.0
deleted file mode 100644
index 05879ff..0000000
--- a/src/cobalt/content/ssl/certs/812e17de.0
+++ /dev/null
@@ -1,22 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc
-MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj
-IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB
-IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE
-RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl
-U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290
-IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU
-ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC
-QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr
-rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S
-NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc
-QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH
-txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP
-BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC
-AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp
-tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa
-IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl
-6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+
-xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
-Cm26OWMohpLzGITY+9HPBVZkVw==
------END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/9f0f5fd6.0 b/src/cobalt/content/ssl/certs/9f0f5fd6.0
deleted file mode 100644
index 7f60447..0000000
--- a/src/cobalt/content/ssl/certs/9f0f5fd6.0
+++ /dev/null
@@ -1,32 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET
-MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb
-BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz
-MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx
-FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g
-Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2
-fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl
-LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV
-WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF
-TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb
-5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc
-CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri
-wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ
-wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG
-m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4
-F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng
-WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB
-BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0
-2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF
-AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/
-0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw
-F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS
-g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj
-qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN
-h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/
-ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V
-btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj
-Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ
-8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW
-gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE=
------END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/f060240e.0 b/src/cobalt/content/ssl/certs/f060240e.0
deleted file mode 100644
index 6d0133d..0000000
--- a/src/cobalt/content/ssl/certs/f060240e.0
+++ /dev/null
@@ -1,22 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw
-PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz
-cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9
-MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz
-IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ
-ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR
-VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL
-kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd
-EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas
-H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0
-HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud
-DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4
-QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu
-Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/
-AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8
-yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR
-FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA
-ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB
-kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
-l7+ijrRU
------END CERTIFICATE-----
diff --git a/src/cobalt/cssom/combinator.h b/src/cobalt/cssom/combinator.h
index 1e54192..d97fe80 100644
--- a/src/cobalt/cssom/combinator.h
+++ b/src/cobalt/cssom/combinator.h
@@ -34,9 +34,12 @@
kDescendantCombinator,
kNextSiblingCombinator,
kFollowingSiblingCombinator,
- kCombinatorCount,
+ kCombinatorTypeCount,
};
+// Avoids the clang error: arithmetic between different enumeration types.
+constexpr size_t kCombinatorCount = static_cast<size_t>(kCombinatorTypeCount);
+
// A combinator is punctuation that represents a particular kind of relationship
// between the selectors on either side.
// https://www.w3.org/TR/selectors4/#combinator
diff --git a/src/cobalt/debug/remote/devtools/front_end/accessibility/AXBreadcrumbsPane.js b/src/cobalt/debug/remote/devtools/front_end/accessibility/AXBreadcrumbsPane.js
index 34708e0..9075c5e 100644
--- a/src/cobalt/debug/remote/devtools/front_end/accessibility/AXBreadcrumbsPane.js
+++ b/src/cobalt/debug/remote/devtools/front_end/accessibility/AXBreadcrumbsPane.js
@@ -112,7 +112,7 @@
_onKeyDown(event) {
if (!this._preselectedBreadcrumb)
return;
- if (!event.path.some(element => element === this._preselectedBreadcrumb.element()))
+ if (!event.composedPath().some(element => element === this._preselectedBreadcrumb.element()))
return;
if (event.shiftKey || event.metaKey || event.ctrlKey)
return;
diff --git a/src/cobalt/debug/remote/devtools/front_end/accessibility/AccessibilityNodeView.js b/src/cobalt/debug/remote/devtools/front_end/accessibility/AccessibilityNodeView.js
index f0c0a2e..9bb5329 100644
--- a/src/cobalt/debug/remote/devtools/front_end/accessibility/AccessibilityNodeView.js
+++ b/src/cobalt/debug/remote/devtools/front_end/accessibility/AccessibilityNodeView.js
@@ -151,7 +151,7 @@
* @return {!Element}
*/
static createExclamationMark(tooltip) {
- const exclamationElement = createElement('label', 'dt-icon-label');
+ const exclamationElement = createElement('span', 'dt-icon-label');
exclamationElement.type = 'smallicon-warning';
exclamationElement.title = tooltip;
return exclamationElement;
diff --git a/src/cobalt/debug/remote/devtools/front_end/accessibility/accessibilityNode.css b/src/cobalt/debug/remote/devtools/front_end/accessibility/accessibilityNode.css
index a6e59ca..7b624a9 100644
--- a/src/cobalt/debug/remote/devtools/front_end/accessibility/accessibilityNode.css
+++ b/src/cobalt/debug/remote/devtools/front_end/accessibility/accessibilityNode.css
@@ -47,7 +47,7 @@
padding-left: 4px;
}
-.tree-outline label[is=dt-icon-label] {
+.tree-outline span[is=dt-icon-label] {
position: relative;
left: -11px;
}
@@ -74,7 +74,7 @@
left: -2px;
}
-.tree-outline label[is=dt-icon-label] + .ax-name {
+.tree-outline span[is=dt-icon-label] + .ax-name {
margin-left: -11px;
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/changes/changesView.css b/src/cobalt/debug/remote/devtools/front_end/changes/changesView.css
index 8d3ad90..552e9ec 100644
--- a/src/cobalt/debug/remote/devtools/front_end/changes/changesView.css
+++ b/src/cobalt/debug/remote/devtools/front_end/changes/changesView.css
@@ -3,14 +3,15 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
-.insertion-point-main{
+[slot=insertion-point-main]{
flex-direction: column;
display: flex;
}
-.insertion-point-sidebar {
+[slot=insertion-point-sidebar] {
overflow: auto;
}
+
.editor-container{
flex: 1;
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/console/ConsoleViewMessage.js b/src/cobalt/debug/remote/devtools/front_end/console/ConsoleViewMessage.js
index fdc9790..ee0d012 100644
--- a/src/cobalt/debug/remote/devtools/front_end/console/ConsoleViewMessage.js
+++ b/src/cobalt/debug/remote/devtools/front_end/console/ConsoleViewMessage.js
@@ -1179,7 +1179,7 @@
return;
if (!this._repeatCountElement) {
- this._repeatCountElement = createElementWithClass('label', 'console-message-repeat-count', 'dt-small-bubble');
+ this._repeatCountElement = createElementWithClass('span', 'console-message-repeat-count', 'dt-small-bubble');
switch (this._message.level) {
case SDK.ConsoleMessage.MessageLevel.Warning:
this._repeatCountElement.type = 'warning';
diff --git a/src/cobalt/debug/remote/devtools/front_end/console_counters/WarningErrorCounter.js b/src/cobalt/debug/remote/devtools/front_end/console_counters/WarningErrorCounter.js
index b51e2ef..b17e8ae 100644
--- a/src/cobalt/debug/remote/devtools/front_end/console_counters/WarningErrorCounter.js
+++ b/src/cobalt/debug/remote/devtools/front_end/console_counters/WarningErrorCounter.js
@@ -39,7 +39,7 @@
*/
_createItem(shadowRoot, iconType) {
const item = createElementWithClass('span', 'counter-item');
- const icon = item.createChild('label', '', 'dt-icon-label');
+ const icon = item.createChild('span', '', 'dt-icon-label');
icon.type = iconType;
const text = icon.createChild('span');
shadowRoot.appendChild(item);
diff --git a/src/cobalt/debug/remote/devtools/front_end/console_counters/errorWarningCounter.css b/src/cobalt/debug/remote/devtools/front_end/console_counters/errorWarningCounter.css
index d6ad447..ee6de7a 100644
--- a/src/cobalt/debug/remote/devtools/front_end/console_counters/errorWarningCounter.css
+++ b/src/cobalt/debug/remote/devtools/front_end/console_counters/errorWarningCounter.css
@@ -18,10 +18,6 @@
margin-left: 6px;
}
-.counter-item label {
- cursor: inherit;
-}
-
.counter-item.counter-item-first {
margin-left: 0;
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/dom_extension/DOMExtension.js b/src/cobalt/debug/remote/devtools/front_end/dom_extension/DOMExtension.js
index baa2879..ae9eb89 100644
--- a/src/cobalt/debug/remote/devtools/front_end/dom_extension/DOMExtension.js
+++ b/src/cobalt/debug/remote/devtools/front_end/dom_extension/DOMExtension.js
@@ -270,10 +270,12 @@
*/
Node.prototype.hasSelection = function() {
// TODO(luoe): use contains(node, {includeShadow: true}) when it is fixed for shadow dom.
- const contents = this.querySelectorAll('content');
- for (const content of contents) {
- if (Array.prototype.some.call(content.getDistributedNodes(), node => node.hasSelection()))
- return true;
+ if (this instanceof Element) {
+ const slots = this.querySelectorAll('slot');
+ for (const slot of slots) {
+ if (Array.prototype.some.call(slot.assignedNodes(), node => node.hasSelection()))
+ return true;
+ }
}
const selection = this.getComponentSelection();
@@ -299,10 +301,11 @@
* @param {string} tagName
* @param {string=} customElementType
* @return {!Element}
+ * @suppress {checkTypes}
* @suppressGlobalPropertiesCheck
*/
function createElement(tagName, customElementType) {
- return document.createElement(tagName, customElementType || '');
+ return document.createElement(tagName, {is: customElementType});
}
/**
@@ -318,10 +321,11 @@
* @param {string} elementName
* @param {string=} className
* @param {string=} customElementType
+ * @suppress {checkTypes}
* @return {!Element}
*/
Document.prototype.createElementWithClass = function(elementName, className, customElementType) {
- const element = this.createElement(elementName, customElementType || '');
+ const element = this.createElement(elementName, {is: customElementType});
if (className)
element.className = className;
return element;
@@ -651,7 +655,7 @@
if (this.shadowRoot)
return this.shadowRoot;
- const distributedNodes = this.getDistributedNodes ? this.getDistributedNodes() : [];
+ const distributedNodes = this instanceof HTMLSlotElement ? this.assignedNodes() : [];
if (distributedNodes.length)
return distributedNodes[0];
@@ -668,7 +672,7 @@
if (sibling)
return sibling;
- node = insertionPoint(node) || node.parentNodeOrShadowHost();
+ node = node.assignedSlot || node.parentNodeOrShadowHost();
}
/**
@@ -676,10 +680,9 @@
* @return {?Node}
*/
function nextSibling(node) {
- const parent = insertionPoint(node);
- if (!parent)
+ if (!node.assignedSlot)
return node.nextSibling;
- const distributedNodes = parent.getDistributedNodes ? parent.getDistributedNodes() : [];
+ const distributedNodes = node.assignedSlot.assignedNodes();
const position = Array.prototype.indexOf.call(distributedNodes, node);
if (position + 1 < distributedNodes.length)
@@ -687,15 +690,6 @@
return null;
}
- /**
- * @param {!Node} node
- * @return {?Node}
- */
- function insertionPoint(node) {
- const insertionPoints = node.getDestinationInsertionPoints ? node.getDestinationInsertionPoints() : [];
- return insertionPoints.length > 0 ? insertionPoints[insertionPoints.length - 1] : null;
- }
-
return null;
};
diff --git a/src/cobalt/debug/remote/devtools/front_end/elements/ElementsSidebarPane.js b/src/cobalt/debug/remote/devtools/front_end/elements/ElementsSidebarPane.js
index 5676b09..1f76f3d 100644
--- a/src/cobalt/debug/remote/devtools/front_end/elements/ElementsSidebarPane.js
+++ b/src/cobalt/debug/remote/devtools/front_end/elements/ElementsSidebarPane.js
@@ -5,8 +5,11 @@
* @unrestricted
*/
Elements.ElementsSidebarPane = class extends UI.VBox {
- constructor() {
- super(true);
+ /**
+ * @param {boolean=} delegatesFocus
+ */
+ constructor(delegatesFocus) {
+ super(true, delegatesFocus);
this.element.classList.add('flex-none');
this._computedStyleModel = new Elements.ComputedStyleModel();
this._computedStyleModel.addEventListener(
diff --git a/src/cobalt/debug/remote/devtools/front_end/elements/StylesSidebarPane.js b/src/cobalt/debug/remote/devtools/front_end/elements/StylesSidebarPane.js
index 2845ba4..7a10535 100644
--- a/src/cobalt/debug/remote/devtools/front_end/elements/StylesSidebarPane.js
+++ b/src/cobalt/debug/remote/devtools/front_end/elements/StylesSidebarPane.js
@@ -29,10 +29,9 @@
Elements.StylesSidebarPane = class extends Elements.ElementsSidebarPane {
constructor() {
- super();
+ super(true /* delegatesFocus */);
this.setMinimumSize(96, 26);
this.registerRequiredCSS('elements/stylesSidebarPane.css');
- this.element.tabIndex = -1;
Common.moduleSetting('colorFormat').addChangeListener(this.update.bind(this));
Common.moduleSetting('textEditorIndent').addChangeListener(this.update.bind(this));
@@ -94,7 +93,7 @@
* @return {!Element}
*/
static createExclamationMark(property) {
- const exclamationElement = createElement('label', 'dt-icon-label');
+ const exclamationElement = createElement('span', 'dt-icon-label');
exclamationElement.className = 'exclamation-mark';
if (!Elements.StylesSidebarPane.ignoreErrorsForProperty(property))
exclamationElement.type = 'smallicon-warning';
diff --git a/src/cobalt/debug/remote/devtools/front_end/elements/classesPaneWidget.css b/src/cobalt/debug/remote/devtools/front_end/elements/classesPaneWidget.css
index ee810fe..01aec13 100644
--- a/src/cobalt/debug/remote/devtools/front_end/elements/classesPaneWidget.css
+++ b/src/cobalt/debug/remote/devtools/front_end/elements/classesPaneWidget.css
@@ -16,7 +16,7 @@
justify-content: flex-start;
}
-.styles-element-classes-pane label {
+.styles-element-classes-pane [is=dt-checkbox] {
margin-right: 15px;
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/emulation/DeviceModeView.js b/src/cobalt/debug/remote/devtools/front_end/emulation/DeviceModeView.js
index e77cf26..144a61b 100644
--- a/src/cobalt/debug/remote/devtools/front_end/emulation/DeviceModeView.js
+++ b/src/cobalt/debug/remote/devtools/front_end/emulation/DeviceModeView.js
@@ -74,7 +74,7 @@
this._bottomResizerElement.title = Common.UIString('Double-click for full height');
this._pageArea = this._screenArea.createChild('div', 'device-mode-page-area');
- this._pageArea.createChild('content');
+ this._pageArea.createChild('slot');
}
_populatePresetsContainer() {
diff --git a/src/cobalt/debug/remote/devtools/front_end/emulation/sensors.css b/src/cobalt/debug/remote/devtools/front_end/emulation/sensors.css
index 03c1311..6960e86 100644
--- a/src/cobalt/debug/remote/devtools/front_end/emulation/sensors.css
+++ b/src/cobalt/debug/remote/devtools/front_end/emulation/sensors.css
@@ -9,10 +9,6 @@
display: block;
}
-.sensors-view label {
- margin-bottom: 10px;
-}
-
.sensors-view input {
width: 100%;
max-width: 100px;
diff --git a/src/cobalt/debug/remote/devtools/front_end/inline_editor/CSSShadowEditor.js b/src/cobalt/debug/remote/devtools/front_end/inline_editor/CSSShadowEditor.js
index ddaa9f8..83b8b1a 100644
--- a/src/cobalt/debug/remote/devtools/front_end/inline_editor/CSSShadowEditor.js
+++ b/src/cobalt/debug/remote/devtools/front_end/inline_editor/CSSShadowEditor.js
@@ -68,7 +68,7 @@
* @return {!Element}
*/
_createSlider(field) {
- const slider = UI.createSliderLabel(0, InlineEditor.CSSShadowEditor.maxRange, -1);
+ const slider = UI.createSlider(0, InlineEditor.CSSShadowEditor.maxRange, -1);
slider.addEventListener('input', this._onSliderInput.bind(this), false);
field.appendChild(slider);
return slider;
diff --git a/src/cobalt/debug/remote/devtools/front_end/inline_editor/ColorSwatch.js b/src/cobalt/debug/remote/devtools/front_end/inline_editor/ColorSwatch.js
index 5f5eb0b..2dfc68a 100644
--- a/src/cobalt/debug/remote/devtools/front_end/inline_editor/ColorSwatch.js
+++ b/src/cobalt/debug/remote/devtools/front_end/inline_editor/ColorSwatch.js
@@ -7,6 +7,17 @@
InlineEditor.ColorSwatch = class extends HTMLSpanElement {
constructor() {
super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/colorSwatch.css');
+
+ this._iconElement = root.createChild('span', 'color-swatch');
+ this._iconElement.title = Common.UIString('Shift-click to change color format');
+ this._swatchInner = this._iconElement.createChild('span', 'color-swatch-inner');
+ this._swatchInner.addEventListener('dblclick', e => e.consume(), false);
+ this._swatchInner.addEventListener('mousedown', e => e.consume(), false);
+ this._swatchInner.addEventListener('click', this._handleClick.bind(this), true);
+
+ root.createChild('slot');
+ this._colorValueElement = this.createChild('span');
}
/**
@@ -15,11 +26,11 @@
static create() {
if (!InlineEditor.ColorSwatch._constructor) {
InlineEditor.ColorSwatch._constructor =
- UI.registerCustomElement('span', 'color-swatch', InlineEditor.ColorSwatch.prototype);
+ UI.registerCustomElement('span', 'color-swatch', InlineEditor.ColorSwatch);
}
- return /** @type {!InlineEditor.ColorSwatch} */ (new InlineEditor.ColorSwatch._constructor());
+ return /** @type {!InlineEditor.ColorSwatch} */ (InlineEditor.ColorSwatch._constructor());
}
/**
@@ -134,23 +145,6 @@
}
/**
- * @override
- */
- createdCallback() {
- const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/colorSwatch.css');
-
- this._iconElement = root.createChild('span', 'color-swatch');
- this._iconElement.title = Common.UIString('Shift-click to change color format');
- this._swatchInner = this._iconElement.createChild('span', 'color-swatch-inner');
- this._swatchInner.addEventListener('dblclick', e => e.consume(), false);
- this._swatchInner.addEventListener('mousedown', e => e.consume(), false);
- this._swatchInner.addEventListener('click', this._handleClick.bind(this), true);
-
- root.createChild('content');
- this._colorValueElement = this.createChild('span');
- }
-
- /**
* @param {!Event} event
*/
_handleClick(event) {
@@ -168,6 +162,11 @@
InlineEditor.BezierSwatch = class extends HTMLSpanElement {
constructor() {
super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/bezierSwatch.css');
+ this._iconElement = UI.Icon.create('smallicon-bezier', 'bezier-swatch-icon');
+ root.appendChild(this._iconElement);
+ this._textElement = this.createChild('span');
+ root.createChild('slot');
}
/**
@@ -176,11 +175,11 @@
static create() {
if (!InlineEditor.BezierSwatch._constructor) {
InlineEditor.BezierSwatch._constructor =
- UI.registerCustomElement('span', 'bezier-swatch', InlineEditor.BezierSwatch.prototype);
+ UI.registerCustomElement('span', 'bezier-swatch', InlineEditor.BezierSwatch);
}
- return /** @type {!InlineEditor.BezierSwatch} */ (new InlineEditor.BezierSwatch._constructor());
+ return /** @type {!InlineEditor.BezierSwatch} */ (InlineEditor.BezierSwatch._constructor());
}
/**
@@ -210,17 +209,6 @@
iconElement() {
return this._iconElement;
}
-
- /**
- * @override
- */
- createdCallback() {
- const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/bezierSwatch.css');
- this._iconElement = UI.Icon.create('smallicon-bezier', 'bezier-swatch-icon');
- root.appendChild(this._iconElement);
- this._textElement = this.createChild('span');
- root.createChild('content');
- }
};
/**
@@ -229,6 +217,11 @@
InlineEditor.CSSShadowSwatch = class extends HTMLSpanElement {
constructor() {
super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/cssShadowSwatch.css');
+ this._iconElement = UI.Icon.create('smallicon-shadow', 'shadow-swatch-icon');
+ root.appendChild(this._iconElement);
+ root.createChild('slot');
+ this._contentElement = this.createChild('span');
}
/**
@@ -237,10 +230,10 @@
static create() {
if (!InlineEditor.CSSShadowSwatch._constructor) {
InlineEditor.CSSShadowSwatch._constructor =
- UI.registerCustomElement('span', 'css-shadow-swatch', InlineEditor.CSSShadowSwatch.prototype);
+ UI.registerCustomElement('span', 'css-shadow-swatch', InlineEditor.CSSShadowSwatch);
}
- return /** @type {!InlineEditor.CSSShadowSwatch} */ (new InlineEditor.CSSShadowSwatch._constructor());
+ return /** @type {!InlineEditor.CSSShadowSwatch} */ (InlineEditor.CSSShadowSwatch._constructor());
}
/**
@@ -290,15 +283,4 @@
colorSwatch() {
return this._colorSwatch;
}
-
- /**
- * @override
- */
- createdCallback() {
- const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/cssShadowSwatch.css');
- this._iconElement = UI.Icon.create('smallicon-shadow', 'shadow-swatch-icon');
- root.appendChild(this._iconElement);
- root.createChild('content');
- this._contentElement = this.createChild('span');
- }
};
diff --git a/src/cobalt/debug/remote/devtools/front_end/inspector_main/renderingOptions.css b/src/cobalt/debug/remote/devtools/front_end/inspector_main/renderingOptions.css
index 77eeb51..b478b44 100644
--- a/src/cobalt/debug/remote/devtools/front_end/inspector_main/renderingOptions.css
+++ b/src/cobalt/debug/remote/devtools/front_end/inspector_main/renderingOptions.css
@@ -8,7 +8,7 @@
padding: 12px;
}
-label {
+[is=dt-checkbox] {
margin: 0px 0px 10px 0px;
flex: none;
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/layers_test_runner/LayersTestRunner.js b/src/cobalt/debug/remote/devtools/front_end/layers_test_runner/LayersTestRunner.js
index d5c69d7..20e51c3 100644
--- a/src/cobalt/debug/remote/devtools/front_end/layers_test_runner/LayersTestRunner.js
+++ b/src/cobalt/debug/remote/devtools/front_end/layers_test_runner/LayersTestRunner.js
@@ -106,7 +106,8 @@
screenY: totalOffset.top - element.scrollTop + offsetY,
clientX: totalOffset.left + offsetX,
clientY: totalOffset.top + offsetY,
- button: button
+ button: button,
+ composed: true
};
if (eventType === 'mouseout') {
diff --git a/src/cobalt/debug/remote/devtools/front_end/network/RequestHeadersView.js b/src/cobalt/debug/remote/devtools/front_end/network/RequestHeadersView.js
index 5c5b4de..2d9ee3e 100644
--- a/src/cobalt/debug/remote/devtools/front_end/network/RequestHeadersView.js
+++ b/src/cobalt/debug/remote/devtools/front_end/network/RequestHeadersView.js
@@ -379,7 +379,7 @@
statusCodeFragment.createChild('div', 'header-name').textContent = Common.UIString('Status Code') + ': ';
statusCodeFragment.createChild('span', 'header-separator');
- const statusCodeImage = statusCodeFragment.createChild('label', 'resource-status-image', 'dt-icon-label');
+ const statusCodeImage = statusCodeFragment.createChild('span', 'resource-status-image', 'dt-icon-label');
statusCodeImage.title = this._request.statusCode + ' ' + this._request.statusText;
if (this._request.statusCode < 300 || this._request.statusCode === 304)
@@ -440,7 +440,7 @@
if (provisionalHeaders) {
const cautionText = Common.UIString('Provisional headers are shown');
const cautionFragment = createDocumentFragment();
- cautionFragment.createChild('label', '', 'dt-icon-label').type = 'smallicon-warning';
+ cautionFragment.createChild('span', '', 'dt-icon-label').type = 'smallicon-warning';
cautionFragment.createChild('div', 'caution').textContent = cautionText;
const cautionTreeElement = new UI.TreeElement(cautionFragment);
cautionTreeElement.selectable = false;
diff --git a/src/cobalt/debug/remote/devtools/front_end/network/networkConfigView.css b/src/cobalt/debug/remote/devtools/front_end/network/networkConfigView.css
index 5c9f81f..6377126 100644
--- a/src/cobalt/debug/remote/devtools/front_end/network/networkConfigView.css
+++ b/src/cobalt/debug/remote/devtools/front_end/network/networkConfigView.css
@@ -57,11 +57,11 @@
line-height: 20px;
}
-.network-config-ua label[is="dt-radio"].checked > * {
+.network-config-ua span[is="dt-radio"].checked > * {
display: none
}
-.network-config-ua input:not(.dt-radio-button) {
+.network-config-ua input {
display: block;
width: calc(100% - 20px);
max-width: 250px;
diff --git a/src/cobalt/debug/remote/devtools/front_end/network/networkLogView.css b/src/cobalt/debug/remote/devtools/front_end/network/networkLogView.css
index b7240de..bf39802 100644
--- a/src/cobalt/debug/remote/devtools/front_end/network/networkLogView.css
+++ b/src/cobalt/debug/remote/devtools/front_end/network/networkLogView.css
@@ -44,7 +44,7 @@
overflow: hidden;
}
-.network-summary-bar label[is=dt-icon-label] {
+.network-summary-bar span[is=dt-icon-label] {
margin-right: 6px;
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/object_ui/ObjectPropertiesSection.js b/src/cobalt/debug/remote/devtools/front_end/object_ui/ObjectPropertiesSection.js
index 88a7f85..5cdc53f 100644
--- a/src/cobalt/debug/remote/devtools/front_end/object_ui/ObjectPropertiesSection.js
+++ b/src/cobalt/debug/remote/devtools/front_end/object_ui/ObjectPropertiesSection.js
@@ -426,7 +426,7 @@
* @param {!Array.<!SDK.RemoteObjectProperty>=} extraProperties
*/
constructor(object, linkifier, emptyPlaceholder, ignoreHasOwnProperty, extraProperties) {
- const contentElement = createElement('content');
+ const contentElement = createElement('slot');
super(contentElement);
this._object = object;
diff --git a/src/cobalt/debug/remote/devtools/front_end/profiler/profilesPanel.css b/src/cobalt/debug/remote/devtools/front_end/profiler/profilesPanel.css
index eab0f1d..4a5384a 100644
--- a/src/cobalt/debug/remote/devtools/front_end/profiler/profilesPanel.css
+++ b/src/cobalt/debug/remote/devtools/front_end/profiler/profilesPanel.css
@@ -128,7 +128,7 @@
margin: 0 0 5px 0;
}
-.profile-launcher-view-content label {
+.profile-launcher-view-content [is=dt-radio] {
font-size: 13px;
}
@@ -165,7 +165,7 @@
margin-left: 22px;
}
-.profile-launcher-view-content p label {
+.profile-launcher-view-content p [is=dt-checkbox] {
display: flex;
}
@@ -190,7 +190,7 @@
to { background-color: rgba(255, 255, 120, 0); }
}
-.profile-canvas-decoration label[is=dt-icon-label] {
+.profile-canvas-decoration span[is=dt-icon-label] {
margin-right: 4px;
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/resources/ApplicationCacheItemsView.js b/src/cobalt/debug/remote/devtools/front_end/resources/ApplicationCacheItemsView.js
index 6c2373b..4f9dcfd 100644
--- a/src/cobalt/debug/remote/devtools/front_end/resources/ApplicationCacheItemsView.js
+++ b/src/cobalt/debug/remote/devtools/front_end/resources/ApplicationCacheItemsView.js
@@ -38,9 +38,9 @@
this._deleteButton.setVisible(false);
this._deleteButton.addEventListener(UI.ToolbarButton.Events.Click, this._deleteButtonClicked, this);
- this._connectivityIcon = createElement('label', 'dt-icon-label');
+ this._connectivityIcon = createElement('span', 'dt-icon-label');
this._connectivityIcon.style.margin = '0 2px 0 5px';
- this._statusIcon = createElement('label', 'dt-icon-label');
+ this._statusIcon = createElement('span', 'dt-icon-label');
this._statusIcon.style.margin = '0 2px 0 5px';
this._frameId = frameId;
diff --git a/src/cobalt/debug/remote/devtools/front_end/security/SecurityPanel.js b/src/cobalt/debug/remote/devtools/front_end/security/SecurityPanel.js
index 44f890f..693249d 100644
--- a/src/cobalt/debug/remote/devtools/front_end/security/SecurityPanel.js
+++ b/src/cobalt/debug/remote/devtools/front_end/security/SecurityPanel.js
@@ -78,7 +78,7 @@
return text;
}
- const highlightedUrl = createElement('span', 'url-text');
+ const highlightedUrl = createElement('span');
const scheme = url.substr(0, index);
const content = url.substr(index + schemeSeparator.length);
diff --git a/src/cobalt/debug/remote/devtools/front_end/settings/settingsScreen.css b/src/cobalt/debug/remote/devtools/front_end/settings/settingsScreen.css
index 47c80a7..9989041 100644
--- a/src/cobalt/debug/remote/devtools/front_end/settings/settingsScreen.css
+++ b/src/cobalt/debug/remote/devtools/front_end/settings/settingsScreen.css
@@ -211,15 +211,11 @@
margin-left: 10px;
}
-.settings-indent-labels label {
- padding-left: 10px;
-}
-
.settings-experiment-hidden {
display: none;
}
-.settings-experiment-hidden label {
+.settings-experiment-hidden [is=dt-checkbox] {
background-color: #ddd;
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/sources/UISourceCodeFrame.js b/src/cobalt/debug/remote/devtools/front_end/sources/UISourceCodeFrame.js
index 47de620..27ee88e 100644
--- a/src/cobalt/debug/remote/devtools/front_end/sources/UISourceCodeFrame.js
+++ b/src/cobalt/debug/remote/devtools/front_end/sources/UISourceCodeFrame.js
@@ -582,7 +582,7 @@
this._icon = this.element.createChild('label', '', 'dt-icon-label');
this._icon.type = Sources.UISourceCodeFrame._iconClassPerLevel[message.level()];
this._repeatCountElement =
- this.element.createChild('label', 'text-editor-row-message-repeat-count hidden', 'dt-small-bubble');
+ this.element.createChild('span', 'text-editor-row-message-repeat-count hidden', 'dt-small-bubble');
this._repeatCountElement.type = Sources.UISourceCodeFrame._bubbleTypePerLevel[message.level()];
const linesContainer = this.element.createChild('div');
const lines = this._message.text().split('\n');
@@ -634,7 +634,7 @@
this._decoration = createElementWithClass('div', 'text-editor-line-decoration');
this._decoration._messageBucket = this;
this._wave = this._decoration.createChild('div', 'text-editor-line-decoration-wave');
- this._icon = this._wave.createChild('label', 'text-editor-line-decoration-icon', 'dt-icon-label');
+ this._icon = this._wave.createChild('span', 'text-editor-line-decoration-icon', 'dt-icon-label');
/** @type {?number} */
this._decorationStartColumn = null;
diff --git a/src/cobalt/debug/remote/devtools/front_end/sources/sourcesPanel.css b/src/cobalt/debug/remote/devtools/front_end/sources/sourcesPanel.css
index 4b49787..17d4d4a 100644
--- a/src/cobalt/debug/remote/devtools/front_end/sources/sourcesPanel.css
+++ b/src/cobalt/debug/remote/devtools/front_end/sources/sourcesPanel.css
@@ -50,7 +50,7 @@
margin-top: 0;
}
-.scripts-debug-toolbar-drawer > label {
+.scripts-debug-toolbar-drawer > [is=dt-checkbox] {
display: flex;
padding-left: 3px;
height: 28px;
diff --git a/src/cobalt/debug/remote/devtools/front_end/timeline/TimelineHistoryManager.js b/src/cobalt/debug/remote/devtools/front_end/timeline/TimelineHistoryManager.js
index 7bd3fc0..ecd5308 100644
--- a/src/cobalt/debug/remote/devtools/front_end/timeline/TimelineHistoryManager.js
+++ b/src/cobalt/debug/remote/devtools/front_end/timeline/TimelineHistoryManager.js
@@ -426,12 +426,11 @@
* @param {!UI.Action} action
*/
constructor(action) {
- super(createElementWithClass('button', 'dropdown-button'));
- const shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'timeline/historyToolbarButton.css');
-
- this._contentElement = shadowRoot.createChild('span', 'content');
+ super(createElementWithClass('button', 'history-dropdown-button'));
+ UI.appendStyle(this.element, 'timeline/historyToolbarButton.css');
+ this._contentElement = this.element.createChild('span', 'content');
const dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down');
- shadowRoot.appendChild(dropdownArrowIcon);
+ this.element.appendChild(dropdownArrowIcon);
this.element.addEventListener('click', () => void action.execute(), false);
this.setEnabled(action.enabled());
action.addEventListener(UI.Action.Events.Enabled, event => this.setEnabled(/** @type {boolean} */ (event.data)));
diff --git a/src/cobalt/debug/remote/devtools/front_end/timeline/historyToolbarButton.css b/src/cobalt/debug/remote/devtools/front_end/timeline/historyToolbarButton.css
index f66188b..0259abf 100644
--- a/src/cobalt/debug/remote/devtools/front_end/timeline/historyToolbarButton.css
+++ b/src/cobalt/debug/remote/devtools/front_end/timeline/historyToolbarButton.css
@@ -4,18 +4,18 @@
* found in the LICENSE file.
*/
-:host {
+.history-dropdown-button {
width: 160px;
height: 26px;
text-align: left;
display: flex;
}
-:host([disabled]) {
+.history-dropdown-button[disabled] {
opacity: .5;
}
-.content {
+.history-dropdown-button > .content {
padding-right: 5px;
overflow: hidden;
text-overflow: ellipsis;
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/HistoryInput.js b/src/cobalt/debug/remote/devtools/front_end/ui/HistoryInput.js
index b5cefa7..81784fc 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/HistoryInput.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/HistoryInput.js
@@ -5,24 +5,21 @@
* @unrestricted
*/
UI.HistoryInput = class extends HTMLInputElement {
+ constructor() {
+ super();
+ this._history = [''];
+ this._historyPosition = 0;
+ this.addEventListener('keydown', this._onKeyDown.bind(this), false);
+ this.addEventListener('input', this._onInput.bind(this), false);
+ }
/**
* @return {!UI.HistoryInput}
*/
static create() {
if (!UI.HistoryInput._constructor)
- UI.HistoryInput._constructor = UI.registerCustomElement('input', 'history-input', UI.HistoryInput.prototype);
+ UI.HistoryInput._constructor = UI.registerCustomElement('input', 'history-input', UI.HistoryInput);
- return /** @type {!UI.HistoryInput} */ (new UI.HistoryInput._constructor());
- }
-
- /**
- * @override
- */
- createdCallback() {
- this._history = [''];
- this._historyPosition = 0;
- this.addEventListener('keydown', this._onKeyDown.bind(this), false);
- this.addEventListener('input', this._onInput.bind(this), false);
+ return /** @type {!UI.HistoryInput} */ (UI.HistoryInput._constructor());
}
/**
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/Icon.js b/src/cobalt/debug/remote/devtools/front_end/ui/Icon.js
index 9ba57c8..2df6469 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/Icon.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/Icon.js
@@ -2,14 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/**
- * @constructor
- * @extends {HTMLSpanElement}
- */
UI.Icon = class extends HTMLSpanElement {
constructor() {
super();
- throw new Error('icon must be created via factory method.');
+ /** @type {?UI.Icon.Descriptor} */
+ this._descriptor = null;
+ /** @type {?UI.Icon.SpriteSheet} */
+ this._spriteSheet = null;
+ /** @type {string} */
+ this._iconType = '';
}
/**
@@ -19,9 +20,9 @@
*/
static create(iconType, className) {
if (!UI.Icon._constructor)
- UI.Icon._constructor = UI.registerCustomElement('span', 'ui-icon', UI.Icon.prototype);
+ UI.Icon._constructor = UI.registerCustomElement('span', 'ui-icon', UI.Icon);
- const icon = /** @type {!UI.Icon} */ (new UI.Icon._constructor());
+ const icon = /** @type {!UI.Icon} */ (UI.Icon._constructor());
if (className)
icon.className = className;
if (iconType)
@@ -30,18 +31,6 @@
}
/**
- * @override
- */
- createdCallback() {
- /** @type {?UI.Icon.Descriptor} */
- this._descriptor = null;
- /** @type {?UI.Icon.SpriteSheet} */
- this._spriteSheet = null;
- /** @type {string} */
- this._iconType = '';
- }
-
- /**
* @param {string} iconType
*/
setIconType(iconType) {
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/ListWidget.js b/src/cobalt/debug/remote/devtools/front_end/ui/ListWidget.js
index c11ae3a..0ba4777 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/ListWidget.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/ListWidget.js
@@ -9,12 +9,11 @@
* @param {!UI.ListWidget.Delegate<T>} delegate
*/
constructor(delegate) {
- super(true);
+ super(true, true /* delegatesFocus */);
this.registerRequiredCSS('ui/listWidget.css');
this._delegate = delegate;
this._list = this.contentElement.createChild('div', 'list');
- this.element.tabIndex = -1;
this._lastSeparator = false;
/** @type {?UI.ElementFocusRestorer} */
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/SearchableView.js b/src/cobalt/debug/remote/devtools/front_end/ui/SearchableView.js
index a0fa78f..f03af0f 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/SearchableView.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/SearchableView.js
@@ -46,7 +46,7 @@
this._setting = settingName ? Common.settings.createSetting(settingName, {}) : null;
this._replaceable = false;
- this.contentElement.createChild('content');
+ this.contentElement.createChild('slot');
this._footerElementContainer = this.contentElement.createChild('div', 'search-bar hidden');
this._footerElementContainer.style.order = 100;
this._footerElement = this._footerElementContainer.createChild('div', 'toolbar-search');
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/SoftDropDown.js b/src/cobalt/debug/remote/devtools/front_end/ui/SoftDropDown.js
index 88e8e97..6d21c34 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/SoftDropDown.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/SoftDropDown.js
@@ -16,10 +16,10 @@
this._model = model;
this.element = createElementWithClass('button', 'soft-dropdown');
- const shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/softDropDownButton.css');
- this._titleElement = shadowRoot.createChild('span', 'title');
+ UI.appendStyle(this.element, 'ui/softDropDownButton.css');
+ this._titleElement = this.element.createChild('span', 'title');
const dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down');
- shadowRoot.appendChild(dropdownArrowIcon);
+ this.element.appendChild(dropdownArrowIcon);
this._glassPane = new UI.GlassPane();
this._glassPane.setMarginBehavior(UI.GlassPane.MarginBehavior.NoMargin);
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/SplitWidget.js b/src/cobalt/debug/remote/devtools/front_end/ui/SplitWidget.js
index f0b55ed..950b230 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/SplitWidget.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/SplitWidget.js
@@ -46,10 +46,10 @@
this.contentElement.classList.add('shadow-split-widget');
this._mainElement =
this.contentElement.createChild('div', 'shadow-split-widget-contents shadow-split-widget-main vbox');
- this._mainElement.createChild('content').select = '.insertion-point-main';
+ this._mainElement.createChild('slot').name = 'insertion-point-main';
this._sidebarElement =
this.contentElement.createChild('div', 'shadow-split-widget-contents shadow-split-widget-sidebar vbox');
- this._sidebarElement.createChild('content').select = '.insertion-point-sidebar';
+ this._sidebarElement.createChild('slot').name = 'insertion-point-sidebar';
this._resizerElement = this.contentElement.createChild('div', 'shadow-split-widget-resizer');
this._resizerElementSize = null;
@@ -165,8 +165,7 @@
this._mainWidget.detach();
this._mainWidget = widget;
if (widget) {
- widget.element.classList.add('insertion-point-main');
- widget.element.classList.remove('insertion-point-sidebar');
+ widget.element.slot = 'insertion-point-main';
if (this._showMode === UI.SplitWidget.ShowMode.OnlyMain || this._showMode === UI.SplitWidget.ShowMode.Both)
widget.show(this.element);
}
@@ -184,8 +183,7 @@
this._sidebarWidget.detach();
this._sidebarWidget = widget;
if (widget) {
- widget.element.classList.add('insertion-point-sidebar');
- widget.element.classList.remove('insertion-point-main');
+ widget.element.slot = 'insertion-point-sidebar';
if (this._showMode === UI.SplitWidget.ShowMode.OnlySidebar || this._showMode === UI.SplitWidget.ShowMode.Both)
widget.show(this.element);
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/TabbedPane.js b/src/cobalt/debug/remote/devtools/front_end/ui/TabbedPane.js
index 44db82d..dfad749 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/TabbedPane.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/TabbedPane.js
@@ -46,7 +46,7 @@
this._tabsElement.addEventListener('keydown', this._keyDown.bind(this), false);
this._contentElement = this.contentElement.createChild('div', 'tabbed-pane-content');
this._contentElement.setAttribute('role', 'tabpanel');
- this._contentElement.createChild('content');
+ this._contentElement.createChild('slot');
/** @type {!Array.<!UI.TabbedPaneTab>} */
this._tabs = [];
/** @type {!Array.<!UI.TabbedPaneTab>} */
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/Toolbar.js b/src/cobalt/debug/remote/devtools/front_end/ui/Toolbar.js
index 790a753..4f8d0bf 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/Toolbar.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/Toolbar.js
@@ -45,7 +45,7 @@
this._enabled = true;
this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/toolbar.css');
this._contentElement = this._shadowRoot.createChild('div', 'toolbar-shadow');
- this._insertionPoint = this._contentElement.createChild('content');
+ this._insertionPoint = this._contentElement.createChild('slot');
}
/**
@@ -265,7 +265,7 @@
delete item._toolbar;
this._items = [];
this._contentElement.removeChildren();
- this._insertionPoint = this._contentElement.createChild('content');
+ this._insertionPoint = this._contentElement.createChild('slot');
}
/**
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/Tooltip.js b/src/cobalt/debug/remote/devtools/front_end/ui/Tooltip.js
index a8034a0..253f22f 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/Tooltip.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/Tooltip.js
@@ -54,7 +54,7 @@
*/
_mouseMove(event) {
const mouseEvent = /** @type {!MouseEvent} */ (event);
- const path = mouseEvent.path;
+ const path = mouseEvent.composedPath();
if (!path || mouseEvent.buttons !== 0 || (mouseEvent.movementX === 0 && mouseEvent.movementY === 0))
return;
@@ -63,7 +63,8 @@
for (const element of path) {
// The offsetParent is null when the element or an ancestor has 'display: none'.
- if (element === this._anchorElement || (element.nodeName !== 'CONTENT' && element.offsetParent === null)) {
+ if (!(element instanceof Element) || element === this._anchorElement ||
+ (element.nodeName !== 'SLOT' && element.offsetParent === null)) {
return;
} else if (element[UI.Tooltip._symbol]) {
this._show(element, mouseEvent);
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/UIUtils.js b/src/cobalt/debug/remote/devtools/front_end/ui/UIUtils.js
index 9c2761c..21e6412 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/UIUtils.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/UIUtils.js
@@ -674,9 +674,7 @@
* @param {!Element} element
*/
UI.installComponentRootStyles = function(element) {
- UI.appendStyle(element, 'ui/inspectorCommon.css');
- UI.themeSupport.injectHighlightStyleSheets(element);
- UI.themeSupport.injectCustomStyleSheets(element);
+ UI._injectCoreStyles(element);
element.classList.add('platform-' + Host.platform());
// Detect overlay scrollbar enable by checking for nonzero scrollbar width.
@@ -704,13 +702,12 @@
/**
* @param {!Element} element
* @param {string=} cssFile
+ * @param {boolean=} delegatesFocus
* @return {!DocumentFragment}
*/
-UI.createShadowRootWithCoreStyles = function(element, cssFile) {
- const shadowRoot = element.createShadowRoot();
- UI.appendStyle(shadowRoot, 'ui/inspectorCommon.css');
- UI.themeSupport.injectHighlightStyleSheets(shadowRoot);
- UI.themeSupport.injectCustomStyleSheets(shadowRoot);
+UI.createShadowRootWithCoreStyles = function(element, cssFile, delegatesFocus) {
+ const shadowRoot = element.attachShadow({mode: 'open', delegatesFocus});
+ UI._injectCoreStyles(shadowRoot);
if (cssFile)
UI.appendStyle(shadowRoot, cssFile);
shadowRoot.addEventListener('focus', UI._focusChanged.bind(UI), true);
@@ -718,6 +715,16 @@
};
/**
+ * @param {!Element|!ShadowRoot} root
+ */
+UI._injectCoreStyles = function(root) {
+ UI.appendStyle(root, 'ui/inspectorCommon.css');
+ UI.appendStyle(root, 'ui/textButton.css');
+ UI.themeSupport.injectHighlightStyleSheets(root);
+ UI.themeSupport.injectCustomStyleSheets(root);
+};
+
+/**
* @param {!Document} document
* @param {!Event} event
*/
@@ -1166,13 +1173,19 @@
/**
* @param {string} localName
* @param {string} typeExtension
- * @param {!Object} prototype
+ * @param {function(new:HTMLElement, *)} definition
* @return {function()}
* @suppressGlobalPropertiesCheck
- * @template T
*/
-UI.registerCustomElement = function(localName, typeExtension, prototype) {
- return document.registerElement(typeExtension, {prototype: Object.create(prototype), extends: localName});
+UI.registerCustomElement = function(localName, typeExtension, definition) {
+ self.customElements.define(typeExtension, class extends definition {
+ constructor() {
+ super();
+ // TODO(einbinder) convert to classes and custom element tags
+ this.setAttribute('is', typeExtension);
+ }
+ }, {extends: localName});
+ return () => createElement(localName, typeExtension);
};
/**
@@ -1183,12 +1196,14 @@
* @return {!Element}
*/
UI.createTextButton = function(text, clickHandler, className, primary) {
- const element = createElementWithClass('button', className || '', 'text-button');
+ const element = createElementWithClass('button', className || '');
element.textContent = text;
+ element.classList.add('text-button');
if (primary)
element.classList.add('primary-button');
if (clickHandler)
element.addEventListener('click', clickHandler, false);
+ element.type = 'button';
return element;
};
@@ -1213,10 +1228,10 @@
* @return {!Element}
*/
UI.createRadioLabel = function(name, title, checked) {
- const element = createElement('label', 'dt-radio');
+ const element = createElement('span', 'dt-radio');
element.radioElement.name = name;
element.radioElement.checked = !!checked;
- element.createTextChild(title);
+ element.labelElement.createTextChild(title);
return element;
};
@@ -1226,7 +1241,7 @@
* @return {!Element}
*/
UI.createLabel = function(title, iconClass) {
- const element = createElement('label', 'dt-icon-label');
+ const element = createElement('span', 'dt-icon-label');
element.createChild('span').textContent = title;
element.type = iconClass;
return element;
@@ -1238,8 +1253,8 @@
* @param {number} max
* @param {number} tabIndex
*/
-UI.createSliderLabel = function(min, max, tabIndex) {
- const element = createElement('label', 'dt-slider');
+UI.createSlider = function(min, max, tabIndex) {
+ const element = createElement('span', 'dt-slider');
element.sliderElement.min = min;
element.sliderElement.max = max;
element.sliderElement.step = 1;
@@ -1270,10 +1285,7 @@
}
};
-/**
- * @extends {HTMLLabelElement}
- */
-UI.CheckboxLabel = class extends HTMLLabelElement {
+UI.CheckboxLabel = class extends HTMLSpanElement {
constructor() {
super();
/** @type {!DocumentFragment} */
@@ -1282,13 +1294,6 @@
this.checkboxElement;
/** @type {!Element} */
this.textElement;
- throw new Error('Checkbox must be created via factory method.');
- }
-
- /**
- * @override
- */
- createdCallback() {
UI.CheckboxLabel._lastId = (UI.CheckboxLabel._lastId || 0) + 1;
const id = 'ui-checkbox-label' + UI.CheckboxLabel._lastId;
this._shadowRoot = UI.createShadowRootWithCoreStyles(this, 'ui/checkboxTextLabel.css');
@@ -1297,7 +1302,7 @@
this.checkboxElement.setAttribute('id', id);
this.textElement = this._shadowRoot.createChild('label', 'dt-checkbox-text');
this.textElement.setAttribute('for', id);
- this._shadowRoot.createChild('content');
+ this._shadowRoot.createChild('slot');
}
/**
@@ -1308,8 +1313,8 @@
*/
static create(title, checked, subtitle) {
if (!UI.CheckboxLabel._constructor)
- UI.CheckboxLabel._constructor = UI.registerCustomElement('label', 'dt-checkbox', UI.CheckboxLabel.prototype);
- const element = /** @type {!UI.CheckboxLabel} */ (new UI.CheckboxLabel._constructor());
+ UI.CheckboxLabel._constructor = UI.registerCustomElement('span', 'dt-checkbox', UI.CheckboxLabel);
+ const element = /** @type {!UI.CheckboxLabel} */ (UI.CheckboxLabel._constructor());
element.checkboxElement.checked = !!checked;
if (title !== undefined) {
element.textElement.textContent = title;
@@ -1350,152 +1355,124 @@
};
(function() {
- UI.registerCustomElement('button', 'text-button', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- this.type = 'button';
- const root = UI.createShadowRootWithCoreStyles(this, 'ui/textButton.css');
- root.createChild('content');
- },
+let labelId = 0;
+UI.registerCustomElement('span', 'dt-radio', class extends HTMLSpanElement {
+ constructor() {
+ super();
+ this.radioElement = this.createChild('input', 'dt-radio-button');
+ this.labelElement = this.createChild('label');
- __proto__: HTMLButtonElement.prototype
- });
+ const id = 'dt-radio-button-id' + (++labelId);
+ this.radioElement.id = id;
+ this.radioElement.type = 'radio';
+ this.labelElement.htmlFor = id;
+ const root = UI.createShadowRootWithCoreStyles(this, 'ui/radioButton.css');
+ root.createChild('slot');
+ this.addEventListener('click', radioClickHandler, false);
+ }
+});
- UI.registerCustomElement('label', 'dt-radio', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- this.radioElement = this.createChild('input', 'dt-radio-button');
- this.radioElement.type = 'radio';
- const root = UI.createShadowRootWithCoreStyles(this, 'ui/radioButton.css');
- root.createChild('content').select = '.dt-radio-button';
- root.createChild('content');
- this.addEventListener('click', radioClickHandler, false);
- },
-
- __proto__: HTMLLabelElement.prototype
- });
-
- /**
+/**
* @param {!Event} event
* @suppressReceiverCheck
* @this {Element}
*/
- function radioClickHandler(event) {
- if (this.radioElement.checked || this.radioElement.disabled)
- return;
- this.radioElement.checked = true;
- this.radioElement.dispatchEvent(new Event('change'));
+function radioClickHandler(event) {
+ if (this.radioElement.checked || this.radioElement.disabled)
+ return;
+ this.radioElement.checked = true;
+ this.radioElement.dispatchEvent(new Event('change'));
+}
+
+UI.registerCustomElement('span', 'dt-icon-label', class extends HTMLSpanElement {
+ constructor() {
+ super();
+ const root = UI.createShadowRootWithCoreStyles(this);
+ this._iconElement = UI.Icon.create();
+ this._iconElement.style.setProperty('margin-right', '4px');
+ root.appendChild(this._iconElement);
+ root.createChild('slot');
}
- UI.registerCustomElement('label', 'dt-icon-label', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- const root = UI.createShadowRootWithCoreStyles(this);
- this._iconElement = UI.Icon.create();
- this._iconElement.style.setProperty('margin-right', '4px');
- root.appendChild(this._iconElement);
- root.createChild('content');
- },
-
- /**
+ /**
* @param {string} type
* @this {Element}
*/
- set type(type) {
- this._iconElement.setIconType(type);
- },
+ set type(type) {
+ this._iconElement.setIconType(type);
+ }
+});
- __proto__: HTMLLabelElement.prototype
- });
+UI.registerCustomElement('span', 'dt-slider', class extends HTMLSpanElement {
+ constructor() {
+ super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'ui/slider.css');
+ this.sliderElement = createElementWithClass('input', 'dt-range-input');
+ this.sliderElement.type = 'range';
+ root.appendChild(this.sliderElement);
+ }
- UI.registerCustomElement('label', 'dt-slider', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- const root = UI.createShadowRootWithCoreStyles(this, 'ui/slider.css');
- this.sliderElement = createElementWithClass('input', 'dt-range-input');
- this.sliderElement.type = 'range';
- root.appendChild(this.sliderElement);
- },
-
- /**
+ /**
* @param {number} amount
* @this {Element}
*/
- set value(amount) {
- this.sliderElement.value = amount;
- },
+ set value(amount) {
+ this.sliderElement.value = amount;
+ }
- /**
+ /**
* @this {Element}
*/
- get value() {
- return this.sliderElement.value;
- },
+ get value() {
+ return this.sliderElement.value;
+ }
+});
- __proto__: HTMLLabelElement.prototype
- });
+UI.registerCustomElement('span', 'dt-small-bubble', class extends HTMLSpanElement {
+ constructor() {
+ super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'ui/smallBubble.css');
+ this._textElement = root.createChild('div');
+ this._textElement.className = 'info';
+ this._textElement.createChild('slot');
+ }
- UI.registerCustomElement('label', 'dt-small-bubble', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- const root = UI.createShadowRootWithCoreStyles(this, 'ui/smallBubble.css');
- this._textElement = root.createChild('div');
- this._textElement.className = 'info';
- this._textElement.createChild('content');
- },
-
- /**
+ /**
* @param {string} type
* @this {Element}
*/
- set type(type) {
- this._textElement.className = type;
- },
+ set type(type) {
+ this._textElement.className = type;
+ }
+});
- __proto__: HTMLLabelElement.prototype
- });
+UI.registerCustomElement('div', 'dt-close-button', class extends HTMLDivElement {
+ constructor() {
+ super();
+ const root = UI.createShadowRootWithCoreStyles(this, 'ui/closeButton.css');
+ this._buttonElement = root.createChild('div', 'close-button');
+ const regularIcon = UI.Icon.create('smallicon-cross', 'default-icon');
+ this._hoverIcon = UI.Icon.create('mediumicon-red-cross-hover', 'hover-icon');
+ this._activeIcon = UI.Icon.create('mediumicon-red-cross-active', 'active-icon');
+ this._buttonElement.appendChild(regularIcon);
+ this._buttonElement.appendChild(this._hoverIcon);
+ this._buttonElement.appendChild(this._activeIcon);
+ }
- UI.registerCustomElement('div', 'dt-close-button', {
- /**
- * @this {Element}
- */
- createdCallback: function() {
- const root = UI.createShadowRootWithCoreStyles(this, 'ui/closeButton.css');
- this._buttonElement = root.createChild('div', 'close-button');
- const regularIcon = UI.Icon.create('smallicon-cross', 'default-icon');
- this._hoverIcon = UI.Icon.create('mediumicon-red-cross-hover', 'hover-icon');
- this._activeIcon = UI.Icon.create('mediumicon-red-cross-active', 'active-icon');
- this._buttonElement.appendChild(regularIcon);
- this._buttonElement.appendChild(this._hoverIcon);
- this._buttonElement.appendChild(this._activeIcon);
- },
-
- /**
+ /**
* @param {boolean} gray
* @this {Element}
*/
- set gray(gray) {
- if (gray) {
- this._hoverIcon.setIconType('mediumicon-gray-cross-hover');
- this._activeIcon.setIconType('mediumicon-gray-cross-active');
- } else {
- this._hoverIcon.setIconType('mediumicon-red-cross-hover');
- this._activeIcon.setIconType('mediumicon-red-cross-active');
- }
- },
-
- __proto__: HTMLDivElement.prototype
- });
+ set gray(gray) {
+ if (gray) {
+ this._hoverIcon.setIconType('mediumicon-gray-cross-hover');
+ this._activeIcon.setIconType('mediumicon-gray-cross-active');
+ } else {
+ this._hoverIcon.setIconType('mediumicon-red-cross-hover');
+ this._activeIcon.setIconType('mediumicon-red-cross-active');
+ }
+ }
+});
})();
/**
@@ -1681,7 +1658,7 @@
}
/**
- * @param {!Element} element
+ * @param {!Element|!ShadowRoot} element
*/
injectHighlightStyleSheets(element) {
this._injectingStyleSheet = true;
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/View.js b/src/cobalt/debug/remote/devtools/front_end/ui/View.js
index bc3d3be..96a784c 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/View.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/View.js
@@ -506,7 +506,7 @@
this._titleElement.addEventListener('keydown', this._onTitleKeyDown.bind(this), false);
this.contentElement.insertBefore(this._titleElement, this.contentElement.firstChild);
- this.contentElement.createChild('content');
+ this.contentElement.createChild('slot');
this._view = view;
view[UI.ViewManager._ExpandableContainerWidget._symbol] = this;
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/Widget.js b/src/cobalt/debug/remote/devtools/front_end/ui/Widget.js
index 861f157..611890d 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/Widget.js
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/Widget.js
@@ -30,13 +30,14 @@
UI.Widget = class extends Common.Object {
/**
* @param {boolean=} isWebComponent
+ * @param {boolean=} delegatesFocus
*/
- constructor(isWebComponent) {
+ constructor(isWebComponent, delegatesFocus) {
super();
this.contentElement = createElementWithClass('div', 'widget');
if (isWebComponent) {
this.element = createElementWithClass('div', 'vbox flex-auto');
- this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element);
+ this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, undefined, delegatesFocus);
this._shadowRoot.appendChild(this.contentElement);
} else {
this.element = this.contentElement;
@@ -599,9 +600,10 @@
UI.VBox = class extends UI.Widget {
/**
* @param {boolean=} isWebComponent
+ * @param {boolean=} delegatesFocus
*/
- constructor(isWebComponent) {
- super(isWebComponent);
+ constructor(isWebComponent, delegatesFocus) {
+ super(isWebComponent, delegatesFocus);
this.contentElement.classList.add('vbox');
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/filter.css b/src/cobalt/debug/remote/devtools/front_end/ui/filter.css
index 025789e..b09df81 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/filter.css
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/filter.css
@@ -46,10 +46,6 @@
align-items: center;
}
-.filter-text-filter label {
- margin: auto 0;
-}
-
.filter-bitset-filter {
padding: 2px;
display: inline-flex;
@@ -116,7 +112,7 @@
position: relative;
}
-.filter-checkbox-filter > label {
+.filter-checkbox-filter > [is=dt-checkbox] {
display: flex;
margin: auto 0;
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/inspectorCommon.css b/src/cobalt/debug/remote/devtools/front_end/ui/inspectorCommon.css
index 2e7fa6e..a65be85 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/inspectorCommon.css
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/inspectorCommon.css
@@ -306,7 +306,7 @@
white-space: nowrap;
}
-label[is=dt-icon-label] {
+span[is=dt-icon-label] {
flex: none;
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/radioButton.css b/src/cobalt/debug/remote/devtools/front_end/ui/radioButton.css
index 47f4775..cadf3a7 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/radioButton.css
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/radioButton.css
@@ -4,7 +4,7 @@
* found in the LICENSE file.
*/
-::content .dt-radio-button {
+::slotted(input.dt-radio-button) {
height: 17px;
width: 17px;
min-width: 17px;
@@ -16,16 +16,16 @@
margin: 0 5px 5px 0;
}
-::content .dt-radio-button:active:not(:disabled) {
+::slotted(input.dt-radio-button:active:not(:disabled)) {
background-image: linear-gradient(to bottom, rgb(194, 194, 194), rgb(239, 239, 239));
}
-::content .dt-radio-button:checked {
+::slotted(input.dt-radio-button:checked) {
background: url(Images/radioDot.png) center no-repeat,
linear-gradient(to bottom, rgb(252, 252, 252), rgb(223, 223, 223));
}
-::content .dt-radio-button:checked:active {
+::slotted(input.dt-radio-button:checked:active) {
background: url(Images/radioDot.png) center no-repeat,
linear-gradient(to bottom, rgb(194, 194, 194), rgb(239, 239, 239));
}
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/softDropDownButton.css b/src/cobalt/debug/remote/devtools/front_end/ui/softDropDownButton.css
index 3812ef1..2270d27 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/softDropDownButton.css
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/softDropDownButton.css
@@ -3,7 +3,7 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
-:host {
+button.soft-dropdown {
height: 26px;
text-align: left;
position: relative;
@@ -11,18 +11,18 @@
background: none;
}
-:host([disabled]) {
+button.soft-dropdown[disabled] {
opacity: .5;
}
-:host .title {
+button.soft-dropdown > .title {
padding-right: 5px;
width: 120px;
overflow: hidden;
text-overflow: ellipsis;
}
-:host([data-keyboard-focus="true"]:focus)::before {
+button.soft-dropdown[data-keyboard-focus="true"]:focus::before {
content: "";
position: absolute;
top: 2px;
diff --git a/src/cobalt/debug/remote/devtools/front_end/ui/textButton.css b/src/cobalt/debug/remote/devtools/front_end/ui/textButton.css
index 001189a..cce75fa 100644
--- a/src/cobalt/debug/remote/devtools/front_end/ui/textButton.css
+++ b/src/cobalt/debug/remote/devtools/front_end/ui/textButton.css
@@ -4,7 +4,7 @@
* found in the LICENSE file.
*/
-:host {
+ .text-button {
margin: 2px;
height: 24px;
font-size: 12px;
@@ -18,52 +18,49 @@
white-space: nowrap;
}
-:host(:not(:disabled):focus),
-:host(:not(:disabled):hover),
-:host(:not(:disabled):active) {
+.text-button:not(:disabled):focus,
+.text-button:not(:disabled):hover,
+.text-button:not(:disabled):active {
background-color: var(--toolbar-bg-color);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
cursor: pointer;
}
-:host(:not(:disabled):active) {
+.text-button:not(:disabled):active {
background-color: #f2f2f2;
}
-:host(:not(:disabled):focus) {
+.text-button:not(:disabled):focus {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(66, 133, 244, 0.4);
}
-:host(:disabled) {
+.text-button:disabled {
opacity: 0.38;
}
-:host(.primary-button), -theme-preserve {
+.text-button.primary-button, -theme-preserve {
background-color: #4285F4;
border: none;
color: #fff;
}
-:host(.primary-button:not(:disabled):focus),
-:host(.primary-button:not(:disabled):hover), -theme-preserve {
- background-color: #3B78E7;
+.text-button.primary-button:not(:disabled):focus,
+.text-button.primary-button:not(:disabled):hover,
+.text-button.primary-button:not(:disabled):active, -theme-preserve {
+ background-color: var(--accent-color-hover);
}
-:host(.primary-button:not(:disabled):active), -theme-preserve {
- background-color: #3367D6;
-}
-
-:host-context(.-theme-with-dark-background):host(:not(.primary-button):not(:disabled):focus),
-:host-context(.-theme-with-dark-background):host(:not(.primary-button):not(:disabled):hover),
-:host-context(.-theme-with-dark-background):host(:not(.primary-button):not(:disabled):active) {
+.-theme-with-dark-background .text-button:not(.primary-button):not(:disabled):focus,
+.-theme-with-dark-background .text-button:not(.primary-button):not(:disabled):hover,
+.-theme-with-dark-background .text-button:not(.primary-button):not(:disabled):active {
background-color: #313131;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
-:host-context(.-theme-with-dark-background):host(:not(.primary-button):not(:disabled):focus) {
+.-theme-with-dark-background .text-button:not(.primary-button):not(:disabled):focus {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(94, 151, 246, 0.6);
}
-:host-context(.-theme-with-dark-background):host(:not(.primary-button):not(:disabled):active) {
+.-theme-with-dark-background .text-button:not(.primary-button):not(:disabled):active {
background-color: #3e3e3e;
}
diff --git a/src/cobalt/doc/performance_tuning.md b/src/cobalt/doc/performance_tuning.md
index c9fc55d..e8336f3 100644
--- a/src/cobalt/doc/performance_tuning.md
+++ b/src/cobalt/doc/performance_tuning.md
@@ -421,11 +421,12 @@
1. The command line option, "--timed_trace=XX" will instruct Cobalt to trace
upon startup, for XX seconds (e.g. "--timed_trace=25"). When completed,
the output will be written to the file `timed_trace.json`.
-2. Using the debug console (hit CTRL+O on a keyboard once or twice), type in the
- command "d.trace()" and hit enter. Cobalt will begin a trace. After
- some time has passed (and presumably you have performed some actions), you
- can open the debug console again and type "d.trace()" again to end the trace.
- The trace output will be written to the file `triggered_trace.json`.
+2. Using the debug console (hit CTRL+O on a keyboard once or twice), type in
+ the command "h5vcc.traceEvent.start()" and hit enter. Cobalt will begin a
+ trace. After some time has passed (and presumably you have performed some
+ actions), you can open the debug console again and type
+ "h5vcc.traceEvent.stop()" again to end the trace.
+ The trace output will be written to the file `h5vcc_trace_event.json`.
The directory the output files will be placed within is the directory that the
Starboard function `SbSystemGetPath()` returns with a `path_id` of
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index d803d68..e8fcc53 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -91,7 +91,7 @@
if (resource_url.SchemeIs("data")) {
return true;
}
- // Check if resource_url is an hls url. Hls url must contain "hls_variant"
+ // Check if resource_url is an hls url. Hls url must contain "hls_variant".
return resource_url.spec().find("hls_variant") != std::string::npos;
}
#endif // SB_HAS(PLAYER_WITH_URL)
diff --git a/src/cobalt/dom/media_source.cc b/src/cobalt/dom/media_source.cc
index 57bc8c0..3b01e26 100644
--- a/src/cobalt/dom/media_source.cc
+++ b/src/cobalt/dom/media_source.cc
@@ -51,8 +51,6 @@
#include "base/compiler_specific.h"
#include "base/guid.h"
#include "base/logging.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
#include "cobalt/base/tokens.h"
#include "cobalt/dom/dom_exception.h"
#include "cobalt/dom/dom_settings.h"
@@ -69,39 +67,6 @@
using media::CHUNK_DEMUXER_ERROR_EOS_STATUS_DECODE_ERROR;
using media::PIPELINE_OK;
-namespace {
-
-// Parse mime and codecs from content type. It will return "video/mp4" and
-// "avc1.42E01E, mp4a.40.2" for "video/mp4; codecs="avc1.42E01E, mp4a.40.2".
-// Note that this function does minimum validation as the media stack will check
-// the mime type and codecs strictly.
-bool ParseContentType(const std::string& content_type, std::string* mime,
- std::string* codecs) {
- DCHECK(mime);
- DCHECK(codecs);
- static const char kCodecs[] = "codecs=";
-
- // SplitString will also trim the results.
- std::vector<std::string> tokens = ::base::SplitString(
- content_type, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- // The first one has to be mime type with delimiter '/' like 'video/mp4'.
- if (tokens.size() < 2 || tokens[0].find('/') == tokens[0].npos) {
- return false;
- }
- *mime = tokens[0];
- for (size_t i = 1; i < tokens.size(); ++i) {
- if (base::strncasecmp(tokens[i].c_str(), kCodecs, strlen(kCodecs))) {
- continue;
- }
- *codecs = tokens[i].substr(strlen("codecs="));
- base::TrimString(*codecs, " \"", codecs);
- break;
- }
- return !codecs->empty();
-}
-
-} // namespace
-
MediaSource::MediaSource()
: chunk_demuxer_(NULL),
ready_state_(kMediaSourceReadyStateClosed),
@@ -203,18 +168,9 @@
return NULL;
}
- std::string mime;
- std::string codecs;
-
- if (!ParseContentType(type, &mime, &codecs)) {
- DOMException::Raise(DOMException::kNotSupportedErr, exception_state);
- // Return value should be ignored.
- return NULL;
- }
-
std::string guid = base::GenerateGUID();
scoped_refptr<SourceBuffer> source_buffer;
- ChunkDemuxer::Status status = chunk_demuxer_->AddId(guid, mime, codecs);
+ ChunkDemuxer::Status status = chunk_demuxer_->AddId(guid, type);
switch (status) {
case ChunkDemuxer::kOk:
source_buffer =
diff --git a/src/cobalt/media/base/audio_decoder_config.h b/src/cobalt/media/base/audio_decoder_config.h
index 06c4b5a..5c15879 100644
--- a/src/cobalt/media/base/audio_decoder_config.h
+++ b/src/cobalt/media/base/audio_decoder_config.h
@@ -80,6 +80,9 @@
return encryption_scheme_;
}
+ void set_mime(const std::string& mime) { mime_ = mime; }
+ const std::string& mime() const { return mime_; }
+
private:
AudioCodec codec_;
SampleFormat sample_format_;
@@ -99,6 +102,13 @@
// as padding added during encoding.
int codec_delay_;
+ // |mime_| contains the mime type string specified when creating the stream.
+ // For example, when the stream is created via MediaSource, it is the mime
+ // string passed to addSourceBuffer(). It can be an empty string when the
+ // appropriate mime string is unknown. It is provided as an extra information
+ // and can be inconsistent with the other member variables.
+ std::string mime_;
+
// Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler
// generated copy constructor and assignment operator. Since the extra data is
// typically small, the performance impact is minimal.
diff --git a/src/cobalt/media/base/starboard_player.cc b/src/cobalt/media/base/starboard_player.cc
index d0c7e92..0880efb 100644
--- a/src/cobalt/media/base/starboard_player.cc
+++ b/src/cobalt/media/base/starboard_player.cc
@@ -150,6 +150,11 @@
DCHECK(set_bounds_helper_);
DCHECK(video_frame_provider_);
+#if SB_API_VERSION >= 11
+ audio_sample_info_.codec = kSbMediaAudioCodecNone;
+ video_sample_info_.codec = kSbMediaVideoCodecNone;
+#endif // SB_API_VERSION >= 11
+
if (audio_config.IsValidConfig()) {
UpdateAudioConfig(audio_config);
}
@@ -157,9 +162,7 @@
UpdateVideoConfig(video_config);
}
- output_mode_ = ComputeSbPlayerOutputMode(
- MediaVideoCodecToSbMediaVideoCodec(video_config.codec()), drm_system,
- prefer_decode_to_texture);
+ output_mode_ = ComputeSbPlayerOutputMode(prefer_decode_to_texture);
CreatePlayer();
@@ -554,8 +557,30 @@
}
#endif // SB_API_VERSION >= 11
- DCHECK(SbPlayerOutputModeSupported(output_mode_, video_codec, drm_system_));
bool has_audio = audio_codec != kSbMediaAudioCodecNone;
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+ SbPlayerCreationParam creation_param = {};
+ creation_param.audio_mime =
+ audio_config_.IsValidConfig() ? audio_config_.mime().c_str() : "";
+ creation_param.video_mime =
+ video_config_.IsValidConfig() ? video_config_.mime().c_str() : "";
+ creation_param.drm_system = drm_system_;
+ creation_param.audio_sample_info = audio_sample_info_;
+ creation_param.video_sample_info = video_sample_info_;
+ creation_param.output_mode = output_mode_;
+ creation_param.max_video_capabilities = max_video_capabilities_.c_str();
+ DCHECK_EQ(SbPlayerGetPreferredOutputMode(&creation_param), output_mode_);
+ player_ = SbPlayerCreate(
+ window_, &creation_param, &StarboardPlayer::DeallocateSampleCB,
+ &StarboardPlayer::DecoderStatusCB, &StarboardPlayer::PlayerStatusCB,
+ &StarboardPlayer::PlayerErrorCB, this,
+ get_decode_target_graphics_context_provider_func_.Run());
+
+#else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+ DCHECK(SbPlayerOutputModeSupported(output_mode_, video_codec, drm_system_));
player_ = SbPlayerCreate(
window_, video_codec, audio_codec,
#if SB_API_VERSION < 10
@@ -573,6 +598,9 @@
#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
this, output_mode_,
get_decode_target_graphics_context_provider_func_.Run());
+
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
DCHECK(SbPlayerIsValid(player_));
if (output_mode_ == kSbPlayerOutputModeDecodeToTexture) {
@@ -935,24 +963,54 @@
// static
SbPlayerOutputMode StarboardPlayer::ComputeSbPlayerOutputMode(
- SbMediaVideoCodec codec, SbDrmSystem drm_system,
- bool prefer_decode_to_texture) {
- // Try to choose the output mode according to the passed in value of
- // |prefer_decode_to_texture|. If the preferred output mode is unavailable
- // though, fallback to an output mode that is available.
- SbPlayerOutputMode output_mode = kSbPlayerOutputModeInvalid;
- if (SbPlayerOutputModeSupported(kSbPlayerOutputModePunchOut, codec,
- drm_system)) {
- output_mode = kSbPlayerOutputModePunchOut;
- }
- if ((prefer_decode_to_texture || output_mode == kSbPlayerOutputModeInvalid) &&
- SbPlayerOutputModeSupported(kSbPlayerOutputModeDecodeToTexture, codec,
- drm_system)) {
- output_mode = kSbPlayerOutputModeDecodeToTexture;
- }
- CHECK_NE(kSbPlayerOutputModeInvalid, output_mode);
+ bool prefer_decode_to_texture) const {
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+ SbPlayerCreationParam creation_param = {};
+ creation_param.audio_mime =
+ audio_config_.IsValidConfig() ? audio_config_.mime().c_str() : "";
+ creation_param.video_mime =
+ video_config_.IsValidConfig() ? video_config_.mime().c_str() : "";
+ creation_param.drm_system = drm_system_;
+ creation_param.audio_sample_info = audio_sample_info_;
+ creation_param.video_sample_info = video_sample_info_;
+ creation_param.max_video_capabilities = max_video_capabilities_.c_str();
+ // Try to choose |kSbPlayerOutputModeDecodeToTexture| when
+ // |prefer_decode_to_texture| is true.
+ if (prefer_decode_to_texture) {
+ creation_param.output_mode = kSbPlayerOutputModeDecodeToTexture;
+ } else {
+ creation_param.output_mode = kSbPlayerOutputModePunchOut;
+ }
+ auto output_mode = SbPlayerGetPreferredOutputMode(&creation_param);
+ CHECK_NE(kSbPlayerOutputModeInvalid, output_mode);
return output_mode;
+#else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+ SbMediaVideoCodec video_codec = kSbMediaVideoCodecNone;
+
+#if SB_API_VERSION >= 11
+ video_codec = video_sample_info_.codec;
+#else // SB_API_VERSION >= 11
+ video_codec = MediaVideoCodecToSbMediaVideoCodec(video_config_.codec());
+#endif // SB_API_VERSION >= 11
+
+ // Try to choose |kSbPlayerOutputModeDecodeToTexture| when
+ // |prefer_decode_to_texture| is true.
+ if (prefer_decode_to_texture) {
+ if (SbPlayerOutputModeSupported(kSbPlayerOutputModeDecodeToTexture,
+ video_codec, drm_system_)) {
+ return kSbPlayerOutputModeDecodeToTexture;
+ }
+ }
+
+ if (SbPlayerOutputModeSupported(kSbPlayerOutputModePunchOut, video_codec,
+ drm_system_)) {
+ return kSbPlayerOutputModePunchOut;
+ }
+ CHECK(SbPlayerOutputModeSupported(kSbPlayerOutputModeDecodeToTexture,
+ video_codec, drm_system_));
+ return kSbPlayerOutputModeDecodeToTexture;
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
}
} // namespace media
diff --git a/src/cobalt/media/base/starboard_player.h b/src/cobalt/media/base/starboard_player.h
index 13ef299..2074cde 100644
--- a/src/cobalt/media/base/starboard_player.h
+++ b/src/cobalt/media/base/starboard_player.h
@@ -210,9 +210,8 @@
#endif // SB_HAS(PLAYER_WITH_URL)
// Returns the output mode that should be used for a video with the given
// specifications.
- static SbPlayerOutputMode ComputeSbPlayerOutputMode(
- SbMediaVideoCodec codec, SbDrmSystem drm_system,
- bool prefer_decode_to_texture);
+ SbPlayerOutputMode ComputeSbPlayerOutputMode(
+ bool prefer_decode_to_texture) const;
// The following variables are initialized in the ctor and never changed.
#if SB_HAS(PLAYER_WITH_URL)
diff --git a/src/cobalt/media/base/video_decoder_config.h b/src/cobalt/media/base/video_decoder_config.h
index ffcdb8a..ae8cf34 100644
--- a/src/cobalt/media/base/video_decoder_config.h
+++ b/src/cobalt/media/base/video_decoder_config.h
@@ -112,6 +112,9 @@
return webm_color_metadata_;
}
+ void set_mime(const std::string& mime) { mime_ = mime; }
+ const std::string& mime() const { return mime_; }
+
private:
VideoCodec codec_;
VideoCodecProfile profile_;
@@ -131,6 +134,13 @@
WebMColorMetadata webm_color_metadata_;
+ // |mime_| contains the mime type string specified when creating the stream.
+ // For example, when the stream is created via MediaSource, it is the mime
+ // string passed to addSourceBuffer(). It can be an empty string when the
+ // appropriate mime string is unknown. It is provided as an extra information
+ // and can be inconsistent with the other member variables.
+ std::string mime_;
+
// Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler
// generated copy constructor and assignment operator. Since the extra data is
// typically small, the performance impact is minimal.
diff --git a/src/cobalt/media/filters/chunk_demuxer.cc b/src/cobalt/media/filters/chunk_demuxer.cc
index bdc048d..e88c81d 100644
--- a/src/cobalt/media/filters/chunk_demuxer.cc
+++ b/src/cobalt/media/filters/chunk_demuxer.cc
@@ -16,6 +16,8 @@
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "base/trace_event/trace_event.h"
#include "cobalt/media/base/audio_decoder_config.h"
#include "cobalt/media/base/bind_to_current_loop.h"
@@ -34,9 +36,44 @@
namespace cobalt {
namespace media {
-ChunkDemuxerStream::ChunkDemuxerStream(Type type, bool splice_frames_enabled,
+namespace {
+
+// Parse type and codecs from mime type. It will return "video/mp4" and
+// "avc1.42E01E, mp4a.40.2" for "video/mp4; codecs="avc1.42E01E, mp4a.40.2".
+// Note that this function does minimum validation as the media stack will check
+// the type and codecs strictly.
+bool ParseMimeType(const std::string& mime_type, std::string* type,
+ std::string* codecs) {
+ DCHECK(type);
+ DCHECK(codecs);
+ static const char kCodecs[] = "codecs=";
+
+ // SplitString will also trim the results.
+ std::vector<std::string> tokens = ::base::SplitString(
+ mime_type, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ // The first one has to be mime type with delimiter '/' like 'video/mp4'.
+ if (tokens.size() < 2 || tokens[0].find('/') == tokens[0].npos) {
+ return false;
+ }
+ *type = tokens[0];
+ for (size_t i = 1; i < tokens.size(); ++i) {
+ if (base::strncasecmp(tokens[i].c_str(), kCodecs, strlen(kCodecs))) {
+ continue;
+ }
+ *codecs = tokens[i].substr(strlen("codecs="));
+ base::TrimString(*codecs, " \"", codecs);
+ break;
+ }
+ return !codecs->empty();
+}
+
+} // namespace
+
+ChunkDemuxerStream::ChunkDemuxerStream(Type type, const std::string& mime,
+ bool splice_frames_enabled,
MediaTrack::Id media_track_id)
: type_(type),
+ mime_(mime),
liveness_(DemuxerStream::LIVENESS_UNKNOWN),
media_track_id_(media_track_id),
state_(UNINITIALIZED),
@@ -272,13 +309,17 @@
AudioDecoderConfig ChunkDemuxerStream::audio_decoder_config() {
CHECK_EQ(type_, AUDIO);
base::AutoLock auto_lock(lock_);
- return stream_->GetCurrentAudioDecoderConfig();
+ auto config = stream_->GetCurrentAudioDecoderConfig();
+ config.set_mime(mime_);
+ return config;
}
VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() {
CHECK_EQ(type_, VIDEO);
base::AutoLock auto_lock(lock_);
- return stream_->GetCurrentVideoDecoderConfig();
+ auto config = stream_->GetCurrentVideoDecoderConfig();
+ config.set_mime(mime_);
+ return config;
}
bool ChunkDemuxerStream::SupportsConfigChanges() { return true; }
@@ -607,10 +648,16 @@
}
ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
- const std::string& type,
- const std::string& codecs) {
- DVLOG(1) << __func__ << " id=" << id << " mime_type=" << type
- << " codecs=" << codecs;
+ const std::string& mime) {
+ DVLOG(1) << __func__ << " id=" << id << " mime_type=" << mime;
+
+ std::string type;
+ std::string codecs;
+
+ if (!ParseMimeType(mime, &type, &codecs)) {
+ return kNotSupported;
+ }
+
base::AutoLock auto_lock(lock_);
if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
@@ -632,8 +679,8 @@
std::unique_ptr<SourceBufferState> source_state(new SourceBufferState(
std::move(stream_parser), std::move(frame_processor),
- base::Bind(&ChunkDemuxer::CreateDemuxerStream, base::Unretained(this),
- id),
+ base::Bind(&ChunkDemuxer::CreateDemuxerStream, base::Unretained(this), id,
+ mime),
media_log_, buffer_allocator_));
SourceBufferState::NewTextTrackCB new_text_track_cb;
@@ -1195,7 +1242,8 @@
}
ChunkDemuxerStream* ChunkDemuxer::CreateDemuxerStream(
- const std::string& source_id, DemuxerStream::Type type) {
+ const std::string& source_id, const std::string& mime,
+ DemuxerStream::Type type) {
// New ChunkDemuxerStreams can be created only during initialization segment
// processing, which happens when a new chunk of data is appended and the
// lock_ must be held by ChunkDemuxer::AppendData.
@@ -1223,8 +1271,8 @@
return NULL;
}
- std::unique_ptr<ChunkDemuxerStream> stream(
- new ChunkDemuxerStream(type, splice_frames_enabled_, media_track_id));
+ std::unique_ptr<ChunkDemuxerStream> stream(new ChunkDemuxerStream(
+ type, mime, splice_frames_enabled_, media_track_id));
DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
track_id_to_demux_stream_map_.end());
track_id_to_demux_stream_map_[media_track_id] = stream.get();
diff --git a/src/cobalt/media/filters/chunk_demuxer.h b/src/cobalt/media/filters/chunk_demuxer.h
index 574e82e..f0d2428 100644
--- a/src/cobalt/media/filters/chunk_demuxer.h
+++ b/src/cobalt/media/filters/chunk_demuxer.h
@@ -35,8 +35,8 @@
public:
typedef std::deque<scoped_refptr<StreamParserBuffer>> BufferQueue;
- ChunkDemuxerStream(Type type, bool splice_frames_enabled,
- MediaTrack::Id media_track_id);
+ ChunkDemuxerStream(Type type, const std::string& mime,
+ bool splice_frames_enabled, MediaTrack::Id media_track_id);
~ChunkDemuxerStream() override;
// ChunkDemuxerStream control methods.
@@ -148,6 +148,8 @@
// Specifies the type of the stream.
Type type_;
+ const std::string mime_;
+
Liveness liveness_;
std::unique_ptr<SourceBufferStream> stream_;
@@ -212,15 +214,14 @@
void StartWaitingForSeek(base::TimeDelta seek_time) override;
void CancelPendingSeek(base::TimeDelta seek_time) override;
- // Registers a new |id| to use for AppendData() calls. |type| indicates
+ // Registers a new |id| to use for AppendData() calls. |mime| indicates
// the MIME type for the data that we intend to append for this ID.
// kOk is returned if the demuxer has enough resources to support another ID
// and supports the format indicated by |type|.
// kNotSupported is returned if |type| is not a supported format.
// kReachedIdLimit is returned if the demuxer cannot handle another ID right
// now.
- Status AddId(const std::string& id, const std::string& type,
- const std::string& codecs);
+ Status AddId(const std::string& id, const std::string& mime);
// Notifies a caller via |tracks_updated_cb| that the set of media tracks
// for a given |id| has changed.
@@ -351,6 +352,7 @@
// Returns a pointer to a new ChunkDemuxerStream instance, which is owned by
// ChunkDemuxer.
ChunkDemuxerStream* CreateDemuxerStream(const std::string& source_id,
+ const std::string& mime,
DemuxerStream::Type type);
void OnNewTextTrack(ChunkDemuxerStream* text_stream,
diff --git a/src/cobalt/media/filters/shell_demuxer.cc b/src/cobalt/media/filters/shell_demuxer.cc
index a68a82a..6f7f226 100644
--- a/src/cobalt/media/filters/shell_demuxer.cc
+++ b/src/cobalt/media/filters/shell_demuxer.cc
@@ -402,6 +402,7 @@
requested_au_->GetMaxSize()));
if (decoder_buffer) {
decoder_buffer->set_is_key_frame(requested_au_->IsKeyframe());
+ buffer_allocator_->UpdateVideoConfig(VideoConfig());
Download(decoder_buffer);
} else {
// As the buffer is full of media data, it is safe to delay 100
diff --git a/src/cobalt/media/formats/mp4/box_definitions.cc b/src/cobalt/media/formats/mp4/box_definitions.cc
index 01cb776..aee8f2c 100644
--- a/src/cobalt/media/formats/mp4/box_definitions.cc
+++ b/src/cobalt/media/formats/mp4/box_definitions.cc
@@ -23,6 +23,31 @@
namespace media {
namespace mp4 {
+namespace {
+
+// Read color coordinate value as defined in the MasteringDisplayColorVolume
+// ('mdcv') box. Each coordinate is a float encoded in uint16_t, with upper
+// bound set to 50000.
+bool ReadMdcvColorCoordinate(BoxReader* reader,
+ float* normalized_value_in_float) {
+ const float kColorCoordinateUpperBound = 50000.;
+
+ uint16_t value_in_uint16;
+ RCHECK(reader->Read2(&value_in_uint16));
+
+ float value_in_float = static_cast<float>(value_in_uint16);
+
+ if (value_in_float >= kColorCoordinateUpperBound) {
+ *normalized_value_in_float = 1.f;
+ return true;
+ }
+
+ *normalized_value_in_float = value_in_float / kColorCoordinateUpperBound;
+ return true;
+}
+
+} // namespace
+
FileType::FileType() {}
FileType::~FileType() {}
FourCC FileType::BoxType() const { return FOURCC_FTYP; }
@@ -620,6 +645,60 @@
return true;
}
+ColorParameterInformation::ColorParameterInformation() {}
+ColorParameterInformation::~ColorParameterInformation() {}
+FourCC ColorParameterInformation::BoxType() const { return FOURCC_COLR; }
+
+bool ColorParameterInformation::Parse(BoxReader* reader) {
+ FourCC type;
+ RCHECK(reader->ReadFourCC(&type));
+ // TODO: Support 'nclc', 'rICC', and 'prof'.
+ RCHECK(type == FOURCC_NCLX);
+
+ uint8_t full_range_byte;
+ RCHECK(reader->Read2(&colour_primaries) &&
+ reader->Read2(&transfer_characteristics) &&
+ reader->Read2(&matrix_coefficients) &&
+ reader->Read1(&full_range_byte));
+ full_range = full_range_byte & 0x80;
+
+ return true;
+}
+
+MasteringDisplayColorVolume::MasteringDisplayColorVolume() {}
+MasteringDisplayColorVolume::~MasteringDisplayColorVolume() {}
+FourCC MasteringDisplayColorVolume::BoxType() const { return FOURCC_MDCV; }
+
+bool MasteringDisplayColorVolume::Parse(BoxReader* reader) {
+ // Technically the color coordinates may be in any order. The spec recommends
+ // GBR and it is assumed that the color coordinates are in such order.
+ RCHECK(ReadMdcvColorCoordinate(reader, &display_primaries_gx) &&
+ ReadMdcvColorCoordinate(reader, &display_primaries_gy) &&
+ ReadMdcvColorCoordinate(reader, &display_primaries_bx) &&
+ ReadMdcvColorCoordinate(reader, &display_primaries_by) &&
+ ReadMdcvColorCoordinate(reader, &display_primaries_rx) &&
+ ReadMdcvColorCoordinate(reader, &display_primaries_ry) &&
+ ReadMdcvColorCoordinate(reader, &white_point_x) &&
+ ReadMdcvColorCoordinate(reader, &white_point_y) &&
+ reader->Read4(&max_display_mastering_luminance) &&
+ reader->Read4(&min_display_mastering_luminance));
+
+ const uint32_t kUnitOfMasteringLuminance = 10000;
+ max_display_mastering_luminance /= kUnitOfMasteringLuminance;
+ min_display_mastering_luminance /= kUnitOfMasteringLuminance;
+
+ return true;
+}
+
+ContentLightLevelInformation::ContentLightLevelInformation() {}
+ContentLightLevelInformation::~ContentLightLevelInformation() {}
+FourCC ContentLightLevelInformation::BoxType() const { return FOURCC_CLLI; }
+
+bool ContentLightLevelInformation::Parse(BoxReader* reader) {
+ return reader->Read2(&max_content_light_level) &&
+ reader->Read2(&max_pic_average_light_level);
+}
+
VideoSampleEntry::VideoSampleEntry()
: format(FOURCC_NULL),
data_reference_index(0),
@@ -688,6 +767,24 @@
frame_bitstream_converter = nullptr;
video_codec = kCodecAV1;
video_codec_profile = av1_config.profile;
+
+ ColorParameterInformation color_parameter_information;
+ if (reader->HasChild(&color_parameter_information)) {
+ RCHECK(reader->ReadChild(&color_parameter_information));
+ this->color_parameter_information = color_parameter_information;
+ }
+
+ MasteringDisplayColorVolume mastering_display_color_volume;
+ if (reader->HasChild(&mastering_display_color_volume)) {
+ RCHECK(reader->ReadChild(&mastering_display_color_volume));
+ this->mastering_display_color_volume = mastering_display_color_volume;
+ }
+
+ ContentLightLevelInformation content_light_level_information;
+ if (reader->HasChild(&content_light_level_information)) {
+ RCHECK(reader->ReadChild(&content_light_level_information));
+ this->content_light_level_information = content_light_level_information;
+ }
break;
}
default:
diff --git a/src/cobalt/media/formats/mp4/box_definitions.h b/src/cobalt/media/formats/mp4/box_definitions.h
index 90415d9..db69017 100644
--- a/src/cobalt/media/formats/mp4/box_definitions.h
+++ b/src/cobalt/media/formats/mp4/box_definitions.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/optional.h"
#include "cobalt/media/base/decrypt_config.h"
#include "cobalt/media/base/media_export.h"
#include "cobalt/media/base/media_log.h"
@@ -239,6 +240,37 @@
uint32_t v_spacing;
};
+struct MEDIA_EXPORT ColorParameterInformation : Box {
+ DECLARE_BOX_METHODS(ColorParameterInformation);
+
+ uint16 colour_primaries;
+ uint16 transfer_characteristics;
+ uint16 matrix_coefficients;
+ bool full_range;
+};
+
+struct MEDIA_EXPORT MasteringDisplayColorVolume : Box {
+ DECLARE_BOX_METHODS(MasteringDisplayColorVolume);
+
+ float display_primaries_gx;
+ float display_primaries_gy;
+ float display_primaries_bx;
+ float display_primaries_by;
+ float display_primaries_rx;
+ float display_primaries_ry;
+ float white_point_x;
+ float white_point_y;
+ uint32 max_display_mastering_luminance;
+ uint32 min_display_mastering_luminance;
+};
+
+struct MEDIA_EXPORT ContentLightLevelInformation : Box {
+ DECLARE_BOX_METHODS(ContentLightLevelInformation);
+
+ uint16 max_content_light_level;
+ uint16 max_pic_average_light_level;
+};
+
struct MEDIA_EXPORT VideoSampleEntry : Box {
DECLARE_BOX_METHODS(VideoSampleEntry);
@@ -253,6 +285,10 @@
VideoCodec video_codec;
VideoCodecProfile video_codec_profile;
+ base::Optional<ColorParameterInformation> color_parameter_information;
+ base::Optional<MasteringDisplayColorVolume> mastering_display_color_volume;
+ base::Optional<ContentLightLevelInformation> content_light_level_information;
+
bool IsFormatValid() const;
scoped_refptr<BitstreamConverter> frame_bitstream_converter;
diff --git a/src/cobalt/media/formats/mp4/fourccs.h b/src/cobalt/media/formats/mp4/fourccs.h
index e79b003..497ac68 100644
--- a/src/cobalt/media/formats/mp4/fourccs.h
+++ b/src/cobalt/media/formats/mp4/fourccs.h
@@ -22,7 +22,9 @@
FOURCC_AVCC = 0x61766343,
FOURCC_BLOC = 0x626C6F63,
FOURCC_CENC = 0x63656e63,
+ FOURCC_CLLI = 0x636c6c69,
FOURCC_CO64 = 0x636f3634,
+ FOURCC_COLR = 0x636f6c72,
FOURCC_CTTS = 0x63747473,
FOURCC_DINF = 0x64696e66,
FOURCC_EDTS = 0x65647473,
@@ -41,6 +43,7 @@
FOURCC_HVCC = 0x68766343,
FOURCC_IODS = 0x696f6473,
FOURCC_MDAT = 0x6d646174,
+ FOURCC_MDCV = 0x6d646376,
FOURCC_MDHD = 0x6d646864,
FOURCC_MDIA = 0x6d646961,
FOURCC_MECO = 0x6d65636f,
@@ -55,6 +58,7 @@
FOURCC_MP4V = 0x6d703476,
FOURCC_MVEX = 0x6d766578,
FOURCC_MVHD = 0x6d766864,
+ FOURCC_NCLX = 0x6e636c78,
FOURCC_PASP = 0x70617370,
FOURCC_PDIN = 0x7064696e,
FOURCC_PRFT = 0x70726674,
diff --git a/src/cobalt/media/formats/mp4/mp4_stream_parser.cc b/src/cobalt/media/formats/mp4/mp4_stream_parser.cc
index 391318b..1ab9371 100644
--- a/src/cobalt/media/formats/mp4/mp4_stream_parser.cc
+++ b/src/cobalt/media/formats/mp4/mp4_stream_parser.cc
@@ -16,6 +16,8 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "cobalt/media/base/audio_decoder_config.h"
+#include "cobalt/media/base/color_space.h"
+#include "cobalt/media/base/hdr_metadata.h"
#include "cobalt/media/base/media_tracks.h"
#include "cobalt/media/base/media_util.h"
#include "cobalt/media/base/stream_parser_buffer.h"
@@ -28,6 +30,7 @@
#include "cobalt/media/formats/mp4/es_descriptor.h"
#include "cobalt/media/formats/mp4/rcheck.h"
#include "cobalt/media/formats/mpeg/adts_constants.h"
+#include "cobalt/media/formats/webm/webm_colour_parser.h"
#include "starboard/memory.h"
#include "starboard/types.h"
@@ -36,7 +39,45 @@
namespace mp4 {
namespace {
+
+using gfx::ColorSpace;
+
const int kMaxEmptySampleLogs = 20;
+
+gfx::ColorSpace ConvertColorParameterInformationToColorSpace(
+ const ColorParameterInformation& info) {
+ auto primary_id = static_cast<ColorSpace::PrimaryID>(info.colour_primaries);
+ auto transfer_id =
+ static_cast<ColorSpace::TransferID>(info.transfer_characteristics);
+ auto matrix_id = static_cast<ColorSpace::MatrixID>(info.matrix_coefficients);
+
+ // Note that we don't check whether the embedded ids are valid. We rely on
+ // the underlying video decoder to reject any ids that it doesn't support.
+ return gfx::ColorSpace(
+ primary_id, transfer_id, matrix_id,
+ info.full_range ? ColorSpace::kRangeIdFull : ColorSpace::kRangeIdLimited);
+}
+
+MasteringMetadata ConvertMdcvToMasteringMetadata(
+ const MasteringDisplayColorVolume& mdcv) {
+ MasteringMetadata mastering_metadata;
+
+ mastering_metadata.primary_r_chromaticity_x = mdcv.display_primaries_rx;
+ mastering_metadata.primary_r_chromaticity_y = mdcv.display_primaries_ry;
+ mastering_metadata.primary_g_chromaticity_x = mdcv.display_primaries_gx;
+ mastering_metadata.primary_g_chromaticity_y = mdcv.display_primaries_gy;
+ mastering_metadata.primary_b_chromaticity_x = mdcv.display_primaries_bx;
+ mastering_metadata.primary_b_chromaticity_y = mdcv.display_primaries_by;
+ mastering_metadata.white_point_chromaticity_x = mdcv.white_point_x;
+ mastering_metadata.white_point_chromaticity_y = mdcv.white_point_y;
+ mastering_metadata.luminance_max =
+ static_cast<float>(mdcv.max_display_mastering_luminance);
+ mastering_metadata.luminance_min =
+ static_cast<float>(mdcv.min_display_mastering_luminance);
+
+ return mastering_metadata;
+}
+
} // namespace
MP4StreamParser::MP4StreamParser(DecoderBuffer::Allocator* buffer_allocator,
@@ -371,6 +412,30 @@
// SPS/PPS are embedded in the video stream
EmptyExtraData(),
is_track_encrypted ? AesCtrEncryptionScheme() : Unencrypted());
+ if (entry.color_parameter_information) {
+ WebMColorMetadata color_metadata = {};
+
+ color_metadata.color_space =
+ ConvertColorParameterInformationToColorSpace(
+ *entry.color_parameter_information);
+
+ if (entry.mastering_display_color_volume) {
+ color_metadata.hdr_metadata.mastering_metadata =
+ ConvertMdcvToMasteringMetadata(
+ *entry.mastering_display_color_volume);
+ }
+
+ if (entry.content_light_level_information) {
+ color_metadata.hdr_metadata.max_cll =
+ entry.content_light_level_information->max_content_light_level;
+ color_metadata.hdr_metadata.max_fall =
+ entry.content_light_level_information
+ ->max_pic_average_light_level;
+ }
+
+ video_config.set_webm_color_metadata(color_metadata);
+ }
+
DVLOG(1) << "video_track_id=" << video_track_id
<< " config=" << video_config.AsHumanReadableString();
if (!video_config.IsValidConfig()) {
diff --git a/src/cobalt/media/sandbox/format_guesstimator.cc b/src/cobalt/media/sandbox/format_guesstimator.cc
index ad5c97f..adc856b 100644
--- a/src/cobalt/media/sandbox/format_guesstimator.cc
+++ b/src/cobalt/media/sandbox/format_guesstimator.cc
@@ -19,6 +19,8 @@
#include "base/bind.h"
#include "base/path_service.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "cobalt/media/base/audio_codecs.h"
#include "cobalt/media/base/audio_decoder_config.h"
@@ -42,20 +44,18 @@
namespace {
-// Container to organize the pairs of supported mime types and their codecs.
-struct SupportedTypeCodecInfo {
- std::string mime;
- std::string codecs;
-};
+// The possible mime type configurations that are supported by cobalt.
+const std::vector<std::string> kSupportedMimeTypes = {
+ "audio/mp4; codecs=\"ac-3\"",
+ "audio/mp4; codecs=\"ec-3\"",
+ "audio/mp4; codecs=\"mp4a.40.2\"",
+ "audio/webm; codecs=\"opus\"",
-// The possible mime and codec configurations that are supported by cobalt.
-const std::vector<SupportedTypeCodecInfo> kSupportedTypesAndCodecs = {
- {"audio/mp4", "ac-3"}, {"audio/mp4", "ec-3"},
- {"audio/mp4", "mp4a.40.2"}, {"audio/webm", "opus"},
-
- {"video/mp4", "av01.0.05M.08"}, {"video/mp4", "avc1.640028, mp4a.40.2"},
- {"video/mp4", "avc1.640028"}, {"video/mp4", "hvc1.1.6.H150.90"},
- {"video/webm", "vp9"},
+ "video/mp4; codecs=\"av01.0.05M.08\"",
+ "video/mp4; codecs=\"avc1.640028, mp4a.40.2\"",
+ "video/mp4; codecs=\"avc1.640028\"",
+ "video/mp4; codecs=\"hvc1.1.6.H150.90\"",
+ "video/webm; codecs=\"vp9\"",
};
// Can be called as:
@@ -103,6 +103,28 @@
SB_UNREFERENCED_PARAMETER(tracks);
}
+// Extract the value of "codecs" parameter from content type. It will return
+// "avc1.42E01E" for "video/mp4; codecs="avc1.42E01E".
+// Note that this function assumes that the input is always valid and does
+// minimum validation..
+std::string ExtractCodec(const std::string& content_type) {
+ static const char kCodecs[] = "codecs=";
+
+ // SplitString will also trim the results.
+ std::vector<std::string> tokens = ::base::SplitString(
+ content_type, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ for (size_t i = 1; i < tokens.size(); ++i) {
+ if (base::strncasecmp(tokens[i].c_str(), kCodecs, strlen(kCodecs))) {
+ continue;
+ }
+ auto codec = tokens[i].substr(strlen("codecs="));
+ base::TrimString(codec, " \"", &codec);
+ return codec;
+ }
+ NOTREACHED();
+ return "";
+}
+
} // namespace
FormatGuesstimator::FormatGuesstimator(const std::string& path_or_url,
@@ -126,17 +148,15 @@
return;
}
progressive_url_ = url;
- mime_ = "video/mp4";
- codecs_ = "avc1.640028, mp4a.40.2";
+ mime_type_ = "video/mp4; codecs=\"avc1.640028, mp4a.40.2\"";
}
void FormatGuesstimator::InitializeAsAdaptive(const base::FilePath& path,
MediaModule* media_module) {
std::vector<uint8_t> header = ReadHeader(path);
- for (const auto& expected_supported_info : kSupportedTypesAndCodecs) {
- DCHECK(mime_.empty());
- DCHECK(codecs_.empty());
+ for (const auto& expected_supported_mime_type : kSupportedMimeTypes) {
+ DCHECK(mime_type_.empty());
ChunkDemuxer* chunk_demuxer = NULL;
WebMediaPlayerHelper::ChunkDemuxerOpenCB open_cb = base::Bind(
@@ -157,8 +177,7 @@
}
const std::string id = "stream";
- if (chunk_demuxer->AddId(id, expected_supported_info.mime,
- expected_supported_info.codecs) !=
+ if (chunk_demuxer->AddId(id, expected_supported_mime_type) !=
ChunkDemuxer::kOk) {
continue;
}
@@ -182,11 +201,10 @@
chunk_demuxer->GetStream(DemuxerStream::Type::AUDIO)) {
const AudioDecoderConfig& decoder_config =
demuxer_stream->audio_decoder_config();
- if (StringToAudioCodec(expected_supported_info.codecs) ==
+ if (StringToAudioCodec(ExtractCodec(expected_supported_mime_type)) ==
decoder_config.codec()) {
adaptive_path_ = path;
- mime_ = expected_supported_info.mime;
- codecs_ = expected_supported_info.codecs;
+ mime_type_ = expected_supported_mime_type;
break;
}
continue;
@@ -195,11 +213,10 @@
DCHECK(demuxer_stream);
const VideoDecoderConfig& decoder_config =
demuxer_stream->video_decoder_config();
- if (StringToVideoCodec(expected_supported_info.codecs) ==
+ if (StringToVideoCodec(ExtractCodec(expected_supported_mime_type)) ==
decoder_config.codec()) {
adaptive_path_ = path;
- mime_ = expected_supported_info.mime;
- codecs_ = expected_supported_info.codecs;
+ mime_type_ = expected_supported_mime_type;
break;
}
}
diff --git a/src/cobalt/media/sandbox/format_guesstimator.h b/src/cobalt/media/sandbox/format_guesstimator.h
index dd95e9c..f9b25fb 100644
--- a/src/cobalt/media/sandbox/format_guesstimator.h
+++ b/src/cobalt/media/sandbox/format_guesstimator.h
@@ -38,7 +38,7 @@
bool is_adaptive() const { return !adaptive_path_.empty(); }
bool is_audio() const {
DCHECK(is_adaptive());
- return mime_.find("audio/") == 0;
+ return mime_type_.find("audio/") == 0;
}
const GURL& progressive_url() const {
@@ -53,13 +53,9 @@
return adaptive_path_.value();
}
- const std::string& mime() const {
+ const std::string& mime_type() const {
DCHECK(is_valid());
- return mime_;
- }
- const std::string& codecs() const {
- DCHECK(is_valid());
- return codecs_;
+ return mime_type_;
}
private:
@@ -69,8 +65,7 @@
GURL progressive_url_;
base::FilePath adaptive_path_;
- std::string mime_;
- std::string codecs_;
+ std::string mime_type_;
};
} // namespace sandbox
diff --git a/src/cobalt/media/sandbox/media2_sandbox.cc b/src/cobalt/media/sandbox/media2_sandbox.cc
index fdbb7df..0228744 100644
--- a/src/cobalt/media/sandbox/media2_sandbox.cc
+++ b/src/cobalt/media/sandbox/media2_sandbox.cc
@@ -118,15 +118,15 @@
demuxer->Initialize(&demuxer_host, base::Bind(OnDemuxerStatus), false);
ChunkDemuxer::Status status =
- demuxer->AddId("audio", "audio/mp4", "mp4a.40.2");
+ demuxer->AddId("audio", "audio/mp4; codecs=\"mp4a.40.2\"");
DCHECK_EQ(status, ChunkDemuxer::kOk);
int video_url_length = SbStringGetLength(argv[2]);
if (video_url_length > 5 &&
SbStringCompare(argv[2] + video_url_length - 5, ".webm", 5) == 0) {
- status = demuxer->AddId("video", "video/webm", "vp9");
+ status = demuxer->AddId("video", "video/webm; codecs=\"vp9\"");
} else {
- status = demuxer->AddId("video", "video/mp4", "avc1.640028");
+ status = demuxer->AddId("video", "video/mp4; codecs=\"avc1.640028\"");
}
DCHECK_EQ(status, ChunkDemuxer::kOk);
diff --git a/src/cobalt/media/sandbox/web_media_player_sandbox.cc b/src/cobalt/media/sandbox/web_media_player_sandbox.cc
index 7d28698..45f5a3f 100644
--- a/src/cobalt/media/sandbox/web_media_player_sandbox.cc
+++ b/src/cobalt/media/sandbox/web_media_player_sandbox.cc
@@ -90,8 +90,6 @@
SbLogRaw(ss.str().c_str());
}
-std::string MakeCodecParameter(const std::string& string) { return string; }
-
void OnInitSegmentReceived(std::unique_ptr<MediaTracks> tracks) {
SB_UNREFERENCED_PARAMETER(tracks);
}
@@ -182,8 +180,7 @@
LOG(INFO) << "Playing " << guesstimator.adaptive_path();
std::string id = guesstimator.is_audio() ? kAudioId : kVideoId;
- auto codecs = MakeCodecParameter(guesstimator.codecs());
- auto status = chunk_demuxer_->AddId(id, guesstimator.mime(), codecs);
+ auto status = chunk_demuxer_->AddId(id, guesstimator.mime_type());
CHECK_EQ(status, ChunkDemuxer::kOk);
chunk_demuxer_->SetTracksWatcher(id, base::Bind(OnInitSegmentReceived));
@@ -234,13 +231,11 @@
LOG(INFO) << "Playing " << audio_guesstimator.adaptive_path() << " and "
<< video_guesstimator.adaptive_path();
- auto codecs = MakeCodecParameter(audio_guesstimator.codecs());
auto status =
- chunk_demuxer_->AddId(kAudioId, audio_guesstimator.mime(), codecs);
+ chunk_demuxer_->AddId(kAudioId, audio_guesstimator.mime_type());
CHECK_EQ(status, ChunkDemuxer::kOk);
- codecs = MakeCodecParameter(video_guesstimator.codecs());
- status = chunk_demuxer_->AddId(kVideoId, video_guesstimator.mime(), codecs);
+ status = chunk_demuxer_->AddId(kVideoId, video_guesstimator.mime_type());
CHECK_EQ(status, ChunkDemuxer::kOk);
chunk_demuxer_->SetTracksWatcher(kAudioId,
diff --git a/src/cobalt/network/url_request_context.cc b/src/cobalt/network/url_request_context.cc
index 7b532ae..671de56 100644
--- a/src/cobalt/network/url_request_context.cc
+++ b/src/cobalt/network/url_request_context.cc
@@ -37,6 +37,7 @@
#include "net/http/http_transaction_factory.h"
#include "net/proxy_resolution/proxy_config.h"
#include "net/proxy_resolution/proxy_resolution_service.h"
+#include "net/third_party/quic/platform/api/quic_flags.h"
#include "net/ssl/ssl_config_service.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "net/url_request/data_protocol_handler.h"
@@ -93,6 +94,10 @@
new ProxyConfigService(proxy_config)),
net_log));
+ // ack decimation significantly increases download bandwidth on low-end
+ // android devices.
+ SetQuicFlag(&FLAGS_quic_reloadable_flag_quic_enable_ack_decimation, true);
+
net::HostResolver::Options options;
options.max_concurrent_resolves = net::HostResolver::kDefaultParallelism;
options.max_retry_attempts = net::HostResolver::kDefaultRetryAttempts;
diff --git a/src/cobalt/renderer/backend/backend.gyp b/src/cobalt/renderer/backend/backend.gyp
index 3ff2de4..3064909 100644
--- a/src/cobalt/renderer/backend/backend.gyp
+++ b/src/cobalt/renderer/backend/backend.gyp
@@ -30,5 +30,31 @@
'<(DEPTH)/cobalt/renderer/backend/starboard/platform_backend.gyp:renderer_platform_backend',
],
},
+ {
+ 'target_name': 'graphics_system_test',
+ 'type': '<(gtest_target_type)',
+ 'sources': [
+ 'graphics_system_test.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/cobalt/base/base.gyp:base',
+ '<(DEPTH)/testing/gmock.gyp:gmock',
+ '<(DEPTH)/cobalt/test/test.gyp:run_all_unittests',
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ '<(DEPTH)/cobalt/renderer/backend/backend.gyp:renderer_backend',
+ '<(DEPTH)/cobalt/system_window/system_window.gyp:system_window',
+ ],
+ },
+ {
+ 'target_name': 'graphics_system_test_deploy',
+ 'type': 'none',
+ 'dependencies': [
+ 'graphics_system_test',
+ ],
+ 'variables': {
+ 'executable_name': 'graphics_system_test',
+ },
+ 'includes': [ '<(DEPTH)/starboard/build/deploy.gypi' ],
+ },
],
}
diff --git a/src/cobalt/renderer/backend/graphics_system_test.cc b/src/cobalt/renderer/backend/graphics_system_test.cc
new file mode 100644
index 0000000..f6ad30c
--- /dev/null
+++ b/src/cobalt/renderer/backend/graphics_system_test.cc
@@ -0,0 +1,123 @@
+// Copyright 2020 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <algorithm>
+#include <memory>
+
+#include "base/optional.h"
+#include "cobalt/renderer/backend/default_graphics_system.h"
+#include "cobalt/renderer/backend/graphics_context.h"
+#include "cobalt/renderer/backend/graphics_system.h"
+#include "starboard/log.h"
+#include "starboard/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cobalt {
+namespace renderer {
+namespace backend {
+
+namespace {
+
+// Number of initializations to use for measuring the reference creation time.
+const int kReferenceCount = 5;
+} // namespace
+
+TEST(GraphicsSystemTest, GraphicsSystemCanBeInitializedOften) {
+ // Test whether the graphics system can be initialized often without slowing
+ // down.
+ std::unique_ptr<GraphicsSystem> graphics_system;
+
+ // Treat the first initialization as a 'warm up'.
+ graphics_system = CreateDefaultGraphicsSystem();
+ graphics_system.reset();
+
+ SbTimeMonotonic start = SbTimeGetMonotonicNow();
+ for (int i = 0; i < kReferenceCount; ++i) {
+ graphics_system = CreateDefaultGraphicsSystem();
+ graphics_system.reset();
+ }
+ SbTimeMonotonic time_per_initialization =
+ (SbTimeGetMonotonicNow() - start) / kReferenceCount;
+ SB_LOG(INFO) << "Measured duration "
+ << time_per_initialization / kSbTimeMillisecond
+ << "ms per initialization.";
+
+ // Graphics system initializations should not take more than the maximum of
+ // 200ms or three times as long as the time we just measured.
+ SbTimeMonotonic maximum_time_per_initialization =
+ std::max(3 * time_per_initialization, 200 * kSbTimeMillisecond);
+
+ SbTimeMonotonic last = SbTimeGetMonotonicNow();
+ for (int i = 0; i < 20; ++i) {
+ graphics_system = CreateDefaultGraphicsSystem();
+ graphics_system.reset();
+ SbTimeMonotonic now = SbTimeGetMonotonicNow();
+ SB_LOG(INFO) << "Test duration " << (now - last) / kSbTimeMillisecond
+ << "ms.";
+ ASSERT_LT(now - last, maximum_time_per_initialization);
+ last = now;
+ }
+}
+
+TEST(GraphicsSystemTest, GraphicsContextCanBeInitializedOften) {
+ // Test whether the graphics system and graphics context can be initialized
+ // often without slowing down.
+ std::unique_ptr<GraphicsSystem> graphics_system;
+ std::unique_ptr<GraphicsContext> graphics_context;
+
+ // Treat the first initialization as a 'warm up'.
+ graphics_system = CreateDefaultGraphicsSystem();
+ graphics_context = graphics_system->CreateGraphicsContext();
+
+ graphics_context.reset();
+ graphics_system.reset();
+
+ SbTimeMonotonic start = SbTimeGetMonotonicNow();
+ for (int i = 0; i < kReferenceCount; ++i) {
+ graphics_system = CreateDefaultGraphicsSystem();
+ graphics_context = graphics_system->CreateGraphicsContext();
+
+ graphics_context.reset();
+ graphics_system.reset();
+ }
+ SbTimeMonotonic time_per_initialization = kSbTimeMillisecond +
+ (SbTimeGetMonotonicNow() - start) / kReferenceCount;
+ SB_LOG(INFO) << "Measured duration "
+ << time_per_initialization / kSbTimeMillisecond
+ << "ms per initialization.";
+
+ // Graphics system and context initializations should not take more than the
+ // maximum of 200ms or three times as long as the time we just measured.
+ SbTimeMonotonic maximum_time_per_initialization =
+ std::max(3 * time_per_initialization, 200 * kSbTimeMillisecond);
+
+ SbTimeMonotonic last = SbTimeGetMonotonicNow();
+ for (int i = 0; i < 20; ++i) {
+ graphics_system = CreateDefaultGraphicsSystem();
+ graphics_context = graphics_system->CreateGraphicsContext();
+
+ graphics_context.reset();
+ graphics_system.reset();
+
+ SbTimeMonotonic now = SbTimeGetMonotonicNow();
+ SB_LOG(INFO) << "Test duration " << (now - last) / kSbTimeMillisecond
+ << "ms.";
+ ASSERT_LT(now - last, maximum_time_per_initialization);
+ last = now;
+ }
+}
+
+} // namespace backend
+} // namespace renderer
+} // namespace cobalt
diff --git a/src/cobalt/script/global_environment.h b/src/cobalt/script/global_environment.h
index 93b10a6..946211b 100644
--- a/src/cobalt/script/global_environment.h
+++ b/src/cobalt/script/global_environment.h
@@ -19,6 +19,7 @@
#include <vector>
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "cobalt/script/error_report.h"
#include "cobalt/script/script_value.h"
@@ -35,7 +36,8 @@
class SourceCode;
// Manages a handle to a JavaScript engine's global object.
-class GlobalEnvironment : public base::RefCounted<GlobalEnvironment> {
+class GlobalEnvironment : public base::RefCounted<GlobalEnvironment>,
+ public base::SupportsWeakPtr<GlobalEnvironment> {
public:
typedef base::Callback<bool(const ErrorReport& error_report)>
ReportErrorCallback;
@@ -126,17 +128,19 @@
public:
ScopedPreventGarbageCollection(GlobalEnvironment* global_environment,
Wrappable* wrappable)
- : global_environment(global_environment), wrappable(wrappable) {
+ : global_environment(global_environment->AsWeakPtr()), wrappable(wrappable) {
global_environment->PreventGarbageCollection(
base::WrapRefCounted(wrappable));
}
~ScopedPreventGarbageCollection() {
- global_environment->AllowGarbageCollection(wrappable);
+ if (global_environment) {
+ global_environment->AllowGarbageCollection(wrappable);
+ }
}
private:
- GlobalEnvironment* global_environment;
+ base::WeakPtr<GlobalEnvironment> global_environment;
Wrappable* wrappable;
};
diff --git a/src/cobalt/version.h b/src/cobalt/version.h
index 98d2e93..b7fa7b2 100644
--- a/src/cobalt/version.h
+++ b/src/cobalt/version.h
@@ -35,6 +35,6 @@
// release is cut.
//.
-#define COBALT_VERSION "20.lts.3"
+#define COBALT_VERSION "20.lts.4"
#endif // COBALT_VERSION_H_
diff --git a/src/starboard/android/apk/app/build.gradle b/src/starboard/android/apk/app/build.gradle
index ad09589..231fbb9 100644
--- a/src/starboard/android/apk/app/build.gradle
+++ b/src/starboard/android/apk/app/build.gradle
@@ -33,8 +33,8 @@
println "TARGET: ${cobaltTarget}"
android {
- compileSdkVersion 28
- buildToolsVersion "28.0.3"
+ compileSdkVersion 29
+ buildToolsVersion "29.0.2"
signingConfigs {
// A signing config that matches what is implicitly used for the "debug" build type.
@@ -48,7 +48,7 @@
defaultConfig {
applicationId "dev.cobalt.coat"
minSdkVersion 21
- targetSdkVersion 28
+ targetSdkVersion 29
versionCode 1
versionName "${buildId}"
manifestPlaceholders = [applicationName: "CoAT: ${cobaltTarget}"]
@@ -130,10 +130,10 @@
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
- if (project.hasProperty('cobaltGradleDir')) {
- // Resolve relative to the current dir at config time by getting a canonical File.
- buildStagingDirectory new File(cobaltGradleDir, 'externalNativeBuild').canonicalFile
- }
+ // Move the staging directory to be a sibling of the build directory, which we moved
+ // in the top-level build.gradle to be in a common top-level 'build' directory. Get
+ // the canonical file at config time so that it's still right at build time.
+ buildStagingDirectory new File("${buildDir}.cxx").canonicalFile
}
}
}
@@ -154,9 +154,9 @@
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
- implementation 'com.android.support:support-annotations:28.0.0'
- implementation 'com.android.support:leanback-v17:28.0.0'
- implementation 'com.android.support:support-v4:28.0.0'
- implementation 'com.google.android.gms:play-services-auth:16.0.1'
+ implementation 'androidx.annotation:annotation:1.1.0'
+ implementation 'androidx.leanback:leanback:1.0.0'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation 'com.google.android.gms:play-services-auth:17.0.0'
implementation 'com.google.protobuf:protobuf-lite:3.0.1'
}
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/account/UserAuthorizerImpl.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/account/UserAuthorizerImpl.java
index 136da8b..1902635 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/account/UserAuthorizerImpl.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/account/UserAuthorizerImpl.java
@@ -27,10 +27,10 @@
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.widget.Toast;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.UserRecoverableAuthException;
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/AudioPermissionRequester.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/AudioPermissionRequester.java
index f8640d8..59ae6ad 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/AudioPermissionRequester.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/AudioPermissionRequester.java
@@ -18,8 +18,8 @@
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
import dev.cobalt.util.Holder;
import dev.cobalt.util.UsedByNative;
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltA11yHelper.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltA11yHelper.java
index 8c07518..b0fcb50 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltA11yHelper.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltA11yHelper.java
@@ -19,11 +19,11 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.widget.ExploreByTouchHelper;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.customview.widget.ExploreByTouchHelper;
import dev.cobalt.util.Log;
import java.util.BitSet;
import java.util.List;
@@ -45,11 +45,19 @@
private static final int FAKE_VIEW_HEIGHT = 10;
private static final int FAKE_VIEW_WIDTH = 10;
- private int previousFocusedViewId = 1;
+ private static final int CENTER_VIEW_ID = 5;
+ private static final int UP_VIEW_ID = 2;
+ private static final int DOWN_VIEW_ID = 8;
+ private static final int LEFT_VIEW_ID = 4;
+ private static final int RIGHT_VIEW_ID = 6;
+
+ private static final int INPUT_FOCUS_CHANGE_DELAY = 1500; // milliseconds
+
// This set tracks whether onPopulateNodeForVirtualView has been
// called for each virtual view id.
private final BitSet nodePopulatedSet = new BitSet(9);
private final Handler handler = new Handler();
+ private boolean unhandledInput;
private boolean hasInitialFocusBeenSet;
public CobaltA11yHelper(View view) {
@@ -77,70 +85,53 @@
}
}
- /**
- * Returns the "patch number" for a given view id, given a focused view id.
- *
- * <p>A "patch number" is a 1-9 number that describes where the requestedViewId is now located on
- * an X-Y grid, given the focusedViewId.
- *
- * <p>Patch number grid:
- * (0,0)----->X
- * |+-+-+-+
- * ||1|2|3|
- * |+-+-+-|
- * ||4|5|6|
- * |+-+-+-|
- * ||7|8|9|
- * |+-+-+-+
- * \./ Y
- *
- * <p>As focus changes, the locations of the views are moved so the focused view is always in the
- * middle (patch number 5) and all of the other views always in the same relative position with
- * respect to each other (with those on the edges adjacent to those on the opposite edges --
- * wrapping around).
- *
- * <p>5 is returned whenever focusedViewId = requestedViewId
- */
- private static int getPatchNumber(int focusedViewId, int requestedViewId) {
- // The (x,y) the focused view has in the 9 patch where 5 is in the middle.
- int focusedX = (focusedViewId - 1) % 3;
- int focusedY = (focusedViewId - 1) / 3;
+ private void focusOnCenter() {
+ // Setting Accessibility focus to CENTER_VIEW_ID will make TalkBack focus
+ // on CENTER_VIEW_ID immediately, but the actual mouse focus is either
+ // unchanged or return INVALID_ID.
+ handler.post(
+ new Runnable() {
+ @Override
+ public void run() {
+ sendEventForVirtualView(
+ CENTER_VIEW_ID, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+ }
+ });
- // x and y offsets of focused view where middle is (0, 0)
- int focusedRelativeToCenterX = focusedX - 1;
- int focusedRelativeToCenterY = focusedY - 1;
-
- // The (x,y) the requested view has in the 9 patch where 5 is in the middle.
- int requestedX = (requestedViewId - 1) % 3;
- int requestedY = (requestedViewId - 1) / 3;
-
- // x and y offsets of requested view where middle is (0, 0)
- int requestedRelativeToCenterX = requestedX - 1;
- int requestedRelativeToCenterY = requestedY - 1;
-
- // The (x,y) that the requested view has in the 9 patch when focusedViewId
- // is in the middle.
- int translatedRequestedX = (1 + 3 + requestedRelativeToCenterX - focusedRelativeToCenterX) % 3;
- int translatedRequestedY = (1 + 3 + requestedRelativeToCenterY - focusedRelativeToCenterY) % 3;
-
- return (translatedRequestedY * 3) + translatedRequestedX + 1;
+ // There is a knwon Android bug about setting focus too early
+ // taking no effect. The impact for Cobalt is that sometimes after
+ // we click on a video, TalkBack sees nothing in focus in the watch
+ // page if no user input happens. To avoid this bug we have to
+ // delay the focus long enough for all the TalkBack movements to settle
+ // down. More details here: https://stackoverflow.com/questions/28472985.
+ handler.postDelayed(
+ new Runnable() {
+ @Override
+ public void run() {
+ sendEventForVirtualView(
+ CENTER_VIEW_ID, AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ }
+ }, INPUT_FOCUS_CHANGE_DELAY);
}
private void maybeInjectEvent(int currentFocusedViewId) {
- switch (getPatchNumber(previousFocusedViewId, currentFocusedViewId)) {
- case 5:
+ if (!unhandledInput) {
+ return;
+ }
+ switch (currentFocusedViewId) {
+ case CENTER_VIEW_ID:
// no move;
break;
- case 2:
+ case UP_VIEW_ID:
nativeInjectKeyEvent(SB_KEY_GAMEPAD_DPAD_UP);
break;
- case 4:
+ case LEFT_VIEW_ID:
nativeInjectKeyEvent(SB_KEY_GAMEPAD_DPAD_LEFT);
break;
- case 6:
+ case RIGHT_VIEW_ID:
nativeInjectKeyEvent(SB_KEY_GAMEPAD_DPAD_RIGHT);
break;
- case 8:
+ case DOWN_VIEW_ID:
nativeInjectKeyEvent(SB_KEY_GAMEPAD_DPAD_DOWN);
break;
default:
@@ -148,9 +139,26 @@
// not possible to reach this.
break;
}
- previousFocusedViewId = currentFocusedViewId;
+ unhandledInput = false;
+ focusOnCenter();
}
+ /**
+ * <p>Fake number grid:
+ * |+-+-+-+
+ * ||1|2|3|
+ * |+-+-+-|
+ * ||4|5|6|
+ * |+-+-+-|
+ * ||7|8|9|
+ * |+-+-+-+
+ *
+ * <p>The focus always starts from the middle number 5. When user changes
+ * focus, the focus is then moved to either 2, 4, 6 or 8 and we can capture
+ * the movement this way. The focus is then quickly switched back to the
+ * center 5 to be ready for the next movement.
+ *
+ */
@Override
protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat node) {
int focusedViewId = getAccessibilityFocusedVirtualViewId();
@@ -158,18 +166,20 @@
if (focusedViewId < 1 || focusedViewId > 9) {
// If this is not one of our nine-patch views, it's probably HOST_ID
// In any case, assume there is no focus change.
- focusedViewId = previousFocusedViewId;
+ focusedViewId = CENTER_VIEW_ID;
}
// onPopulateNodeForVirtualView() gets called at least once every
// time the focused view changes. So see if it's changed since the
// last time we've been called and inject an event if so.
- maybeInjectEvent(focusedViewId);
+ if (focusedViewId != CENTER_VIEW_ID) {
+ maybeInjectEvent(focusedViewId);
+ } else {
+ unhandledInput = true;
+ }
- int patchNumber = getPatchNumber(focusedViewId, virtualViewId);
-
- int x = (patchNumber - 1) % 3;
- int y = (patchNumber - 1) / 3;
+ int x = (virtualViewId - 1) % 3;
+ int y = (virtualViewId - 1) / 3;
// Note that the specific bounds here are arbitrary. The importance
// is the relative bounds to each other.
@@ -188,14 +198,7 @@
// but not before, ask that the accessibility focus be moved from
// it's initial position on HOST_ID to the one we want to start with.
hasInitialFocusBeenSet = true;
- handler.post(
- new Runnable() {
- @Override
- public void run() {
- sendEventForVirtualView(
- previousFocusedViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
- }
- });
+ focusOnCenter();
}
}
@@ -203,59 +206,4 @@
protected boolean onPerformActionForVirtualView(int virtualViewId, int action, Bundle arguments) {
return false;
}
-
- /** A simple equivilent to Assert.assertEquals so we don't depend on junit */
- private static void assertEquals(int expected, int actual) {
- if (expected != actual) {
- throw new RuntimeException("Expected " + expected + " actual " + actual);
- }
- }
-
- /**
- * Unit test for getPatchNumber().
- *
- * <p>As of this writing, the Java portion of the Cobalt build has no unit test mechanism.
- *
- * <p>To run this test, simply call it from application start and start the application.
- *
- * <p>TODO: Move this to a real unit test location when one exists.
- */
- private static void testGetPatchNumber() {
- Log.i(TAG, "+testGetPatchNumber");
-
- assertEquals(1, getPatchNumber(5, 1));
- assertEquals(2, getPatchNumber(5, 2));
- assertEquals(3, getPatchNumber(5, 3));
- assertEquals(4, getPatchNumber(5, 4));
- assertEquals(5, getPatchNumber(5, 5));
- assertEquals(6, getPatchNumber(5, 6));
- assertEquals(7, getPatchNumber(5, 7));
- assertEquals(8, getPatchNumber(5, 8));
- assertEquals(9, getPatchNumber(5, 9));
-
- for (int i = 1; i <= 9; i++) {
- assertEquals(5, getPatchNumber(i, i));
- }
-
- assertEquals(5, getPatchNumber(1, 1));
- assertEquals(6, getPatchNumber(1, 2));
- assertEquals(4, getPatchNumber(1, 3));
- assertEquals(8, getPatchNumber(1, 4));
- assertEquals(9, getPatchNumber(1, 5));
- assertEquals(7, getPatchNumber(1, 6));
- assertEquals(2, getPatchNumber(1, 7));
- assertEquals(3, getPatchNumber(1, 8));
- assertEquals(1, getPatchNumber(1, 9));
-
- assertEquals(9, getPatchNumber(9, 1));
- assertEquals(7, getPatchNumber(9, 2));
- assertEquals(8, getPatchNumber(9, 3));
- assertEquals(3, getPatchNumber(9, 4));
- assertEquals(1, getPatchNumber(9, 5));
- assertEquals(2, getPatchNumber(9, 6));
- assertEquals(6, getPatchNumber(9, 7));
- assertEquals(4, getPatchNumber(9, 8));
- assertEquals(5, getPatchNumber(9, 9));
- Log.i(TAG, "-testGetPatchNumber");
- }
}
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/PlatformError.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/PlatformError.java
index db0cae7..999b349 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/PlatformError.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/PlatformError.java
@@ -23,7 +23,7 @@
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
-import android.support.annotation.IntDef;
+import androidx.annotation.IntDef;
import dev.cobalt.util.Holder;
import dev.cobalt.util.Log;
import java.lang.annotation.Retention;
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
index 85c7c56..ee77d2d 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
@@ -18,7 +18,6 @@
import static android.media.AudioManager.GET_DEVICES_INPUTS;
import static dev.cobalt.util.Log.TAG;
-import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
@@ -34,6 +33,7 @@
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.CaptioningManager;
+import androidx.annotation.RequiresApi;
import dev.cobalt.account.UserAuthorizer;
import dev.cobalt.feedback.FeedbackService;
import dev.cobalt.media.AudioOutputManager;
@@ -146,7 +146,7 @@
@SuppressWarnings("unused")
@UsedByNative
- void beforeStartOrResume() {
+ protected void beforeStartOrResume() {
Log.i(TAG, "Prepare to resume");
// Bring our platform services to life before resuming so that they're ready to deal with
// whatever the web app wants to do with them as part of its start/resume logic.
@@ -159,7 +159,7 @@
@SuppressWarnings("unused")
@UsedByNative
- void beforeSuspend() {
+ protected void beforeSuspend() {
Log.i(TAG, "Prepare to suspend");
// We want the MediaSession to be deactivated immediately before suspending so that by the time
// the launcher is visible our "Now Playing" card is already gone. Then Cobalt and the web app
@@ -173,7 +173,7 @@
@SuppressWarnings("unused")
@UsedByNative
- void afterStopped() {
+ protected void afterStopped() {
starboardStopped = true;
ttsHelper.shutdown();
userAuthorizer.shutdown();
@@ -326,7 +326,7 @@
}
}
- @TargetApi(23)
+ @RequiresApi(23)
private boolean isMicrophoneConnectedV23() {
// A check specifically for microphones is not available before API 28, so it is assumed that a
// connected input audio device is a microphone.
@@ -430,7 +430,7 @@
/** Returns string for kSbSystemPropertyUserAgentAuxField */
@SuppressWarnings("unused")
@UsedByNative
- String getUserAgentAuxField() {
+ protected String getUserAgentAuxField() {
StringBuilder sb = new StringBuilder();
String packageName = appContext.getApplicationInfo().packageName;
@@ -497,7 +497,7 @@
* https://developer.android.com/reference/android/view/Display.HdrCapabilities.html for valid
* values.
*/
- @TargetApi(24)
+ @RequiresApi(24)
@SuppressWarnings("unused")
@UsedByNative
public boolean isHdrTypeSupported(int hdrType) {
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/ArtworkLoader.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/ArtworkLoader.java
index d76266f..8fb4945 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/ArtworkLoader.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/ArtworkLoader.java
@@ -19,9 +19,9 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
-import android.support.annotation.NonNull;
import android.util.Pair;
import android.util.Size;
+import androidx.annotation.NonNull;
import dev.cobalt.util.Log;
import java.io.IOException;
import java.io.InputStream;
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java
index 2105e5b..0508e27 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java
@@ -16,11 +16,11 @@
import static dev.cobalt.media.Log.TAG;
-import android.annotation.TargetApi;
import android.content.Context;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.os.Build;
+import androidx.annotation.RequiresApi;
import dev.cobalt.util.Log;
import dev.cobalt.util.UsedByNative;
import java.util.ArrayList;
@@ -85,7 +85,7 @@
}
/** Returns the maximum number of HDMI channels for API 23 and above. */
- @TargetApi(23)
+ @RequiresApi(23)
private int getMaxChannelsV23() {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
AudioDeviceInfo[] deviceInfos = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
index ec1fd88..419f5d8 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
@@ -16,13 +16,13 @@
import static dev.cobalt.media.Log.TAG;
-import android.annotation.TargetApi;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTimestamp;
import android.media.AudioTrack;
import android.os.Build;
+import androidx.annotation.RequiresApi;
import dev.cobalt.util.Log;
import dev.cobalt.util.UsedByNative;
import java.nio.ByteBuffer;
@@ -213,7 +213,7 @@
return 0;
}
- @TargetApi(24)
+ @RequiresApi(24)
private int getUnderrunCountV24() {
if (audioTrack == null) {
Log.e(TAG, "Unable to call getUnderrunCount() with NULL audio track.");
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/CobaltMediaSession.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/CobaltMediaSession.java
index ae511c9..2bfce23 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/CobaltMediaSession.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/CobaltMediaSession.java
@@ -16,7 +16,6 @@
import static dev.cobalt.media.Log.TAG;
-import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
@@ -31,6 +30,7 @@
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.view.WindowManager;
+import androidx.annotation.RequiresApi;
import dev.cobalt.util.DisplayUtil;
import dev.cobalt.util.Holder;
import dev.cobalt.util.Log;
@@ -262,7 +262,7 @@
.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
- @TargetApi(26)
+ @RequiresApi(26)
private int requestAudioFocusV26() {
if (audioFocusRequest == null) {
AudioAttributes audioAtrributes =
@@ -281,7 +281,7 @@
getAudioManager().abandonAudioFocus(this);
}
- @TargetApi(26)
+ @RequiresApi(26)
private void abandonAudioFocusV26() {
if (audioFocusRequest != null) {
getAudioManager().abandonAudioFocusRequest(audioFocusRequest);
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
index 1c597b2..064fc65 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
@@ -327,6 +327,7 @@
hdrStaticInfo.putShort((short) (minMasteringLuminance + 0.5f));
hdrStaticInfo.putShort((short) DEFAULT_MAX_CLL);
hdrStaticInfo.putShort((short) DEFAULT_MAX_FALL);
+ hdrStaticInfo.rewind();
this.hdrStaticInfo = hdrStaticInfo;
}
}
@@ -495,7 +496,7 @@
boolean shouldConfigureHdr =
android.os.Build.VERSION.SDK_INT >= 24
&& colorInfo != null
- && MediaCodecUtil.isHdrCapableVp9Decoder(findVideoDecoderResult);
+ && MediaCodecUtil.isHdrCapableVideoDecoder(mime, findVideoDecoderResult);
if (shouldConfigureHdr) {
Log.d(TAG, "Setting HDR info.");
mediaFormat.setInteger(MediaFormat.KEY_COLOR_TRANSFER, colorInfo.colorTransfer);
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java
index b7fdad8..8991611 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java
@@ -44,6 +44,7 @@
private static boolean isVp9WhiteListed;
private static final String SECURE_DECODER_SUFFIX = ".secure";
private static final String VP9_MIME_TYPE = "video/x-vnd.on2.vp9";
+ private static final String AV1_MIME_TYPE = "video/av01";
/**
* A simple "struct" to bundle up the results from findVideoDecoder, as its clients may require
@@ -392,7 +393,7 @@
FindVideoDecoderResult findVideoDecoderResult =
findVideoDecoder(mimeType, secure, frameWidth, frameHeight, bitrate, fps, mustSupportHdr);
return !findVideoDecoderResult.name.equals("")
- && (!mustSupportHdr || isHdrCapableVp9Decoder(findVideoDecoderResult));
+ && (!mustSupportHdr || isHdrCapableVideoDecoder(mimeType, findVideoDecoderResult));
}
/**
@@ -405,23 +406,32 @@
return !findAudioDecoder(mimeType, bitrate).equals("");
}
- /** Determine whether the system has a decoder capable of playing HDR VP9. */
+ /**
+ * Determine whether the system has a decoder capable of playing HDR. Currently VP9 and AV1 are
+ * HDR supported codecs
+ */
@SuppressWarnings("unused")
@UsedByNative
- public static boolean hasHdrCapableVp9Decoder() {
+ public static boolean hasHdrCapableVideoDecoder(String mimeType) {
// VP9Profile* values were not added until API level 24. See
// https://developer.android.com/reference/android/media/MediaCodecInfo.CodecProfileLevel.html.
if (Build.VERSION.SDK_INT < 24) {
return false;
}
+ // AV1ProfileMain10HDR10 value was not added until API level 29. See
+ // https://developer.android.com/reference/android/media/MediaCodecInfo.CodecProfileLevel.html.
+ if (mimeType.equals(AV1_MIME_TYPE) && Build.VERSION.SDK_INT < 29) {
+ return false;
+ }
FindVideoDecoderResult findVideoDecoderResult =
- findVideoDecoder(VP9_MIME_TYPE, false, 0, 0, 0, 0, true);
- return isHdrCapableVp9Decoder(findVideoDecoderResult);
+ findVideoDecoder(mimeType, false, 0, 0, 0, 0, true);
+ return isHdrCapableVideoDecoder(mimeType, findVideoDecoderResult);
}
- /** Determine whether findVideoDecoderResult is capable of playing HDR VP9 */
- public static boolean isHdrCapableVp9Decoder(FindVideoDecoderResult findVideoDecoderResult) {
+ /** Determine whether findVideoDecoderResult is capable of playing HDR */
+ public static boolean isHdrCapableVideoDecoder(
+ String mimeType, FindVideoDecoderResult findVideoDecoderResult) {
CodecCapabilities codecCapabilities = findVideoDecoderResult.codecCapabilities;
if (codecCapabilities == null) {
return false;
@@ -431,9 +441,15 @@
return false;
}
for (CodecProfileLevel codecProfileLevel : codecProfileLevels) {
- if (codecProfileLevel.profile == CodecProfileLevel.VP9Profile2HDR
- || codecProfileLevel.profile == CodecProfileLevel.VP9Profile3HDR) {
- return true;
+ if (mimeType.equals(VP9_MIME_TYPE)) {
+ if (codecProfileLevel.profile == CodecProfileLevel.VP9Profile2HDR
+ || codecProfileLevel.profile == CodecProfileLevel.VP9Profile3HDR) {
+ return true;
+ }
+ } else if (mimeType.equals(AV1_MIME_TYPE)) {
+ if (codecProfileLevel.profile == CodecProfileLevel.AV1ProfileMain10HDR10) {
+ return true;
+ }
}
}
@@ -569,7 +585,8 @@
: name;
FindVideoDecoderResult findVideoDecoderResult =
new FindVideoDecoderResult(resultName, videoCapabilities, codecCapabilities);
- if (hdr && !isHdrCapableVp9Decoder(findVideoDecoderResult)) {
+ if (hdr && !isHdrCapableVideoDecoder(mimeType, findVideoDecoderResult)) {
+ Log.v(TAG, String.format("Rejecting %s, reason: codec does not support HDR", name));
continue;
}
Log.v(TAG, String.format("Found suitable decoder, %s", name));
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java
index 24fe96f..3af5ad5 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java
@@ -20,7 +20,6 @@
import static dev.cobalt.media.Log.TAG;
-import android.annotation.TargetApi;
import android.media.DeniedByServerException;
import android.media.MediaCrypto;
import android.media.MediaCryptoException;
@@ -30,6 +29,7 @@
import android.media.NotProvisionedException;
import android.media.UnsupportedSchemeException;
import android.os.Build;
+import androidx.annotation.RequiresApi;
import dev.cobalt.coat.CobaltHttpHelper;
import dev.cobalt.util.Log;
import dev.cobalt.util.UsedByNative;
@@ -429,7 +429,7 @@
mMediaDrm.setPropertyString("sessionSharing", "enable");
}
- @TargetApi(23)
+ @RequiresApi(23)
private void setOnKeyStatusChangeListenerV23() {
mMediaDrm.setOnKeyStatusChangeListener(
new MediaDrm.OnKeyStatusChangeListener() {
@@ -546,7 +546,12 @@
Log.e(TAG, "Failed to provision device during MediaCrypto creation.");
return false;
}
- return true;
+ try {
+ mMediaCryptoSession = openSession();
+ } catch (NotProvisionedException e2) {
+ Log.e(TAG, "Device still not provisioned after supposedly successful provisioning", e2);
+ return false;
+ }
}
if (mMediaCryptoSession == null) {
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/VideoFrameReleaseTimeHelper.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/VideoFrameReleaseTimeHelper.java
index 4287c8c..0274811 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/VideoFrameReleaseTimeHelper.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/VideoFrameReleaseTimeHelper.java
@@ -29,7 +29,6 @@
package dev.cobalt.media;
-import android.annotation.TargetApi;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
@@ -37,10 +36,11 @@
import android.view.Choreographer;
import android.view.Choreographer.FrameCallback;
import android.view.WindowManager;
+import androidx.annotation.RequiresApi;
import dev.cobalt.util.UsedByNative;
/** Makes a best effort to adjust frame release timestamps for a smoother visual result. */
-@TargetApi(16)
+@RequiresApi(16)
@SuppressWarnings("unused")
@UsedByNative
public final class VideoFrameReleaseTimeHelper {
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/storage/CobaltStorageLoader.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/storage/CobaltStorageLoader.java
index c471b0c..680445f 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/storage/CobaltStorageLoader.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/storage/CobaltStorageLoader.java
@@ -17,7 +17,7 @@
import static dev.cobalt.util.Log.TAG;
import android.os.FileObserver;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import com.google.protobuf.InvalidProtocolBufferException;
import dev.cobalt.storage.StorageProto.Storage;
import dev.cobalt.util.Log;
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/Holder.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/Holder.java
index 7fa3407..ad48bbd 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/Holder.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/Holder.java
@@ -14,7 +14,7 @@
package dev.cobalt.util;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
/** Holds a mutable reference to an object, or null. */
public class Holder<T> {
diff --git a/src/starboard/android/apk/build.gradle b/src/starboard/android/apk/build.gradle
index b50ae22..525c56b 100644
--- a/src/starboard/android/apk/build.gradle
+++ b/src/starboard/android/apk/build.gradle
@@ -20,7 +20,7 @@
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.3.0'
+ classpath 'com.android.tools.build:gradle:3.5.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -53,3 +53,10 @@
// 'buildDir' which can end up putting it at the wrong depth in the file system.
def rootBuildDir = hasProperty('cobaltGradleDir') ? new File(cobaltGradleDir, 'build') : buildDir
allprojects { buildDir = new File(rootBuildDir, project.name).canonicalFile }
+
+// Android Studio Gradle plugin 3.5+ builds all supported ABIs for a connected device. Override the
+// property it sets to build just the first one, which is the preferred ABI for the device.
+if (hasProperty('android.injected.build.abi')) {
+ def firstAbi = properties.get('android.injected.build.abi').split(',').first()
+ allprojects { setProperty('android.injected.build.abi', firstAbi) }
+}
diff --git a/src/starboard/android/apk/build.id b/src/starboard/android/apk/build.id
new file mode 100644
index 0000000..2a2074e
--- /dev/null
+++ b/src/starboard/android/apk/build.id
@@ -0,0 +1 @@
+263411
\ No newline at end of file
diff --git a/src/starboard/android/apk/cobalt-gradle.sh b/src/starboard/android/apk/cobalt-gradle.sh
index d135b4b..4a37c4f 100755
--- a/src/starboard/android/apk/cobalt-gradle.sh
+++ b/src/starboard/android/apk/cobalt-gradle.sh
@@ -22,7 +22,6 @@
while [ "$1" ]; do
case "$1" in
--sdk) shift; ANDROID_HOME="$1" ;;
- --ndk) shift; ANDROID_NDK_HOME="$1" ;;
--cache) shift; mkdir -p "$1";
GRADLE_ARGS+=("--project-cache-dir" $(cd "$1"; pwd)) ;;
--reset) RESET_GRADLE=1 ;;
@@ -50,9 +49,7 @@
fi
export ANDROID_HOME
-export ANDROID_NDK_HOME
echo "ANDROID_HOME=${ANDROID_HOME}"
-echo "ANDROID_NDK_HOME=${ANDROID_NDK_HOME}"
echo "TASK: ${GRADLE_ARGS[-1]}"
# Allow parallel gradle builds, as defined by a COBALT_GRADLE_BUILD_COUNT envvar
diff --git a/src/starboard/android/apk/gradle.properties b/src/starboard/android/apk/gradle.properties
index 2d5bfe3..d9f30ec 100644
--- a/src/starboard/android/apk/gradle.properties
+++ b/src/starboard/android/apk/gradle.properties
@@ -23,6 +23,8 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
+android.enableJetifier=true
+android.useAndroidX=true
org.gradle.jvmargs=-Xmx4g
# When configured, Gradle will run in incubating parallel mode.
diff --git a/src/starboard/android/apk/gradle/wrapper/gradle-wrapper.properties b/src/starboard/android/apk/gradle/wrapper/gradle-wrapper.properties
index b17c1fc..cb820ac 100644
--- a/src/starboard/android/apk/gradle/wrapper/gradle-wrapper.properties
+++ b/src/starboard/android/apk/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Jan 29 11:03:00 PST 2019
+#Thu Jan 02 11:15:25 PST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
diff --git a/src/starboard/android/shared/application_android.cc b/src/starboard/android/shared/application_android.cc
index cae801e..24b5517 100644
--- a/src/starboard/android/shared/application_android.cc
+++ b/src/starboard/android/shared/application_android.cc
@@ -362,7 +362,6 @@
}
void ApplicationAndroid::ProcessAndroidInput() {
- SB_DCHECK(input_events_generator_);
AInputEvent* android_event = NULL;
while (AInputQueue_getEvent(input_queue_, &android_event) >= 0) {
SB_LOG(INFO) << "Android input: type="
@@ -370,6 +369,11 @@
if (AInputQueue_preDispatchEvent(input_queue_, android_event)) {
continue;
}
+ if (!input_events_generator_) {
+ SB_DLOG(WARNING) << "Android input event ignored without an SbWindow.";
+ AInputQueue_finishEvent(input_queue_, android_event, false);
+ continue;
+ }
InputEventsGenerator::Events app_events;
bool handled = input_events_generator_->CreateInputEventsFromAndroidEvent(
android_event, &app_events);
@@ -385,7 +389,10 @@
int err = read(keyboard_inject_readfd_, &key, sizeof(key));
SB_DCHECK(err >= 0) << "Keyboard inject read failed: errno=" << errno;
SB_LOG(INFO) << "Keyboard inject: " << key;
-
+ if (!input_events_generator_) {
+ SB_DLOG(WARNING) << "Injected input event ignored without an SbWindow.";
+ return;
+ }
InputEventsGenerator::Events app_events;
input_events_generator_->CreateInputEventsFromSbKey(key, &app_events);
for (int i = 0; i < app_events.size(); ++i) {
diff --git a/src/starboard/android/shared/cobalt/android_media_session_client.cc b/src/starboard/android/shared/cobalt/android_media_session_client.cc
index 1861af9..30ec630 100644
--- a/src/starboard/android/shared/cobalt/android_media_session_client.cc
+++ b/src/starboard/android/shared/cobalt/android_media_session_client.cc
@@ -289,12 +289,16 @@
}
}
- jlong duration = session_state.duration();
- // Set duration to negative if duration is unknown or infinite, as with live
- // playback.
- // https://developer.android.com/reference/android/support/v4/media/MediaMetadataCompat#METADATA_KEY_DURATION
- if (duration == kSbTimeMax) {
- duration = -1;
+ jlong durationInMilliseconds;
+ if (session_state.duration() == kSbTimeMax) {
+ // Set duration to negative if duration is unknown or infinite, as with live
+ // playback.
+ // https://developer.android.com/reference/android/support/v4/media/MediaMetadataCompat#METADATA_KEY_DURATION
+ durationInMilliseconds = -1;
+ } else {
+ // SbTime is measured in microseconds while Android MediaSession expects
+ // duration in milliseconds.
+ durationInMilliseconds = session_state.duration() / kSbTimeMillisecond;
}
env->CallStarboardVoidMethodOrAbort(
@@ -305,7 +309,7 @@
session_state.current_playback_position() / kSbTimeMillisecond,
static_cast<jfloat>(session_state.actual_playback_rate()),
j_title.Get(), j_artist.Get(), j_album.Get(), j_artwork.Get(),
- duration);
+ durationInMilliseconds);
}
};
diff --git a/src/starboard/android/shared/cobalt/configuration.py b/src/starboard/android/shared/cobalt/configuration.py
index 3633045..8fac1a4 100644
--- a/src/starboard/android/shared/cobalt/configuration.py
+++ b/src/starboard/android/shared/cobalt/configuration.py
@@ -60,6 +60,7 @@
# Disabled because of: Fail (Tests do not account for player with url?).
('csp/WebPlatformTest.Run/'
'content_security_policy_media_src_media_src_allowed_html'),
+ ('websockets/WebPlatformTest.Run/websockets_*'),
]
return filters
diff --git a/src/starboard/android/shared/configuration_public.h b/src/starboard/android/shared/configuration_public.h
index 8236b6e..33e0714 100644
--- a/src/starboard/android/shared/configuration_public.h
+++ b/src/starboard/android/shared/configuration_public.h
@@ -330,6 +330,11 @@
// stack size for media stack threads.
#define SB_MEDIA_THREAD_STACK_SIZE 0U
+// Specifies whether this platform support the improved player creation and
+// output mode query. Please see comments of SbPlayerCreate() and
+// SbPlayerGetPreferredOutputMode() in player.h for more details.
+#define SB_HAS_PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT 1
+
// --- Decoder-only Params ---
// Specifies how media buffers must be aligned on this platform as some
diff --git a/src/starboard/android/shared/log.cc b/src/starboard/android/shared/log.cc
index 35ed73d..6cbc17f 100644
--- a/src/starboard/android/shared/log.cc
+++ b/src/starboard/android/shared/log.cc
@@ -25,11 +25,8 @@
#include "starboard/common/log.h"
#include "starboard/common/string.h"
#include "starboard/configuration.h"
-#include "starboard/thread.h"
-
-#if SB_API_VERSION >= 11
#include "starboard/shared/starboard/log_mutex.h"
-#endif // SB_API_VERSION >= 11
+#include "starboard/thread.h"
using starboard::android::shared::JniEnvExt;
using starboard::android::shared::ScopedLocalJavaRef;
diff --git a/src/starboard/android/shared/media_decoder.cc b/src/starboard/android/shared/media_decoder.cc
index 482b6a8..f1a3dfb 100644
--- a/src/starboard/android/shared/media_decoder.cc
+++ b/src/starboard/android/shared/media_decoder.cc
@@ -18,11 +18,9 @@
#include "starboard/android/shared/jni_utils.h"
#include "starboard/android/shared/media_common.h"
#include "starboard/audio_sink.h"
-#if SB_API_VERSION >= 11
-#include "starboard/format_string.h"
-#endif // SB_API_VERSION >= 11
#include "starboard/common/log.h"
#include "starboard/common/string.h"
+#include "starboard/format_string.h"
#include "starboard/shared/pthread/thread_create_priority.h"
namespace starboard {
diff --git a/src/starboard/android/shared/media_is_video_supported.cc b/src/starboard/android/shared/media_is_video_supported.cc
index 239130a..d5260c9 100644
--- a/src/starboard/android/shared/media_is_video_supported.cc
+++ b/src/starboard/android/shared/media_is_video_supported.cc
@@ -33,15 +33,21 @@
const jint HDR_TYPE_HDR10 = 2;
const jint HDR_TYPE_HLG = 3;
-bool IsHDRTransferCharacteristicsSupported(SbMediaTransferId transfer_id) {
- SB_DCHECK(transfer_id != kSbMediaTransferIdBt709 &&
- transfer_id != kSbMediaTransferIdUnspecified);
- // An HDR capable VP9 decoder is needed to handle HDR at all.
- bool has_hdr_capable_vp9_decoder =
+bool IsHDRTransferCharacteristicsSupported(SbMediaVideoCodec video_codec,
+ SbMediaTransferId transfer_id) {
+ const char* mime = SupportedVideoCodecToMimeType(video_codec);
+ if (!mime) {
+ return false;
+ }
+ JniEnvExt* env = JniEnvExt::Get();
+
+ // An HDR capable VP9 or AV1 decoder is needed to handle HDR at all.
+ bool has_hdr_capable_decoder =
JniEnvExt::Get()->CallStaticBooleanMethodOrAbort(
- "dev/cobalt/media/MediaCodecUtil", "hasHdrCapableVp9Decoder",
- "()Z") == JNI_TRUE;
- if (!has_hdr_capable_vp9_decoder) {
+ "dev/cobalt/media/MediaCodecUtil", "hasHdrCapableVideoDecoder",
+ "(Ljava/lang/String;)Z",
+ env->NewStringStandardUTFOrAbort(mime)) == JNI_TRUE;
+ if (!has_hdr_capable_decoder) {
return false;
}
@@ -75,7 +81,7 @@
int fps,
bool decode_to_texture_required) {
if (!IsSDRVideo(bit_depth, primary_id, transfer_id, matrix_id)) {
- if (!IsHDRTransferCharacteristicsSupported(transfer_id)) {
+ if (!IsHDRTransferCharacteristicsSupported(video_codec, transfer_id)) {
return false;
}
}
diff --git a/src/starboard/android/shared/platform_deploy.gypi b/src/starboard/android/shared/platform_deploy.gypi
index 3d6e60f..ecc7699 100644
--- a/src/starboard/android/shared/platform_deploy.gypi
+++ b/src/starboard/android/shared/platform_deploy.gypi
@@ -40,14 +40,13 @@
'action': [
'<(DEPTH)/starboard/android/apk/cobalt-gradle.sh',
'--sdk', '<(ANDROID_HOME)',
- '--ndk', '<(NDK_HOME)',
- '--cache', '<(GRADLE_FILES_DIR)/cache',
- '--project-dir', '<(DEPTH)/starboard/android/apk/',
+ '--cache', '$${PWD}/<(GRADLE_FILES_DIR)/cache',
+ '--project-dir', '$${PWD}/<(DEPTH)/starboard/android/apk/',
'-P', 'cobaltBuildAbi=<(ANDROID_ABI)',
- '-P', 'cobaltDeployApk=<(apk)',
- '-P', 'cobaltContentDir=<(content_deploy_dir)',
- '-P', 'cobaltGradleDir=<(GRADLE_FILES_DIR)',
- '-P', 'cobaltProductDir=<(PRODUCT_DIR)',
+ '-P', 'cobaltDeployApk=$${PWD}/<(apk)',
+ '-P', 'cobaltContentDir=$${PWD}/<(content_deploy_dir)',
+ '-P', 'cobaltGradleDir=$${PWD}/<(GRADLE_FILES_DIR)',
+ '-P', 'cobaltProductDir=$${PWD}/<(PRODUCT_DIR)',
'-P', 'cobaltTarget=<(executable_name)',
'assembleCobalt_<(GRADLE_BUILD_TYPE)',
],
diff --git a/src/starboard/android/shared/player_create.cc b/src/starboard/android/shared/player_create.cc
index 7edd8d6..142eaab 100644
--- a/src/starboard/android/shared/player_create.cc
+++ b/src/starboard/android/shared/player_create.cc
@@ -30,27 +30,38 @@
UpdateActiveSessionPlatformPlaybackState;
SbPlayer SbPlayerCreate(SbWindow window,
- SbMediaVideoCodec video_codec,
- SbMediaAudioCodec audio_codec,
-#if SB_API_VERSION < 10
- SbMediaTime duration_pts,
-#endif // SB_API_VERSION < 10
- SbDrmSystem drm_system,
- const SbMediaAudioSampleInfo* audio_sample_info,
- const char* max_video_capabilities,
+ const SbPlayerCreationParam* creation_param,
SbPlayerDeallocateSampleFunc sample_deallocate_func,
SbPlayerDecoderStatusFunc decoder_status_func,
SbPlayerStatusFunc player_status_func,
SbPlayerErrorFunc player_error_func,
void* context,
- SbPlayerOutputMode output_mode,
SbDecodeTargetGraphicsContextProvider* provider) {
SB_UNREFERENCED_PARAMETER(window);
- SB_UNREFERENCED_PARAMETER(max_video_capabilities);
- SB_UNREFERENCED_PARAMETER(provider);
-#if SB_API_VERSION < 10
- SB_UNREFERENCED_PARAMETER(duration_pts);
-#endif // SB_API_VERSION < 10
+
+ if (!creation_param) {
+ SB_LOG(ERROR) << "CreationParam cannot be null.";
+ return kSbPlayerInvalid;
+ }
+
+ if (!creation_param->audio_mime) {
+ SB_LOG(ERROR) << "creation_param->audio_mime cannot be null.";
+ return kSbPlayerInvalid;
+ }
+ if (!creation_param->video_mime) {
+ SB_LOG(ERROR) << "creation_param->video_mime cannot be null.";
+ return kSbPlayerInvalid;
+ }
+ if (!creation_param->max_video_capabilities) {
+ SB_LOG(ERROR) << "creation_param->max_video_capabilities cannot be null.";
+ return kSbPlayerInvalid;
+ }
+
+ SB_LOG(INFO) << "SbPlayerCreate() called with audio mime \""
+ << creation_param->audio_mime << "\", video mime \""
+ << creation_param->video_mime
+ << "\", and max video capabilities \""
+ << creation_param->max_video_capabilities << "\".";
if (!sample_deallocate_func || !decoder_status_func || !player_status_func
#if SB_HAS(PLAYER_ERROR_MESSAGE)
@@ -60,6 +71,9 @@
return kSbPlayerInvalid;
}
+ auto audio_codec = creation_param->audio_sample_info.codec;
+ auto video_codec = creation_param->video_sample_info.codec;
+
if (audio_codec != kSbMediaAudioCodecNone &&
audio_codec != kSbMediaAudioCodecAac &&
audio_codec != kSbMediaAudioCodecOpus) {
@@ -67,13 +81,6 @@
return kSbPlayerInvalid;
}
- if (audio_codec == kSbMediaAudioCodecAac && !audio_sample_info) {
- SB_LOG(ERROR)
- << "SbPlayerCreate() requires a non-NULL SbMediaAudioSampleInfo "
- << "when |audio_codec| is not kSbMediaAudioCodecNone";
- return kSbPlayerInvalid;
- }
-
if (video_codec != kSbMediaVideoCodecNone &&
video_codec != kSbMediaVideoCodecH264 &&
video_codec != kSbMediaVideoCodecVp9 &&
@@ -89,7 +96,8 @@
return kSbPlayerInvalid;
}
- if (!SbPlayerOutputModeSupported(output_mode, video_codec, drm_system)) {
+ auto output_mode = creation_param->output_mode;
+ if (SbPlayerGetPreferredOutputMode(creation_param) != output_mode) {
SB_LOG(ERROR) << "Unsupported player output mode " << output_mode;
return kSbPlayerInvalid;
}
@@ -103,13 +111,13 @@
UpdateActiveSessionPlatformPlaybackState(kPlaying);
starboard::scoped_ptr<PlayerWorker::Handler> handler(
- new FilterBasedPlayerWorkerHandler(video_codec, audio_codec, drm_system,
- audio_sample_info, output_mode,
- provider));
+ new FilterBasedPlayerWorkerHandler(
+ video_codec, audio_codec, creation_param->drm_system,
+ &creation_param->audio_sample_info, output_mode, provider));
SbPlayer player = SbPlayerPrivate::CreateInstance(
- audio_codec, video_codec, audio_sample_info, sample_deallocate_func,
- decoder_status_func, player_status_func, player_error_func, context,
- handler.Pass());
+ audio_codec, video_codec, &creation_param->audio_sample_info,
+ sample_deallocate_func, decoder_status_func, player_status_func,
+ player_error_func, context, handler.Pass());
// TODO: accomplish this through more direct means.
// Set the bounds to initialize the VideoSurfaceView. The initial values don't
diff --git a/src/starboard/android/shared/sdk_utils.py b/src/starboard/android/shared/sdk_utils.py
index bc0c11c..2618b8b 100644
--- a/src/starboard/android/shared/sdk_utils.py
+++ b/src/starboard/android/shared/sdk_utils.py
@@ -13,36 +13,36 @@
# limitations under the License.
"""Utilities to use the toolchain from the Android NDK."""
-import ConfigParser
+import errno
import fcntl
-import hashlib
import logging
import os
import re
import shutil
-import StringIO
import subprocess
import sys
import time
-import urllib
import zipfile
+import requests
from starboard.tools import build
+# Which version of the Android NDK to install and build with.
+_NDK_VERSION = '20.1.5948944'
+
# Packages to install in the Android SDK.
# We download ndk-bundle separately, so it's not in this list.
# Get available packages from "sdkmanager --list --verbose"
_ANDROID_SDK_PACKAGES = [
- 'build-tools;28.0.3',
- 'cmake;3.6.4111459',
+ 'build-tools;29.0.2',
+ 'cmake;3.10.2.4988404',
'emulator',
'extras;android;m2repository',
'extras;google;m2repository',
- 'lldb;3.1',
+ 'ndk;' + _NDK_VERSION,
'patcher;v4',
- 'platforms;android-28',
+ 'platforms;android-29',
'platform-tools',
- 'tools',
]
# Seconds to sleep before writing "y" for android sdk update license prompt.
@@ -50,11 +50,11 @@
# Location from which to download the SDK command-line tools
# see https://developer.android.com/studio/index.html#command-tools
-_SDK_URL = 'https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip'
+_SDK_URL = 'https://dl.google.com/android/repository/commandlinetools-linux-6200805_latest.zip'
# Location from which to download the Android NDK.
# see https://developer.android.com/ndk/downloads (perhaps in "NDK archives")
-_NDK_ZIP_REVISION = 'android-ndk-r19c'
+_NDK_ZIP_REVISION = 'android-ndk-r20b'
_NDK_ZIP_FILE = _NDK_ZIP_REVISION + '-linux-x86_64.zip'
_NDK_URL = 'https://dl.google.com/android/repository/' + _NDK_ZIP_FILE
@@ -70,44 +70,18 @@
else:
_SDK_PATH = _STARBOARD_TOOLCHAINS_SDK_DIR
-_ANDROID_NDK_HOME = os.environ.get('ANDROID_NDK_HOME')
-if _ANDROID_NDK_HOME:
- _NDK_PATH = _ANDROID_NDK_HOME
-else:
- _NDK_PATH = os.path.join(_SDK_PATH, 'ndk-bundle')
+_NDK_PATH = os.path.join(_SDK_PATH, 'ndk', _NDK_VERSION)
-_SDKMANAGER_TOOL = os.path.join(_SDK_PATH, 'tools', 'bin', 'sdkmanager')
-
-# Maps the Android ABI to the architecture name of the toolchain.
-_TOOLS_ABI_ARCH_MAP = {
- 'x86': 'x86',
- 'armeabi': 'arm',
- 'armeabi-v7a': 'arm',
- 'arm64-v8a': 'arm64',
-}
-
-_SCRIPT_HASH_PROPERTY = 'SdkUtils.Hash'
-
-with open(__file__, 'rb') as script:
- _SCRIPT_HASH = hashlib.md5(script.read()).hexdigest()
+_SDKMANAGER_TOOL = os.path.join(_SDK_PATH, 'cmdline-tools', '1.0', 'bin',
+ 'sdkmanager')
-def _CheckStamp(dir_path):
- """Checks that the specified directory is up-to-date with the NDK."""
- stamp_path = os.path.join(dir_path, 'ndk.stamp')
- return (os.path.exists(stamp_path) and
- _ReadNdkRevision(stamp_path) == _GetInstalledNdkRevision() and
- _ReadProperty(stamp_path, _SCRIPT_HASH_PROPERTY) == _SCRIPT_HASH)
-
-
-def _UpdateStamp(dir_path):
- """Updates the stamp file in the specified directory to the NDK revision."""
- path = GetNdkPath()
- properties_path = os.path.join(path, 'source.properties')
- stamp_path = os.path.join(dir_path, 'ndk.stamp')
- shutil.copyfile(properties_path, stamp_path)
- with open(stamp_path, 'a') as stamp:
- stamp.write('{} = {}\n'.format(_SCRIPT_HASH_PROPERTY, _SCRIPT_HASH))
+def _MakeDirs(destination_path):
+ try:
+ os.makedirs(destination_path)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
def GetNdkPath():
@@ -118,34 +92,12 @@
return _SDK_PATH
-def _ReadNdkRevision(properties_path):
- return _ReadProperty(properties_path, 'pkg.revision')
-
-
-def _ReadProperty(properties_path, property_key):
- with open(properties_path, 'r') as f:
- ini_str = '[properties]\n' + f.read()
- config = ConfigParser.RawConfigParser()
- config.readfp(StringIO.StringIO(ini_str))
- try:
- return config.get('properties', property_key)
- except ConfigParser.NoOptionError:
- return None
-
-
-def _GetInstalledNdkRevision():
- """Returns the installed NDK's revision."""
- path = GetNdkPath()
- properties_path = os.path.join(path, 'source.properties')
- try:
- return _ReadNdkRevision(properties_path)
- except IOError:
- logging.error("Error: Can't read NDK properties in %s", properties_path)
- sys.exit(1)
-
-
def _DownloadAndUnzipFile(url, destination_path):
- dl_file, dummy_headers = urllib.urlretrieve(url)
+ shutil.rmtree(destination_path, ignore_errors=True)
+ _MakeDirs(destination_path)
+ dl_file = os.path.join(destination_path, 'tmp.zip')
+ request = requests.get(url, allow_redirects=True)
+ open(dl_file, 'wb').write(request.content)
_UnzipFile(dl_file, destination_path)
@@ -165,49 +117,34 @@
toolchains_dir_fd = os.open(_STARBOARD_TOOLCHAINS_DIR, os.O_RDONLY)
fcntl.flock(toolchains_dir_fd, fcntl.LOCK_EX)
+ if os.environ.get('ANDROID_NDK_HOME'):
+ logging.warning('Warning: ANDROID_NDK_HOME is deprecated and ignored.')
+
if _ANDROID_HOME:
if not os.access(_SDKMANAGER_TOOL, os.X_OK):
- logging.error('Error: ANDROID_HOME is set but SDK is not present!')
+ logging.error('Error: ANDROID_HOME is set but SDK is not present.')
sys.exit(1)
logging.warning('Warning: Using Android SDK in ANDROID_HOME,'
' which is not automatically updated.\n'
' The following package versions are installed:')
installed_packages = _GetInstalledSdkPackages()
for package in _ANDROID_SDK_PACKAGES:
- version = installed_packages.get(package, '< MISSING! >')
+ version = installed_packages.get(package, '< NOT INSTALLED >')
msg = ' {:30} : {}'.format(package, version)
logging.warning(msg)
- else:
- logging.warning('Checking Android SDK.')
- _DownloadInstallOrUpdateSdk()
- ndk_path = GetNdkPath()
- if _ANDROID_NDK_HOME:
- logging.warning('Warning: ANDROID_NDK_HOME references NDK %s in %s,'
- ' which is not automatically updated.',
- _GetInstalledNdkRevision(), ndk_path)
+ if not os.path.exists(GetNdkPath()):
+ logging.error('Error: ANDROID_HOME is is missing NDK %s.',
+ _NDK_VERSION)
+ sys.exit(1)
- if _ANDROID_HOME or _ANDROID_NDK_HOME:
reply = raw_input(
'Do you want to continue using your custom Android tools? [y/N]')
if reply.upper() != 'Y':
sys.exit(1)
- elif not _CheckStamp(ndk_path):
- logging.warning('Downloading NDK from %s to %s', _NDK_URL, ndk_path)
- if os.path.exists(ndk_path):
- shutil.rmtree(ndk_path)
- # Download the NDK into _STARBOARD_TOOLCHAINS_DIR and move the top
- # _NDK_ZIP_REVISION directory that is in the zip to 'ndk-bundle'.
- ndk_unzip_path = os.path.join(_STARBOARD_TOOLCHAINS_DIR,
- _NDK_ZIP_REVISION)
- if os.path.exists(ndk_unzip_path):
- shutil.rmtree(ndk_unzip_path)
- _DownloadAndUnzipFile(_NDK_URL, _STARBOARD_TOOLCHAINS_DIR)
- # Move NDK into its proper final place.
- os.rename(ndk_unzip_path, ndk_path)
- _UpdateStamp(ndk_path)
-
- logging.warning('Using Android NDK version %s', _GetInstalledNdkRevision())
+ else:
+ logging.warning('Checking Android SDK.')
+ _DownloadInstallOrUpdateSdk()
finally:
fcntl.flock(toolchains_dir_fd, fcntl.LOCK_UN)
os.close(toolchains_dir_fd)
@@ -235,14 +172,15 @@
section_re = re.compile(r'^[A-Z][^:]*:$')
version_re = re.compile(r'^\s+Version:\s+(\S+)')
- p = subprocess.Popen(
- [_SDKMANAGER_TOOL, '--list', '--verbose'], stdout=subprocess.PIPE)
+ p = subprocess.Popen([_SDKMANAGER_TOOL, '--list', '--verbose'],
+ stdout=subprocess.PIPE)
installed_package_versions = {}
new_style = False
old_style = False
for line in iter(p.stdout.readline, ''):
-
+ # Throw away loading progress indicators up to the last CR.
+ line = line.split('\r')[-1]
if section_re.match(line):
if new_style or old_style:
# We left the new/old style installed packages section
@@ -292,6 +230,14 @@
if os.path.exists(_STARBOARD_TOOLCHAINS_SDK_DIR):
shutil.rmtree(_STARBOARD_TOOLCHAINS_SDK_DIR)
_DownloadAndUnzipFile(_SDK_URL, _STARBOARD_TOOLCHAINS_SDK_DIR)
+ # TODO: Remove this workaround for sdkmanager incorrectly picking up the
+ # "tools" directory from the ZIP as the name of its component.
+ if not os.access(_SDKMANAGER_TOOL, os.X_OK):
+ old_tools_dir = os.path.join(_STARBOARD_TOOLCHAINS_SDK_DIR, 'tools')
+ new_tools_dir = os.path.join(_STARBOARD_TOOLCHAINS_SDK_DIR,
+ 'cmdline-tools', '1.0')
+ os.mkdir(os.path.dirname(new_tools_dir))
+ os.rename(old_tools_dir, new_tools_dir)
if not os.access(_SDKMANAGER_TOOL, os.X_OK):
logging.error('SDK download failed.')
sys.exit(1)
diff --git a/src/starboard/android/shared/starboard_platform.gypi b/src/starboard/android/shared/starboard_platform.gypi
index 2401618..365ced9 100644
--- a/src/starboard/android/shared/starboard_platform.gypi
+++ b/src/starboard/android/shared/starboard_platform.gypi
@@ -404,9 +404,9 @@
'<(DEPTH)/starboard/shared/starboard/player/player_get_info.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_get_info2.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_get_maximum_number_of_samples_per_write.cc',
+ '<(DEPTH)/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
- '<(DEPTH)/starboard/shared/starboard/player/player_output_mode_supported.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_seek.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_seek2.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_set_volume.cc',
diff --git a/src/starboard/android/shared/window_on_screen_keyboard_suggestions_supported.cc b/src/starboard/android/shared/window_on_screen_keyboard_suggestions_supported.cc
index 992e15e..ffd2d59 100644
--- a/src/starboard/android/shared/window_on_screen_keyboard_suggestions_supported.cc
+++ b/src/starboard/android/shared/window_on_screen_keyboard_suggestions_supported.cc
@@ -15,9 +15,7 @@
#include "starboard/window.h"
#if SB_HAS(ON_SCREEN_KEYBOARD)
-#if SB_API_VERSION >= 11
bool SbWindowOnScreenKeyboardSuggestionsSupported(SbWindow window) {
return true;
}
-#endif // SB_API_VERSION >= 11
#endif // SB_HAS(ON_SCREEN_KEYBOARD)
diff --git a/src/starboard/android/shared/window_update_on_screen_keyboard_suggestions.cc b/src/starboard/android/shared/window_update_on_screen_keyboard_suggestions.cc
index 24f0925..f3e75c2 100644
--- a/src/starboard/android/shared/window_update_on_screen_keyboard_suggestions.cc
+++ b/src/starboard/android/shared/window_update_on_screen_keyboard_suggestions.cc
@@ -17,7 +17,6 @@
#include "starboard/android/shared/application_android.h"
#if SB_HAS(ON_SCREEN_KEYBOARD)
-#if SB_API_VERSION >= 11
void SbWindowUpdateOnScreenKeyboardSuggestions(SbWindow window,
const char* suggestions[],
int num_suggestions,
@@ -31,5 +30,4 @@
ticket);
return;
}
-#endif // SB_API_VERSION >= 11
#endif // SB_HAS(ON_SCREEN_KEYBOARD)
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h
index e06b52e..a49c22b 100644
--- a/src/starboard/configuration.h
+++ b/src/starboard/configuration.h
@@ -644,6 +644,15 @@
#define SB_HAS_AC3_AUDIO 1
#endif // defined(SB_HAS_AC3_AUDIO)
#endif // SB_API_VERSION >= 11
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+#if SB_API_VERSION < 11
+#error \
+ "SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT) requires " \
+ "SB_API_VERSION 11 or later."
+#endif // SB_API_VERSION < 11
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
// --- Derived Configuration -------------------------------------------------
// Whether the current platform is little endian.
diff --git a/src/starboard/linux/shared/BUILD.gn b/src/starboard/linux/shared/BUILD.gn
index 8fa8add..bd55f1e 100644
--- a/src/starboard/linux/shared/BUILD.gn
+++ b/src/starboard/linux/shared/BUILD.gn
@@ -533,9 +533,9 @@
"//starboard/shared/starboard/player/player_destroy.cc",
"//starboard/shared/starboard/player/player_get_current_frame.cc",
"//starboard/shared/starboard/player/player_get_info.cc",
+ "//starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc",
"//starboard/shared/starboard/player/player_internal.cc",
"//starboard/shared/starboard/player/player_internal.h",
- "//starboard/shared/starboard/player/player_output_mode_supported.cc",
"//starboard/shared/starboard/player/player_seek.cc",
"//starboard/shared/starboard/player/player_set_bounds.cc",
"//starboard/shared/starboard/player/player_set_playback_rate.cc",
diff --git a/src/starboard/linux/shared/starboard_platform.gypi b/src/starboard/linux/shared/starboard_platform.gypi
index 1297986..ea9844d 100644
--- a/src/starboard/linux/shared/starboard_platform.gypi
+++ b/src/starboard/linux/shared/starboard_platform.gypi
@@ -196,6 +196,7 @@
'<(DEPTH)/starboard/shared/pthread/mutex_release.cc',
'<(DEPTH)/starboard/shared/pthread/once.cc',
'<(DEPTH)/starboard/shared/pthread/thread_context_get_pointer.cc',
+ '<(DEPTH)/starboard/shared/pthread/thread_context_internal.cc',
'<(DEPTH)/starboard/shared/pthread/thread_context_internal.h',
'<(DEPTH)/starboard/shared/pthread/thread_create.cc',
'<(DEPTH)/starboard/shared/pthread/thread_create_local_key.cc',
@@ -290,6 +291,7 @@
'<(DEPTH)/starboard/shared/starboard/player/player_get_info.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_get_info2.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_get_maximum_number_of_samples_per_write.cc',
+ '<(DEPTH)/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
'<(DEPTH)/starboard/shared/starboard/player/player_output_mode_supported.cc',
diff --git a/src/starboard/nplb/drm_create_system_test.cc b/src/starboard/nplb/drm_create_system_test.cc
index 0b68275..9cd4b7a 100644
--- a/src/starboard/nplb/drm_create_system_test.cc
+++ b/src/starboard/nplb/drm_create_system_test.cc
@@ -44,7 +44,6 @@
TEST(SbDrmTest, NullCallbacks) {
for (int i = 0; i < SB_ARRAY_SIZE_INT(kKeySystems); ++i) {
const char* key_system = kKeySystems[i];
-#if SB_API_VERSION >= 10
{
SbDrmSystem drm_system = SbDrmCreateSystem(
key_system, NULL /* context */,
@@ -86,69 +85,9 @@
EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
SbDrmDestroySystem(drm_system);
}
-#elif SB_HAS(DRM_SESSION_CLOSED)
- {
- SbDrmSystem drm_system = SbDrmCreateSystem(
- key_system, NULL /* context */,
- NULL /* session_update_request_func */, DummySessionUpdatedFunc,
- DummySessionKeyStatusesChangedFunc, DummySessionClosedFunc);
- EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
- SbDrmDestroySystem(drm_system);
- }
- {
- SbDrmSystem drm_system = SbDrmCreateSystem(
- key_system, NULL /* context */, DummySessionUpdateRequestFunc,
- NULL /*session_updated_func */, DummySessionKeyStatusesChangedFunc,
- DummySessionClosedFunc);
- EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
- SbDrmDestroySystem(drm_system);
- }
- {
- SbDrmSystem drm_system = SbDrmCreateSystem(
- key_system, NULL /* context */, DummySessionUpdateRequestFunc,
- DummySessionUpdatedFunc, NULL /* session_key_statuses_changed_func */,
- DummySessionClosedFunc);
- EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
- SbDrmDestroySystem(drm_system);
- }
- {
- SbDrmSystem drm_system = SbDrmCreateSystem(
- key_system, NULL /* context */, DummySessionUpdateRequestFunc,
- DummySessionUpdatedFunc, DummySessionKeyStatusesChangedFunc,
- NULL /* session_closed_func */);
- EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
- SbDrmDestroySystem(drm_system);
- }
-#else // SB_HAS(DRM_SESSION_CLOSED)
- {
- SbDrmSystem drm_system = SbDrmCreateSystem(
- key_system, NULL /* context */,
- NULL /* session_update_request_func */, DummySessionUpdatedFunc,
- DummySessionKeyStatusesChangedFunc);
- EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
- SbDrmDestroySystem(drm_system);
- }
- {
- SbDrmSystem drm_system = SbDrmCreateSystem(
- key_system, NULL /* context */, DummySessionUpdateRequestFunc,
- NULL /* session_updated_func */, DummySessionKeyStatusesChangedFunc);
- EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
- SbDrmDestroySystem(drm_system);
- }
- {
- SbDrmSystem drm_system = SbDrmCreateSystem(
- key_system, NULL /* context */, DummySessionUpdateRequestFunc,
- DummySessionUpdatedFunc,
- NULL /* session_key_statuses_changed_func */);
- EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
- SbDrmDestroySystem(drm_system);
- }
-#endif // SB_HAS(DRM_SESSION_CLOSED)
}
}
-#endif // SB_API_VERSION >= 10
-#if SB_API_VERSION >= 10
TEST(SbDrmTest, MultiDrm) {
const int kMaxPlayersPerKeySystem = 16;
std::vector<SbDrmSystem> created_drm_systems;
diff --git a/src/starboard/nplb/media_can_play_mime_and_key_system_test.cc b/src/starboard/nplb/media_can_play_mime_and_key_system_test.cc
new file mode 100644
index 0000000..2e38c86
--- /dev/null
+++ b/src/starboard/nplb/media_can_play_mime_and_key_system_test.cc
@@ -0,0 +1,102 @@
+// Copyright 2020 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/media.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace media {
+namespace {
+
+TEST(SbMediaCanPlayMimeAndKeySystem, SunnyDay) {
+ // Vp9
+ SbMediaCanPlayMimeAndKeySystem(
+ "video/webm; codecs=\"vp9\"; width=3840; height=2160; framerate=30; "
+ "bitrate=21823784; eotf=bt709",
+ "");
+ // Avc
+ SbMediaSupportType result = SbMediaCanPlayMimeAndKeySystem(
+ "video/mp4; codecs=\"avc1.4d4015\"; width=640; "
+ "height=360; framerate=30;",
+ "");
+ ASSERT_EQ(result, kSbMediaSupportTypeProbably);
+ // Hdr bt709
+ SbMediaCanPlayMimeAndKeySystem(
+ "video/webm; codecs=\"vp09.02.10.10\";eotf=bt709;width=640;height=360",
+ "");
+ // Aac
+ result = SbMediaCanPlayMimeAndKeySystem(
+ "audio/mp4; codecs=\"mp4a.40.2\"; channels=2", "");
+ ASSERT_EQ(result, kSbMediaSupportTypeProbably);
+ // Opus
+ SbMediaCanPlayMimeAndKeySystem("audio/webm; codecs=\"opus\"; channels=2", "");
+}
+
+TEST(SbMediaCanPlayMimeAndKeySystem, Invalid) {
+ // Invalid codec
+ SbMediaSupportType result =
+ SbMediaCanPlayMimeAndKeySystem("video/webm; codecs=\"abc\";", "");
+ ASSERT_EQ(result, kSbMediaSupportTypeNotSupported);
+
+ result = SbMediaCanPlayMimeAndKeySystem(
+ "video/webm; codecs=\"vp09.00.01.00.22\";", "");
+ ASSERT_EQ(result, kSbMediaSupportTypeNotSupported);
+
+ // Invalid container
+ result =
+ SbMediaCanPlayMimeAndKeySystem("video/abc; codecs=\"avc1.4d4015\";", "");
+ ASSERT_EQ(result, kSbMediaSupportTypeNotSupported);
+
+ // Invalid size
+ result = SbMediaCanPlayMimeAndKeySystem(
+ "video/mp4; codecs=\"avc1.4d4015\"; width=99999; height=1080;", "");
+ ASSERT_EQ(result, kSbMediaSupportTypeNotSupported);
+
+ result = SbMediaCanPlayMimeAndKeySystem(
+ "video/mp4; codecs=\"avc1.4d4015\"; width=1920; height=99999;", "");
+ ASSERT_EQ(result, kSbMediaSupportTypeNotSupported);
+
+ // Invalid bitrate
+ result = SbMediaCanPlayMimeAndKeySystem(
+ "video/mp4; codecs=\"avc1.4d4015\"; width=1920; height=1080; "
+ "bitrate=999999999;",
+ "");
+ ASSERT_EQ(result, kSbMediaSupportTypeNotSupported);
+
+ // Invalid eotf
+ result = SbMediaCanPlayMimeAndKeySystem(
+ "video/webm; codecs=\"vp09.02.10.10\"; width=1920; height=1080; "
+ "eotf=abc",
+ "");
+ ASSERT_EQ(result, kSbMediaSupportTypeNotSupported);
+
+ // Invalid channels
+ result = SbMediaCanPlayMimeAndKeySystem(
+ "audio/mp4; codecs=\"mp4a.40.2\"; channels=99", "");
+ ASSERT_EQ(result, kSbMediaSupportTypeNotSupported);
+
+ // Invalid keysystem
+ result = SbMediaCanPlayMimeAndKeySystem(
+ "video/mp4; codecs=\"avc1.4d4015\"; width=1920; height=1080;", "abc");
+ ASSERT_EQ(result, kSbMediaSupportTypeNotSupported);
+}
+
+} // namespace
+} // namespace media
+} // namespace starboard
+} // namespace shared
+} // namespace starboard
diff --git a/src/starboard/nplb/media_set_audio_write_duration_test.cc b/src/starboard/nplb/media_set_audio_write_duration_test.cc
index 0ca9a37..39fecb0 100644
--- a/src/starboard/nplb/media_set_audio_write_duration_test.cc
+++ b/src/starboard/nplb/media_set_audio_write_duration_test.cc
@@ -16,6 +16,7 @@
#include "starboard/common/optional.h"
#include "starboard/common/spin_lock.h"
+#include "starboard/nplb/player_creation_param_helpers.h"
#include "starboard/player.h"
#include "starboard/shared/starboard/media/media_support_internal.h"
#include "starboard/shared/starboard/player/video_dmp_reader.h"
@@ -98,10 +99,8 @@
sample_info.buffer_size = player_sample_info.buffer_size;
sample_info.timestamp = player_sample_info.timestamp;
sample_info.drm_info = NULL;
-#if SB_API_VERSION >= 11
sample_info.type = kSbMediaTypeAudio;
sample_info.audio_sample_info = dmp_reader_.audio_sample_info();
-#endif // SB_API_VERSION >= 11
SbPlayer player = pending_decoder_status_->player;
SbMediaType type = pending_decoder_status_->type;
@@ -136,25 +135,40 @@
SbMediaAudioCodec kAudioCodec = dmp_reader_.audio_codec();
SbDrmSystem kDrmSystem = kSbDrmSystemInvalid;
+ last_input_timestamp_ =
+ dmp_reader_.GetPlayerSampleInfo(kSbMediaTypeAudio, 0).timestamp;
+ first_input_timestamp_ = last_input_timestamp_;
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+ SbPlayerCreationParam creation_param = CreatePlayerCreationParam(
+ audio_sample_info.codec, kSbMediaVideoCodecNone);
+ creation_param.audio_sample_info = audio_sample_info;
+ creation_param.output_mode =
+ SbPlayerGetPreferredOutputMode(&creation_param);
+ EXPECT_NE(creation_param.output_mode, kSbPlayerOutputModeInvalid);
+
+ SbPlayer player = SbPlayerCreate(
+ fake_graphics_context_provider_.window(), &creation_param,
+ DummyDeallocateSampleFunc, DecoderStatusFunc, PlayerStatusFunc,
+ DummyErrorFunc, this /* context */,
+ fake_graphics_context_provider_.decoder_target_provider());
+#else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
SbPlayerOutputMode output_mode = kSbPlayerOutputModeDecodeToTexture;
+
if (!SbPlayerOutputModeSupported(output_mode, kSbMediaVideoCodecNone,
kSbDrmSystemInvalid)) {
output_mode = kSbPlayerOutputModePunchOut;
}
- last_input_timestamp_ =
- dmp_reader_.GetPlayerSampleInfo(kSbMediaTypeAudio, 0).timestamp;
- first_input_timestamp_ = last_input_timestamp_;
-
SbPlayer player = SbPlayerCreate(
fake_graphics_context_provider_.window(), kSbMediaVideoCodecNone,
kAudioCodec, kSbDrmSystemInvalid, &audio_sample_info,
-#if SB_API_VERSION >= 11
NULL /* max_video_capabilities */,
-#endif // SB_API_VERSION >= 11
DummyDeallocateSampleFunc, DecoderStatusFunc, PlayerStatusFunc,
DummyErrorFunc, this /* context */, output_mode,
fake_graphics_context_provider_.decoder_target_provider());
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
EXPECT_TRUE(SbPlayerIsValid(player));
return player;
}
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp
index 9043651..7dae228 100644
--- a/src/starboard/nplb/nplb.gyp
+++ b/src/starboard/nplb/nplb.gyp
@@ -151,7 +151,7 @@
# TODO: Separate functions tested by media buffer test into multiple
# files.
'media_buffer_test.cc',
- 'media_set_audio_write_duration_test.cc',
+ 'media_can_play_mime_and_key_system_test.cc',
'memory_align_to_page_size_test.cc',
'memory_allocate_aligned_test.cc',
'memory_allocate_test.cc',
@@ -181,6 +181,9 @@
'once_test.cc',
'optional_test.cc',
'player_create_test.cc',
+ 'player_creation_param_helpers.cc',
+ 'player_creation_param_helpers.h',
+ 'player_get_preferred_output_mode_test.cc',
'player_output_mode_supported_test.cc',
'random_helpers.cc',
'recursive_mutex_test.cc',
diff --git a/src/starboard/nplb/player_create_test.cc b/src/starboard/nplb/player_create_test.cc
index 0aa6b0e..a3f4efc 100644
--- a/src/starboard/nplb/player_create_test.cc
+++ b/src/starboard/nplb/player_create_test.cc
@@ -16,6 +16,7 @@
#include "starboard/blitter.h"
#include "starboard/decode_target.h"
+#include "starboard/nplb/player_creation_param_helpers.h"
#include "starboard/player.h"
#include "starboard/testing/fake_graphics_context_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -53,56 +54,92 @@
const char* message) {}
#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
-SbMediaAudioSampleInfo GetDefaultAudioSampleInfo() {
- SbMediaAudioSampleInfo audio_sample_info;
+SbPlayer CallSbPlayerCreate(
+ SbWindow window,
+ SbMediaVideoCodec video_codec,
+ SbMediaAudioCodec audio_codec,
+ SbDrmSystem drm_system,
+ const SbMediaAudioSampleInfo* audio_sample_info,
+ const char* max_video_capabilities,
+ SbPlayerDeallocateSampleFunc sample_deallocate_func,
+ SbPlayerDecoderStatusFunc decoder_status_func,
+ SbPlayerStatusFunc player_status_func,
+ void* context,
+ SbPlayerOutputMode output_mode,
+ SbDecodeTargetGraphicsContextProvider* context_provider) {
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+ if (audio_sample_info) {
+ SB_CHECK(audio_sample_info->codec == audio_codec);
+ } else {
+ SB_CHECK(audio_codec == kSbMediaAudioCodecNone);
+ }
+
+ SbPlayerCreationParam creation_param =
+ CreatePlayerCreationParam(audio_codec, video_codec);
+ if (audio_sample_info) {
+ creation_param.audio_sample_info = *audio_sample_info;
+ }
+ creation_param.drm_system = drm_system;
+ creation_param.output_mode = output_mode;
+ creation_param.max_video_capabilities = max_video_capabilities;
+
+ return SbPlayerCreate(window, &creation_param, sample_deallocate_func,
+ decoder_status_func, player_status_func, DummyErrorFunc,
+ context, context_provider);
+
+#else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+ return SbPlayerCreate(window, video_codec, audio_codec,
+#if SB_API_VERSION < 10
+ SB_PLAYER_NO_DURATION,
+#endif // SB_API_VERSION < 10
+ kSbDrmSystemInvalid, audio_sample_info,
#if SB_API_VERSION >= 11
- audio_sample_info.codec = kSbMediaAudioCodecAac;
+ max_video_capabilities,
#endif // SB_API_VERSION >= 11
- audio_sample_info.format_tag = 0xff;
- audio_sample_info.number_of_channels = 2;
- audio_sample_info.samples_per_second = 22050;
- audio_sample_info.block_alignment = 4;
- audio_sample_info.bits_per_sample = 32;
- audio_sample_info.audio_specific_config_size = 0;
- audio_sample_info.average_bytes_per_second =
- audio_sample_info.samples_per_second *
- audio_sample_info.number_of_channels * audio_sample_info.bits_per_sample /
- 8;
+ sample_deallocate_func, decoder_status_func,
+ player_status_func,
+#if SB_HAS(PLAYER_ERROR_MESSAGE)
+ DummyErrorFunc,
+#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
+ context, output_mode, context_provider);
- return audio_sample_info;
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+}
+
+bool IsOutputModeSupported(SbPlayerOutputMode output_mode,
+ SbMediaVideoCodec codec) {
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+ SbPlayerCreationParam creation_param =
+ CreatePlayerCreationParam(kSbMediaAudioCodecNone, codec);
+ creation_param.output_mode = output_mode;
+ return SbPlayerGetPreferredOutputMode(&creation_param) == output_mode;
+#else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+ return SbPlayerOutputModeSupported(output_mode, codec, kSbDrmSystemInvalid);
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
}
TEST_F(SbPlayerTest, SunnyDay) {
- SbMediaAudioSampleInfo audio_sample_info = GetDefaultAudioSampleInfo();
+ SbMediaAudioSampleInfo audio_sample_info =
+ CreateAudioSampleInfo(kSbMediaAudioCodecAac);
SbMediaVideoCodec kVideoCodec = kSbMediaVideoCodecH264;
- SbDrmSystem kDrmSystem = kSbDrmSystemInvalid;
SbPlayerOutputMode output_modes[] = {kSbPlayerOutputModeDecodeToTexture,
kSbPlayerOutputModePunchOut};
for (int i = 0; i < SB_ARRAY_SIZE_INT(output_modes); ++i) {
SbPlayerOutputMode output_mode = output_modes[i];
- if (!SbPlayerOutputModeSupported(output_mode, kVideoCodec, kDrmSystem)) {
+
+ if (!IsOutputModeSupported(output_mode, kVideoCodec)) {
continue;
}
-
- SbPlayer player = SbPlayerCreate(
+ SbPlayer player = CallSbPlayerCreate(
fake_graphics_context_provider_.window(), kSbMediaVideoCodecH264,
- kSbMediaAudioCodecAac,
-#if SB_API_VERSION < 10
- SB_PLAYER_NO_DURATION,
-#endif // SB_API_VERSION < 10
- kSbDrmSystemInvalid, &audio_sample_info,
-#if SB_API_VERSION >= 11
- NULL /* max_video_capabilities */,
-#endif // SB_API_VERSION >= 11
- DummyDeallocateSampleFunc, DummyDecoderStatusFunc, DummyStatusFunc,
-#if SB_HAS(PLAYER_ERROR_MESSAGE)
- DummyErrorFunc,
-#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
- NULL /* context */, output_mode,
- fake_graphics_context_provider_.decoder_target_provider());
+ kSbMediaAudioCodecAac, kSbDrmSystemInvalid, &audio_sample_info,
+ "" /* max_video_capabilities */, DummyDeallocateSampleFunc,
+ DummyDecoderStatusFunc, DummyStatusFunc, NULL /* context */,
+ output_mode, fake_graphics_context_provider_.decoder_target_provider());
EXPECT_TRUE(SbPlayerIsValid(player));
if (output_mode == kSbPlayerOutputModeDecodeToTexture) {
@@ -115,36 +152,26 @@
#if SB_API_VERSION >= 10
TEST_F(SbPlayerTest, NullCallbacks) {
- SbMediaAudioSampleInfo audio_sample_info = GetDefaultAudioSampleInfo();
+ SbMediaAudioSampleInfo audio_sample_info =
+ CreateAudioSampleInfo(kSbMediaAudioCodecAac);
SbMediaVideoCodec kVideoCodec = kSbMediaVideoCodecH264;
- SbDrmSystem kDrmSystem = kSbDrmSystemInvalid;
SbPlayerOutputMode output_modes[] = {kSbPlayerOutputModeDecodeToTexture,
kSbPlayerOutputModePunchOut};
for (int i = 0; i < SB_ARRAY_SIZE_INT(output_modes); ++i) {
SbPlayerOutputMode output_mode = output_modes[i];
- if (!SbPlayerOutputModeSupported(output_mode, kVideoCodec, kDrmSystem)) {
+ if (!IsOutputModeSupported(output_mode, kVideoCodec)) {
continue;
}
{
- SbPlayer player = SbPlayerCreate(
+ SbPlayer player = CallSbPlayerCreate(
fake_graphics_context_provider_.window(), kSbMediaVideoCodecH264,
- kSbMediaAudioCodecAac,
-#if SB_API_VERSION < 10
- SB_PLAYER_NO_DURATION,
-#endif // SB_API_VERSION < 10
- kSbDrmSystemInvalid, &audio_sample_info,
-#if SB_API_VERSION >= 11
- NULL /* max_video_capabilities */,
-#endif // SB_API_VERSION >= 11
- NULL /* deallocate_sample_func */, DummyDecoderStatusFunc,
- DummyStatusFunc,
-#if SB_HAS(PLAYER_ERROR_MESSAGE)
- DummyErrorFunc,
-#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
- NULL /* context */, output_mode,
+ kSbMediaAudioCodecAac, kSbDrmSystemInvalid, &audio_sample_info,
+ "" /* max_video_capabilities */, NULL /* deallocate_sample_func */,
+ DummyDecoderStatusFunc, DummyStatusFunc, NULL /* context */,
+ output_mode,
fake_graphics_context_provider_.decoder_target_provider());
EXPECT_FALSE(SbPlayerIsValid(player));
@@ -152,22 +179,12 @@
}
{
- SbPlayer player = SbPlayerCreate(
+ SbPlayer player = CallSbPlayerCreate(
fake_graphics_context_provider_.window(), kSbMediaVideoCodecH264,
- kSbMediaAudioCodecAac,
-#if SB_API_VERSION < 10
- SB_PLAYER_NO_DURATION,
-#endif // SB_API_VERSION < 10
- kSbDrmSystemInvalid, &audio_sample_info,
-#if SB_API_VERSION >= 11
- NULL /* max_video_capabilities */,
-#endif // SB_API_VERSION >= 11
- DummyDeallocateSampleFunc, NULL /* decoder_status_func */,
- DummyStatusFunc,
-#if SB_HAS(PLAYER_ERROR_MESSAGE)
- DummyErrorFunc,
-#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
- NULL /* context */, output_mode,
+ kSbMediaAudioCodecAac, kSbDrmSystemInvalid, &audio_sample_info,
+ "" /* max_video_capabilities */, DummyDeallocateSampleFunc,
+ NULL /* decoder_status_func */, DummyStatusFunc, NULL /* context */,
+ output_mode,
fake_graphics_context_provider_.decoder_target_provider());
EXPECT_FALSE(SbPlayerIsValid(player));
@@ -175,22 +192,12 @@
}
{
- SbPlayer player = SbPlayerCreate(
+ SbPlayer player = CallSbPlayerCreate(
fake_graphics_context_provider_.window(), kSbMediaVideoCodecH264,
- kSbMediaAudioCodecAac,
-#if SB_API_VERSION < 10
- SB_PLAYER_NO_DURATION,
-#endif // SB_API_VERSION < 10
- kSbDrmSystemInvalid, &audio_sample_info,
-#if SB_API_VERSION >= 11
- NULL /* max_video_capabilities */,
-#endif // SB_API_VERSION >= 11
- DummyDeallocateSampleFunc, DummyDecoderStatusFunc,
- NULL /*status_func */,
-#if SB_HAS(PLAYER_ERROR_MESSAGE)
- DummyErrorFunc,
-#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
- NULL /* context */, output_mode,
+ kSbMediaAudioCodecAac, kSbDrmSystemInvalid, &audio_sample_info,
+ "" /* max_video_capabilities */, DummyDeallocateSampleFunc,
+ DummyDecoderStatusFunc, NULL /*status_func */, NULL /* context */,
+ output_mode,
fake_graphics_context_provider_.decoder_target_provider());
EXPECT_FALSE(SbPlayerIsValid(player));
@@ -198,13 +205,29 @@
}
#if SB_HAS(PLAYER_ERROR_MESSAGE)
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+ {
+ SbPlayerCreationParam creation_param = CreatePlayerCreationParam(
+ kSbMediaAudioCodecAac, kSbMediaVideoCodecH264);
+
+ SbPlayer player = SbPlayerCreate(
+ fake_graphics_context_provider_.window(), &creation_param,
+ DummyDeallocateSampleFunc, DummyDecoderStatusFunc, DummyStatusFunc,
+ NULL /* error_func */, NULL /* context */,
+ fake_graphics_context_provider_.decoder_target_provider());
+ EXPECT_FALSE(SbPlayerIsValid(player));
+
+ SbPlayerDestroy(player);
+ }
+
+#else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
{
SbPlayer player = SbPlayerCreate(
fake_graphics_context_provider_.window(), kSbMediaVideoCodecH264,
kSbMediaAudioCodecAac,
-#if SB_API_VERSION < 10
- SB_PLAYER_NO_DURATION,
-#endif // SB_API_VERSION < 10
kSbDrmSystemInvalid, &audio_sample_info,
#if SB_API_VERSION >= 11
NULL /* max_video_capabilities */,
@@ -216,6 +239,9 @@
SbPlayerDestroy(player);
}
+
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
}
}
@@ -224,31 +250,21 @@
#if SB_HAS(AUDIOLESS_VIDEO)
TEST_F(SbPlayerTest, Audioless) {
SbMediaVideoCodec kVideoCodec = kSbMediaVideoCodecH264;
- SbDrmSystem kDrmSystem = kSbDrmSystemInvalid;
SbPlayerOutputMode output_modes[] = {kSbPlayerOutputModeDecodeToTexture,
kSbPlayerOutputModePunchOut};
for (int i = 0; i < SB_ARRAY_SIZE_INT(output_modes); ++i) {
SbPlayerOutputMode output_mode = output_modes[i];
- if (!SbPlayerOutputModeSupported(output_mode, kVideoCodec, kDrmSystem)) {
+ if (!IsOutputModeSupported(output_mode, kVideoCodec)) {
continue;
}
- SbPlayer player = SbPlayerCreate(
+ SbPlayer player = CallSbPlayerCreate(
fake_graphics_context_provider_.window(), kVideoCodec,
- kSbMediaAudioCodecNone,
-#if SB_API_VERSION < 10
- SB_PLAYER_NO_DURATION,
-#endif // SB_API_VERSION < 10
- kSbDrmSystemInvalid, NULL /* audio_sample_info */,
-#if SB_API_VERSION >= 11
- NULL /* max_video_capabilities */,
-#endif // SB_API_VERSION >= 11
+ kSbMediaAudioCodecNone, kSbDrmSystemInvalid,
+ NULL /* audio_sample_info */, "" /* max_video_capabilities */,
DummyDeallocateSampleFunc, DummyDecoderStatusFunc, DummyStatusFunc,
-#if SB_HAS(PLAYER_ERROR_MESSAGE)
- DummyErrorFunc,
-#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
NULL /* context */, output_mode,
fake_graphics_context_provider_.decoder_target_provider());
EXPECT_TRUE(SbPlayerIsValid(player));
@@ -264,36 +280,26 @@
#if SB_API_VERSION >= 10
TEST_F(SbPlayerTest, AudioOnly) {
- SbMediaAudioSampleInfo audio_sample_info = GetDefaultAudioSampleInfo();
+ SbMediaAudioSampleInfo audio_sample_info =
+ CreateAudioSampleInfo(kSbMediaAudioCodecAac);
SbMediaAudioCodec kAudioCodec = kSbMediaAudioCodecAac;
SbMediaVideoCodec kVideoCodec = kSbMediaVideoCodecH264;
- SbDrmSystem kDrmSystem = kSbDrmSystemInvalid;
SbPlayerOutputMode output_modes[] = {kSbPlayerOutputModeDecodeToTexture,
kSbPlayerOutputModePunchOut};
for (int i = 0; i < SB_ARRAY_SIZE_INT(output_modes); ++i) {
SbPlayerOutputMode output_mode = output_modes[i];
- if (!SbPlayerOutputModeSupported(output_mode, kVideoCodec, kDrmSystem)) {
+ if (!IsOutputModeSupported(output_mode, kVideoCodec)) {
continue;
}
- SbPlayer player = SbPlayerCreate(
+ SbPlayer player = CallSbPlayerCreate(
fake_graphics_context_provider_.window(), kSbMediaVideoCodecNone,
- kAudioCodec,
-#if SB_API_VERSION < 10
- SB_PLAYER_NO_DURATION,
-#endif // SB_API_VERSION < 10
- kSbDrmSystemInvalid, &audio_sample_info,
-#if SB_API_VERSION >= 11
- NULL /* max_video_capabilities */,
-#endif // SB_API_VERSION >= 11
- DummyDeallocateSampleFunc, DummyDecoderStatusFunc, DummyStatusFunc,
-#if SB_HAS(PLAYER_ERROR_MESSAGE)
- DummyErrorFunc,
-#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
- NULL /* context */, output_mode,
- fake_graphics_context_provider_.decoder_target_provider());
+ kAudioCodec, kSbDrmSystemInvalid, &audio_sample_info,
+ "" /* max_video_capabilities */, DummyDeallocateSampleFunc,
+ DummyDecoderStatusFunc, DummyStatusFunc, NULL /* context */,
+ output_mode, fake_graphics_context_provider_.decoder_target_provider());
EXPECT_TRUE(SbPlayerIsValid(player));
if (output_mode == kSbPlayerOutputModeDecodeToTexture) {
@@ -303,11 +309,10 @@
SbPlayerDestroy(player);
}
}
-#endif // SB_API_VERSION >= 10
-#if SB_API_VERSION >= 10
TEST_F(SbPlayerTest, MultiPlayer) {
- SbMediaAudioSampleInfo audio_sample_info = GetDefaultAudioSampleInfo();
+ SbMediaAudioSampleInfo audio_sample_info =
+ CreateAudioSampleInfo(kSbMediaAudioCodecAac);
SbDrmSystem kDrmSystem = kSbDrmSystemInvalid;
constexpr SbPlayerOutputMode kOutputModes[] = {
@@ -387,14 +392,11 @@
#if SB_API_VERSION >= 11
audio_sample_info.codec = kAudioCodecs[k];
#endif // SB_API_VERSION >= 11
- created_players.push_back(SbPlayerCreate(
+ created_players.push_back(CallSbPlayerCreate(
fake_graphics_context_provider_.window(), kVideoCodecs[l],
kAudioCodecs[k], kSbDrmSystemInvalid, &audio_sample_info,
-#if SB_API_VERSION >= 11
- NULL /* max_video_capabilities */,
-#endif // SB_API_VERSION >= 11
- DummyDeallocateSampleFunc, DummyDecoderStatusFunc,
- DummyStatusFunc, DummyErrorFunc, NULL /* context */,
+ "" /* max_video_capabilities */, DummyDeallocateSampleFunc,
+ DummyDecoderStatusFunc, DummyStatusFunc, NULL /* context */,
kOutputModes[j],
fake_graphics_context_provider_.decoder_target_provider()));
if (!SbPlayerIsValid(created_players.back())) {
diff --git a/src/starboard/nplb/player_creation_param_helpers.cc b/src/starboard/nplb/player_creation_param_helpers.cc
new file mode 100644
index 0000000..62009ff
--- /dev/null
+++ b/src/starboard/nplb/player_creation_param_helpers.cc
@@ -0,0 +1,149 @@
+// Copyright 2020 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/nplb/player_creation_param_helpers.h"
+
+#include "starboard/common/log.h"
+
+namespace starboard {
+namespace nplb {
+
+SbMediaAudioSampleInfo CreateAudioSampleInfo(SbMediaAudioCodec codec) {
+ SbMediaAudioSampleInfo audio_sample_info = {};
+
+#if SB_API_VERSION >= 11
+ audio_sample_info.codec = codec;
+#endif // SB_API_VERSION >= 11
+
+ switch (codec) {
+ case kSbMediaAudioCodecNone:
+ break;
+ case kSbMediaAudioCodecAac: {
+ static const uint8_t kAacAudioSpecificConfig[16] = {18, 16};
+
+ audio_sample_info.format_tag = 0xff;
+ audio_sample_info.number_of_channels = 2;
+ audio_sample_info.samples_per_second = 44100;
+ audio_sample_info.block_alignment = 4;
+ audio_sample_info.bits_per_sample = 16;
+ audio_sample_info.audio_specific_config = kAacAudioSpecificConfig;
+ audio_sample_info.audio_specific_config_size =
+ sizeof(kAacAudioSpecificConfig);
+ audio_sample_info.average_bytes_per_second =
+ audio_sample_info.samples_per_second *
+ audio_sample_info.number_of_channels *
+ audio_sample_info.bits_per_sample / 8;
+ break;
+ }
+ case kSbMediaAudioCodecAc3:
+ case kSbMediaAudioCodecEac3: {
+ audio_sample_info.format_tag = 0xff;
+ audio_sample_info.number_of_channels = 6;
+ audio_sample_info.samples_per_second = 48000;
+ audio_sample_info.block_alignment = 4;
+ audio_sample_info.bits_per_sample = 16;
+ audio_sample_info.audio_specific_config = nullptr;
+ audio_sample_info.audio_specific_config_size = 0;
+ audio_sample_info.average_bytes_per_second =
+ audio_sample_info.samples_per_second *
+ audio_sample_info.number_of_channels *
+ audio_sample_info.bits_per_sample / 8;
+ break;
+ }
+ case kSbMediaAudioCodecOpus: {
+ static const uint8_t kOpusAudioSpecificConfig[19] = {
+ 79, 112, 117, 115, 72, 101, 97, 100, 1, 2, 56, 1, 128, 187};
+
+ audio_sample_info.format_tag = 0xff;
+ audio_sample_info.number_of_channels = 2;
+ audio_sample_info.samples_per_second = 48000;
+ audio_sample_info.block_alignment = 4;
+ audio_sample_info.bits_per_sample = 32;
+ audio_sample_info.audio_specific_config = kOpusAudioSpecificConfig;
+ audio_sample_info.audio_specific_config_size =
+ sizeof(kOpusAudioSpecificConfig);
+ audio_sample_info.average_bytes_per_second =
+ audio_sample_info.samples_per_second *
+ audio_sample_info.number_of_channels *
+ audio_sample_info.bits_per_sample / 8;
+ break;
+ }
+ case kSbMediaAudioCodecVorbis: {
+ // Note that unlike the configuration of the other formats, the following
+ // configuration is made up, instead of taking from a real input.
+ audio_sample_info.format_tag = 0xff;
+ audio_sample_info.number_of_channels = 2;
+ audio_sample_info.samples_per_second = 48000;
+ audio_sample_info.block_alignment = 4;
+ audio_sample_info.bits_per_sample = 16;
+ audio_sample_info.audio_specific_config = nullptr;
+ audio_sample_info.audio_specific_config_size = 0;
+ audio_sample_info.average_bytes_per_second =
+ audio_sample_info.samples_per_second *
+ audio_sample_info.number_of_channels *
+ audio_sample_info.bits_per_sample / 8;
+ break;
+ }
+ }
+ return audio_sample_info;
+}
+
+SbMediaVideoSampleInfo CreateVideoSampleInfo(SbMediaVideoCodec codec) {
+ SbMediaVideoSampleInfo video_sample_info = {};
+
+#if SB_API_VERSION >= 11
+ video_sample_info.codec = codec;
+#endif // SB_API_VERSION >= 11
+
+#if SB_API_VERSION >= 11
+ video_sample_info.color_metadata.primaries = kSbMediaPrimaryIdBt709;
+ video_sample_info.color_metadata.transfer = kSbMediaTransferIdBt709;
+ video_sample_info.color_metadata.matrix = kSbMediaMatrixIdBt709;
+ video_sample_info.color_metadata.range = kSbMediaRangeIdLimited;
+#else // SB_API_VERSION >= 11
+ static SbMediaColorMetadata color_metadata;
+ color_metadata.primaries = kSbMediaPrimaryIdBt709;
+ color_metadata.transfer = kSbMediaTransferIdBt709;
+ color_metadata.matrix = kSbMediaMatrixIdBt709;
+ color_metadata.range = kSbMediaRangeIdLimited;
+ video_sample_info.color_metadata = &color_metadata;
+#endif // SB_API_VERSION >= 11
+
+ video_sample_info.frame_width = 1920;
+ video_sample_info.frame_height = 1080;
+
+ return video_sample_info;
+}
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+SbPlayerCreationParam CreatePlayerCreationParam(SbMediaAudioCodec audio_codec,
+ SbMediaVideoCodec video_codec) {
+ SbPlayerCreationParam creation_param = {};
+
+ creation_param.audio_mime = "";
+ creation_param.video_mime = "";
+ creation_param.drm_system = kSbDrmSystemInvalid;
+ creation_param.audio_sample_info = CreateAudioSampleInfo(audio_codec);
+ creation_param.video_sample_info = CreateVideoSampleInfo(video_codec);
+ creation_param.output_mode = kSbPlayerOutputModeInvalid;
+ creation_param.max_video_capabilities = "";
+
+ return creation_param;
+}
+
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+} // namespace nplb
+} // namespace starboard
diff --git a/src/starboard/nplb/player_creation_param_helpers.h b/src/starboard/nplb/player_creation_param_helpers.h
new file mode 100644
index 0000000..8cb327d
--- /dev/null
+++ b/src/starboard/nplb/player_creation_param_helpers.h
@@ -0,0 +1,37 @@
+// Copyright 2020 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_NPLB_PLAYER_CREATION_PARAM_HELPERS_H_
+#define STARBOARD_NPLB_PLAYER_CREATION_PARAM_HELPERS_H_
+
+#include "starboard/configuration.h"
+
+#include "starboard/media.h"
+#include "starboard/player.h"
+
+namespace starboard {
+namespace nplb {
+
+SbMediaAudioSampleInfo CreateAudioSampleInfo(SbMediaAudioCodec codec);
+SbMediaVideoSampleInfo CreateVideoSampleInfo(SbMediaVideoCodec codec);
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+SbPlayerCreationParam CreatePlayerCreationParam(SbMediaAudioCodec audio_codec,
+ SbMediaVideoCodec video_codec);
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+} // namespace nplb
+} // namespace starboard
+
+#endif // STARBOARD_NPLB_PLAYER_CREATION_PARAM_HELPERS_H_
diff --git a/src/starboard/nplb/player_get_preferred_output_mode_test.cc b/src/starboard/nplb/player_get_preferred_output_mode_test.cc
new file mode 100644
index 0000000..4167dd9
--- /dev/null
+++ b/src/starboard/nplb/player_get_preferred_output_mode_test.cc
@@ -0,0 +1,52 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/player.h"
+
+#include "starboard/configuration.h"
+#include "starboard/nplb/player_creation_param_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+TEST(SbPlayerGetPreferredOutputModeTest, SunnyDay) {
+ auto creation_param =
+ CreatePlayerCreationParam(kSbMediaAudioCodecAac, kSbMediaVideoCodecH264);
+
+ creation_param.output_mode = kSbPlayerOutputModeInvalid;
+ auto output_mode = SbPlayerGetPreferredOutputMode(&creation_param);
+ ASSERT_NE(output_mode, kSbPlayerOutputModeInvalid);
+
+ creation_param.output_mode = output_mode;
+ output_mode = SbPlayerGetPreferredOutputMode(&creation_param);
+ ASSERT_EQ(output_mode, creation_param.output_mode);
+
+ creation_param.output_mode = kSbPlayerOutputModeDecodeToTexture;
+ output_mode = SbPlayerGetPreferredOutputMode(&creation_param);
+ ASSERT_NE(output_mode, kSbPlayerOutputModeInvalid);
+
+ creation_param.output_mode = kSbPlayerOutputModePunchOut;
+ output_mode = SbPlayerGetPreferredOutputMode(&creation_param);
+ ASSERT_NE(output_mode, kSbPlayerOutputModeInvalid);
+}
+
+} // namespace
+} // namespace nplb
+} // namespace starboard
+
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
diff --git a/src/starboard/nplb/player_output_mode_supported_test.cc b/src/starboard/nplb/player_output_mode_supported_test.cc
index 65b35b3..d4e77f2 100644
--- a/src/starboard/nplb/player_output_mode_supported_test.cc
+++ b/src/starboard/nplb/player_output_mode_supported_test.cc
@@ -21,6 +21,8 @@
namespace nplb {
namespace {
+#if !SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
TEST(SbPlayerOutputModeSupportedTest, SunnyDay) {
SbMediaVideoCodec kVideoCodec = kSbMediaVideoCodecH264;
SbDrmSystem kDrmSystem = kSbDrmSystemInvalid;
@@ -46,6 +48,8 @@
EXPECT_FALSE(result);
}
+#endif // !SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
} // namespace
} // namespace nplb
} // namespace starboard
diff --git a/src/starboard/nplb/socket_get_interface_address_test.cc b/src/starboard/nplb/socket_get_interface_address_test.cc
index 36ed9c3..3c1a317 100644
--- a/src/starboard/nplb/socket_get_interface_address_test.cc
+++ b/src/starboard/nplb/socket_get_interface_address_test.cc
@@ -64,7 +64,7 @@
EXPECT_TRUE(SbSocketGetInterfaceAddress(NULL, &source, &netmask));
// A netmask that starts with 0 is likely incorrect.
- EXPECT_TRUE(netmask.address[0] & 0x8);
+ EXPECT_TRUE(netmask.address[0] & 0x80);
EXPECT_TRUE(source.type == kSbSocketAddressTypeIpv4 ||
source.type == kSbSocketAddressTypeIpv6);
EXPECT_TRUE(netmask.type == kSbSocketAddressTypeIpv4 ||
@@ -89,7 +89,7 @@
EXPECT_FALSE(IsLocalhost(&source));
// A netmask that starts with 0 is likely incorrect.
- EXPECT_TRUE(netmask.address[0] & 0x8);
+ EXPECT_TRUE(netmask.address[0] & 0x80);
EXPECT_EQ(GetAddressType(), source.type);
EXPECT_EQ(GetAddressType(), netmask.type);
EXPECT_EQ(0, source.port);
@@ -128,7 +128,7 @@
EXPECT_EQ(GetAddressType(), source.type);
EXPECT_NE(0, source.port);
// A netmask that starts with 0 is likely incorrect.
- EXPECT_TRUE(netmask.address[0] & 0x8);
+ EXPECT_TRUE(netmask.address[0] & 0x80);
EXPECT_EQ(GetAddressType(), netmask.type);
EXPECT_NE(0, SbMemoryCompare(source.address, invalid_address.address,
SB_ARRAY_SIZE(source.address)));
diff --git a/src/starboard/player.h b/src/starboard/player.h
index 08e16d1..b579672 100644
--- a/src/starboard/player.h
+++ b/src/starboard/player.h
@@ -117,6 +117,51 @@
kSbPlayerOutputModeInvalid,
} SbPlayerOutputMode;
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+// The playback related parameters to pass into SbPlayerCreate() and
+// SbPlayerGetPreferredOutputMode().
+typedef struct SbPlayerCreationParam {
+ // The audio mime of the stream if available. Otherwise it will point to an
+ // empty string. It will never be NULL.
+ const char* audio_mime;
+ // The video mime of the stream if available. Otherwise it will point to an
+ // empty string. It will never be NULL.
+ const char* video_mime;
+ // Provides an appropriate DRM system if the media stream has encrypted
+ // portions. It will be |kSbDrmSystemInvalid| if the stream does not have
+ // encrypted portions.
+ SbDrmSystem drm_system;
+ // Contains a populated SbMediaAudioSampleInfo if |audio_sample_info.codec|
+ // isn't |kSbMediaAudioCodecNone|. When |audio_sample_info.codec| is
+ // |kSbMediaAudioCodecNone|, the video doesn't have an audio track.
+ SbMediaAudioSampleInfo audio_sample_info;
+ // Contains a populated SbMediaVideoSampleInfo if |video_sample_info.codec|
+ // isn't |kSbMediaVideoCodecNone|. When |video_sample_info.codec| is
+ // |kSbMediaVideoCodecNone|, the video is audio only.
+ SbMediaVideoSampleInfo video_sample_info;
+ // Selects how the decoded video frames will be output. For example,
+ // |kSbPlayerOutputModePunchOut| indicates that the decoded video frames will
+ // be output to a background video layer by the platform, and
+ // |kSbPlayerOutputDecodeToTexture| indicates that the decoded video frames
+ // should be made available for the application to pull via calls to
+ // SbPlayerGetCurrentFrame().
+ SbPlayerOutputMode output_mode;
+ // Indicates the max video capabilities required. The web app will not provide
+ // a video stream exceeding the maximums described by this parameter. Allows
+ // the platform to optimize playback pipeline for low quality video streams if
+ // it knows that it will never adapt to higher quality streams. The string
+ // uses the same format as the string passed in to
+ // SbMediaCanPlayMimeAndKeySystem(), for example, when it is set to
+ // "width=1920; height=1080; framerate=15;", the video will never adapt to
+ // resolution higher than 1920x1080 or frame per second higher than 15 fps.
+ // When the maximums are unknown, this will be set to an empty string. It
+ // will never be set to NULL.
+ const char* max_video_capabilities;
+} SbPlayerCreationParam;
+
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
#if SB_API_VERSION >= 11
// Identify the type of side data accompanied with |SbPlayerSampleInfo|, as side
@@ -411,15 +456,16 @@
// is no longer valid after this function returns. The implementation has to
// make a copy of the content if it is needed after the function returns.
#if SB_API_VERSION >= 11
-// |max_video_capabilities|: This string communicates the video maximums to the
-// platform. The web app will not provide a video stream exceeding the
-// maximums described by this parameter. Allows the platform to optimize
-// playback pipeline for low quality video streams if it knows that it will
-// never adapt to higher quality streams. The string uses the same format as
-// the string passed in to SbMediaCanPlayMimeAndKeySystem(), for example, when
-// it is set to "width=1920; height=1080; framerate=15;", the video will never
-// adapt to resolution higher than 1920x1080 or frame per second higher than
-// 15 fps. When the maximums are unknown, this will be set to NULL.
+// |max_video_capabilities|: This string communicates the max video capabilities
+// required to the platform. The web app will not provide a video stream
+// exceeding the maximums described by this parameter. Allows the platform to
+// optimize playback pipeline for low quality video streams if it knows that
+// it will never adapt to higher quality streams. The string uses the same
+// format as the string passed in to SbMediaCanPlayMimeAndKeySystem(), for
+// example, when it is set to "width=1920; height=1080; framerate=15;", the
+// video will never adapt to resolution higher than 1920x1080 or frame per
+// second higher than 15 fps. When the maximums are unknown, this will be set
+// to NULL.
#endif // SB_API_VERSION >= 11
#if SB_HAS(AUDIOLESS_VIDEO)
// When |audio_codec| is |kSbMediaAudioCodecNone|, this must be set to NULL.
@@ -467,6 +513,21 @@
// |decoder_status_func|, |player_status_func|, or |player_error_func| if it
// applies), then |kSbPlayerInvalid| must be returned.
#endif // SB_API_VERSION >= 10
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+SB_EXPORT SbPlayer
+SbPlayerCreate(SbWindow window,
+ const SbPlayerCreationParam* creation_param,
+ SbPlayerDeallocateSampleFunc sample_deallocate_func,
+ SbPlayerDecoderStatusFunc decoder_status_func,
+ SbPlayerStatusFunc player_status_func,
+ SbPlayerErrorFunc player_error_func,
+ void* context,
+ SbDecodeTargetGraphicsContextProvider* context_provider);
+
+#else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
SB_EXPORT SbPlayer
SbPlayerCreate(SbWindow window,
SbMediaVideoCodec video_codec,
@@ -492,12 +553,38 @@
void* context,
SbPlayerOutputMode output_mode,
SbDecodeTargetGraphicsContextProvider* context_provider);
+
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+// Returns the preferred output mode of the implementation when a video
+// described by |creation_param| is played. It is assumed that it is okay to
+// call SbPlayerCreate() with the same video described by |creation_param|,
+// with its |output_mode| member replaced by the returned output mode.
+// When the caller has no preference on the output mode, it will set
+// |creation_param->output_mode| to |kSbPlayerOutputModeInvalid|, and the
+// implementation can return its preferred output mode based on the information
+// contained in |creation_param|. The caller can also set
+// |creation_param->output_mode| to its preferred output mode, and the
+// implementation should return the same output mode if it is supported,
+// otherwise the implementation should return an output mode that it is
+// supported, as if |creation_param->output_mode| is set to
+// |kSbPlayerOutputModeInvalid| prior to the call.
+// Note that it is not the responsibility of this function to verify whether the
+// video described by |creation_param| can be played on the platform, and the
+// implementation should try its best effort to return a valid output mode.
+// |creation_param| will never be NULL.
+SB_EXPORT SbPlayerOutputMode
+SbPlayerGetPreferredOutputMode(const SbPlayerCreationParam* creation_param);
+
+#else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
// Returns true if the given player output mode is supported by the platform.
// If this function returns true, it is okay to call SbPlayerCreate() with
// the given |output_mode|.
SB_EXPORT bool SbPlayerOutputModeSupported(SbPlayerOutputMode output_mode,
SbMediaVideoCodec codec,
SbDrmSystem drm_system);
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
// Destroys |player|, freeing all associated resources. Each callback must
// receive one more callback to say that the player was destroyed. Callbacks
diff --git a/src/starboard/raspi/shared/launcher.py b/src/starboard/raspi/shared/launcher.py
index 75e57c6..2ea99b7 100644
--- a/src/starboard/raspi/shared/launcher.py
+++ b/src/starboard/raspi/shared/launcher.py
@@ -143,7 +143,7 @@
retry_count = 0
expected_prompts = [
r'.*Are\syou\ssure.*', # Fingerprint verification
- r'\S+ password:', # Password prompt
+ r'.* password:', # Password prompt
'.*[a-zA-Z]+.*', # Any other text input
]
while True:
diff --git a/src/starboard/raspi/shared/starboard_platform.gypi b/src/starboard/raspi/shared/starboard_platform.gypi
index 3c0ebb4..f71d0c8 100644
--- a/src/starboard/raspi/shared/starboard_platform.gypi
+++ b/src/starboard/raspi/shared/starboard_platform.gypi
@@ -234,6 +234,7 @@
'<(DEPTH)/starboard/shared/pthread/mutex_release.cc',
'<(DEPTH)/starboard/shared/pthread/once.cc',
'<(DEPTH)/starboard/shared/pthread/thread_context_get_pointer.cc',
+ '<(DEPTH)/starboard/shared/pthread/thread_context_internal.cc',
'<(DEPTH)/starboard/shared/pthread/thread_context_internal.h',
'<(DEPTH)/starboard/shared/pthread/thread_create.cc',
'<(DEPTH)/starboard/shared/pthread/thread_create_local_key.cc',
@@ -326,6 +327,7 @@
'<(DEPTH)/starboard/shared/starboard/player/player_get_info.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_get_info2.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_get_maximum_number_of_samples_per_write.cc',
+ '<(DEPTH)/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
'<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
'<(DEPTH)/starboard/shared/starboard/player/player_output_mode_supported.cc',
diff --git a/src/starboard/shared/pthread/thread_context_get_pointer.cc b/src/starboard/shared/pthread/thread_context_get_pointer.cc
index d7e2e7d..4625ebf 100644
--- a/src/starboard/shared/pthread/thread_context_get_pointer.cc
+++ b/src/starboard/shared/pthread/thread_context_get_pointer.cc
@@ -21,88 +21,24 @@
#include "starboard/common/log.h"
#include "starboard/shared/pthread/thread_context_internal.h"
-// TODO: Implement for e.g. Mac OSX, BSD flavors, QNX - maybe in another file.
-#if !defined(__gnu_linux__) // Note: __linux__ is undef'd for Starboard builds.
-#error "SbThreadContext is only implemented for Linux"
-#endif
-
-// UCLIBC pretends to be GLIBC.
-#if (defined(__GLIBC__) || defined(__GNU_LIBRARY__)) && !defined(__UCLIBC__)
-#define SB_IS_GLIBC 1
-#else
-#define SB_IS_GLIBC 0
-#endif
-
-// clang-format off
-#if SB_IS_ARCH_X86
-# if SB_IS_32_BIT
-# error("TODO: Validate UCONTEXT macros on 32-bit X86")
-# define UCONTEXT_IP(ucontext) ((ucontext)->uc_mcontext.gregs[REG_EIP])
-# define UCONTEXT_SP(ucontext) ((ucontext)->uc_mcontext.gregs[REG_ESP])
-# define UCONTEXT_FP(ucontext) ((ucontext)->uc_mcontext.gregs[REG_EBP])
-# elif SB_IS_64_BIT
-# define UCONTEXT_IP(ucontext) ((ucontext)->uc_mcontext.gregs[REG_RIP])
-# define UCONTEXT_SP(ucontext) ((ucontext)->uc_mcontext.gregs[REG_RSP])
-# define UCONTEXT_FP(ucontext) ((ucontext)->uc_mcontext.gregs[REG_RBP])
-# endif
-#elif SB_IS_ARCH_ARM
-# if SB_IS_32_BIT
-# if SB_IS_GLIBC && ((__GLIBC__ * 100 + __GLIBC_MINOR__) < 204)
-# error("TODO: Validate UCONTEXT macros on 32-bit ARM w/ old GLIBC")
-# define UCONTEXT_IP(ucontext) ((ucontext)->uc_mcontext.gregs[R15])
-# define UCONTEXT_SP(ucontext) ((ucontext)->uc_mcontext.gregs[R13])
-# define UCONTEXT_FP(ucontext) ((ucontext)->uc_mcontext.gregs[R11])
-# else // SB_IS_GLIBC < 2.04
-# define UCONTEXT_IP(ucontext) ((ucontext)->uc_mcontext.arm_pc)
-# define UCONTEXT_SP(ucontext) ((ucontext)->uc_mcontext.arm_sp)
-# define UCONTEXT_FP(ucontext) ((ucontext)->uc_mcontext.arm_fp)
-# endif // SB_IS_GLIBC < 2.04
-# elif SB_IS_64_BIT
-# error("TODO: Validate UCONTEXT macros on 64-bit ARM")
-# define UCONTEXT_IP(ucontext) ((ucontext)->uc_mcontext.pc)
-# define UCONTEXT_SP(ucontext) ((ucontext)->uc_mcontext.sp)
-# define UCONTEXT_FP(ucontext) ((ucontext)->uc_mcontext.regs[29])
-# endif
-#elif SB_IS_ARCH_MIPS
-# error("TODO: Validate UCONTEXT macros on MIPS")
-# define UCONTEXT_IP(ucontext) ((ucontext)->uc_mcontext.pc)
-# define UCONTEXT_SP(ucontext) ((ucontext)->uc_mcontext.gregs[29])
-# define UCONTEXT_FP(ucontext) ((ucontext)->uc_mcontext.gregs[30])
-#elif SB_IS_ARCH_PPC
-# if SB_IS_GLIBC
-# error("TODO: Validate UCONTEXT macros on PPC w/ GLIBC")
-# define UCONTEXT_IP(ucontext) ((ucontext)->uc_mcontext.regs->nip)
-# define UCONTEXT_SP(ucontext) ((ucontext)->uc_mcontext.regs->gpr[PT_R1])
-# define UCONTEXT_FP(ucontext) ((ucontext)->uc_mcontext.regs->gpr[PT_R31])
-# else // SB_IS_GLIBC
-# error("TODO: Validate UCONTEXT macros on PPC")
-# define UCONTEXT_IP(ucontext) ((ucontext)->uc_mcontext.gp_regs[32])
-# define UCONTEXT_SP(ucontext) ((ucontext)->uc_mcontext.gp_regs[1])
-# define UCONTEXT_FP(ucontext) ((ucontext)->uc_mcontext.gp_regs[31])
-# endif // SB_IS_GLIBC
-#else // SB_IS_ARCH_XXX
-# error "SbThreadContext isn't implemented for this CPU architecture"
-#endif // SB_IS_ARCH_XXX
-// clang-format on
-
bool SbThreadContextGetPointer(SbThreadContext context,
SbThreadContextProperty property,
void** out_value) {
- if (context == kSbThreadContextInvalid || context->ucontext == nullptr) {
+ if (context == kSbThreadContextInvalid || context->ip_ == nullptr) {
return false;
}
switch (property) {
case kSbThreadContextInstructionPointer:
- *out_value = reinterpret_cast<void*>(UCONTEXT_IP(context->ucontext));
+ *out_value = context->ip_;
return true;
case kSbThreadContextStackPointer:
- *out_value = reinterpret_cast<void*>(UCONTEXT_SP(context->ucontext));
+ *out_value = context->sp_;
return true;
case kSbThreadContextFramePointer:
- *out_value = reinterpret_cast<void*>(UCONTEXT_FP(context->ucontext));
+ *out_value = context->fp_;
return true;
default:
diff --git a/src/starboard/shared/pthread/thread_context_internal.cc b/src/starboard/shared/pthread/thread_context_internal.cc
new file mode 100644
index 0000000..f5e7353
--- /dev/null
+++ b/src/starboard/shared/pthread/thread_context_internal.cc
@@ -0,0 +1,73 @@
+// Copyright 2020 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/pthread/thread_context_internal.h"
+
+#if SB_API_VERSION >= 11
+
+#if !defined(__gnu_linux__) // Note: __linux__ is undef'd for Starboard builds.
+#error "SbThreadContext is only implemented for Linux"
+#endif
+
+#if !(SB_IS_32_BIT || SB_IS_64_BIT)
+#error "CPU architecture must be either 32-bit or 64-bit"
+#endif
+
+// UCLIBC pretends to be GLIBC.
+#if (defined(__GLIBC__) || defined(__GNU_LIBRARY__)) && !defined(__UCLIBC__)
+#define SB_IS_GLIBC 1
+#else
+#define SB_IS_GLIBC 0
+#endif
+
+SbThreadContextPrivate::SbThreadContextPrivate(ucontext_t* ucontext) {
+ mcontext_t& mcontext = ucontext->uc_mcontext;
+
+// TODO: Remove redundant #if checks when
+// SB_MINIMUM_API_VERSION >= SB_SABI_FILE_VERSION.
+#if SB_IS_ARCH_X86 || SB_IS_ARCH_X64
+#if SB_IS_64_BIT
+ // 64-bit X86 (aka X64)
+ ip_ = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
+ sp_ = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
+ fp_ = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]);
+#else
+ // 32-bit X86
+ ip_ = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]);
+ sp_ = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]);
+ fp_ = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]);
+#endif
+#elif SB_IS_ARCH_ARM || SB_IS_ARCH_ARM64
+#if SB_IS_64_BIT
+ // 64-bit ARM
+ ip_ = reinterpret_cast<void*>(mcontext.pc);
+ sp_ = reinterpret_cast<void*>(mcontext.sp);
+ fp_ = reinterpret_cast<void*>(mcontext.regs[29]);
+#elif SB_IS_GLIBC && ((__GLIBC__ * 100 + __GLIBC_MINOR__) < 204)
+ // 32-bit ARM w/ old GLIBC that used gregs[]
+ ip_ = reinterpret_cast<void*>(mcontext.gregs[R15]);
+ sp_ = reinterpret_cast<void*>(mcontext.gregs[R13]);
+ fp_ = reinterpret_cast<void*>(mcontext.gregs[R11]);
+#else
+ // 32-bit ARM
+ ip_ = reinterpret_cast<void*>(mcontext.arm_pc);
+ sp_ = reinterpret_cast<void*>(mcontext.arm_sp);
+ fp_ = reinterpret_cast<void*>(mcontext.arm_fp);
+#endif
+#else // SB_IS_ARCH_XXX
+#error "SbThreadContext isn't implemented for this CPU architecture"
+#endif // SB_IS_ARCH_XXX
+}
+
+#endif // SB_API_VERSION >= 11
diff --git a/src/starboard/shared/pthread/thread_context_internal.h b/src/starboard/shared/pthread/thread_context_internal.h
index 3effcd6..14ef86d 100644
--- a/src/starboard/shared/pthread/thread_context_internal.h
+++ b/src/starboard/shared/pthread/thread_context_internal.h
@@ -15,11 +15,23 @@
#ifndef STARBOARD_SHARED_PTHREAD_THREAD_CONTEXT_INTERNAL_H_
#define STARBOARD_SHARED_PTHREAD_THREAD_CONTEXT_INTERNAL_H_
+#include <signal.h>
+
#include "starboard/thread.h"
#if SB_API_VERSION >= 11
struct SbThreadContextPrivate {
- ucontext_t* ucontext = nullptr;
+ explicit SbThreadContextPrivate(ucontext_t* ucontext);
+
+ SbThreadContextPrivate() = default;
+ SbThreadContextPrivate(const SbThreadContextPrivate&) = default;
+ SbThreadContextPrivate(SbThreadContextPrivate&&) = default;
+ SbThreadContextPrivate& operator=(const SbThreadContextPrivate&) = default;
+ SbThreadContextPrivate& operator=(SbThreadContextPrivate&&) = default;
+
+ void* ip_ = nullptr;
+ void* sp_ = nullptr;
+ void* fp_ = nullptr;
};
#endif // SB_API_VERSION >= 11
diff --git a/src/starboard/shared/pthread/thread_sampler_internal.cc b/src/starboard/shared/pthread/thread_sampler_internal.cc
index bca4da4..a56f8ec 100644
--- a/src/starboard/shared/pthread/thread_sampler_internal.cc
+++ b/src/starboard/shared/pthread/thread_sampler_internal.cc
@@ -109,7 +109,7 @@
starboard::ScopedLock lock(GetMutex());
SB_DCHECK(frozen_sampler_ == sampler) << "SbThreadSampler didn't freeze.";
if (frozen_sampler_ != sampler) return false;
- sb_context_.ucontext = nullptr;
+ sb_context_ = SbThreadContextPrivate();
sem_post(&thaw_semaphore_);
frozen_sampler_ = kSbThreadSamplerInvalid;
return true;
@@ -119,7 +119,7 @@
void* context) {
SB_UNREFERENCED_PARAMETER(info);
if (signal != SIGPROF) return;
- sb_context_.ucontext = reinterpret_cast<ucontext_t*>(context);
+ sb_context_ = SbThreadContextPrivate(reinterpret_cast<ucontext_t*>(context));
// |Freeze| can return the context now.
sem_post(&freeze_semaphore_);
// Keep this thread frozen until |Thaw| is called.
diff --git a/src/starboard/shared/starboard/player/filter/video_frame_cadence_pattern_generator.cc b/src/starboard/shared/starboard/player/filter/video_frame_cadence_pattern_generator.cc
index 83ccb11..e291f6f 100644
--- a/src/starboard/shared/starboard/player/filter/video_frame_cadence_pattern_generator.cc
+++ b/src/starboard/shared/starboard/player/filter/video_frame_cadence_pattern_generator.cc
@@ -75,9 +75,9 @@
}
void VideoFrameCadencePatternGenerator::AdvanceToNextFrame() {
- SB_DCHECK(refresh_rate_ != kInvalidRefreshRate);
- SB_DCHECK(frame_rate_ != kInvalidFrameRate);
-
+ // It is possible that AdvanceToNextFrame() is called before refresh rate and
+ // frame rate are set. This can happen when the platform release the frame on
+ // rendering.
++frame_index_;
}
diff --git a/src/starboard/shared/starboard/player/player_create.cc b/src/starboard/shared/starboard/player/player_create.cc
index fd6f379..c8dfbdd 100644
--- a/src/starboard/shared/starboard/player/player_create.cc
+++ b/src/starboard/shared/starboard/player/player_create.cc
@@ -33,6 +33,49 @@
FilterBasedPlayerWorkerHandler;
using starboard::shared::starboard::player::PlayerWorker;
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+SbPlayer SbPlayerCreate(SbWindow window,
+ const SbPlayerCreationParam* creation_param,
+ SbPlayerDeallocateSampleFunc sample_deallocate_func,
+ SbPlayerDecoderStatusFunc decoder_status_func,
+ SbPlayerStatusFunc player_status_func,
+ SbPlayerErrorFunc player_error_func,
+ void* context,
+ SbDecodeTargetGraphicsContextProvider* provider) {
+ if (!creation_param) {
+ SB_LOG(ERROR) << "CreationParam cannot be null.";
+ return kSbPlayerInvalid;
+ }
+ if (!creation_param->audio_mime) {
+ SB_LOG(ERROR) << "creation_param->audio_mime cannot be null.";
+ return kSbPlayerInvalid;
+ }
+ if (!creation_param->video_mime) {
+ SB_LOG(ERROR) << "creation_param->video_mime cannot be null.";
+ return kSbPlayerInvalid;
+ }
+ if (!creation_param->max_video_capabilities) {
+ SB_LOG(ERROR) << "creation_param->max_video_capabilities cannot be null.";
+ return kSbPlayerInvalid;
+ }
+
+ SB_LOG(INFO) << "SbPlayerCreate() called with audio mime \""
+ << creation_param->audio_mime << "\", video mime \""
+ << creation_param->video_mime
+ << "\", and max video capabilities \""
+ << creation_param->max_video_capabilities << "\".";
+
+ SbMediaAudioCodec audio_codec = creation_param->audio_sample_info.codec;
+ SbMediaVideoCodec video_codec = creation_param->video_sample_info.codec;
+ SbDrmSystem drm_system = creation_param->drm_system;
+ const SbMediaAudioSampleInfo* audio_sample_info =
+ &creation_param->audio_sample_info;
+ const char* max_video_capabilities = creation_param->max_video_capabilities;
+ const auto output_mode = creation_param->output_mode;
+
+#else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
SbPlayer SbPlayerCreate(SbWindow window,
SbMediaVideoCodec video_codec,
SbMediaAudioCodec audio_codec,
@@ -53,6 +96,8 @@
void* context,
SbPlayerOutputMode output_mode,
SbDecodeTargetGraphicsContextProvider* provider) {
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
SB_UNREFERENCED_PARAMETER(window);
#if SB_API_VERSION >= 11
SB_UNREFERENCED_PARAMETER(max_video_capabilities);
@@ -120,10 +165,17 @@
return kSbPlayerInvalid;
}
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+ if (SbPlayerGetPreferredOutputMode(creation_param) != output_mode) {
+ SB_LOG(ERROR) << "Unsupported player output mode " << output_mode;
+ return kSbPlayerInvalid;
+ }
+#else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
if (!SbPlayerOutputModeSupported(output_mode, video_codec, drm_system)) {
SB_LOG(ERROR) << "Unsupported player output mode " << output_mode;
return kSbPlayerInvalid;
}
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
UpdateActiveSessionPlatformPlaybackState(kPlaying);
diff --git a/src/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc b/src/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc
new file mode 100644
index 0000000..f69b6d7
--- /dev/null
+++ b/src/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc
@@ -0,0 +1,74 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/player.h"
+
+#include <algorithm>
+
+#include "starboard/configuration.h"
+#include "starboard/shared/starboard/player/filter/video_decoder_internal.h"
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+SbPlayerOutputMode SbPlayerGetPreferredOutputMode(
+ const SbPlayerCreationParam* creation_param) {
+ using starboard::shared::starboard::player::filter::VideoDecoder;
+
+ if (!creation_param) {
+ SB_LOG(ERROR) << "creation_param cannot be NULL";
+ return kSbPlayerOutputModeInvalid;
+ }
+
+ if (!creation_param->audio_mime) {
+ SB_LOG(ERROR) << "creation_param->audio_mime cannot be NULL";
+ return kSbPlayerOutputModeInvalid;
+ }
+
+ if (!creation_param->video_mime) {
+ SB_LOG(ERROR) << "creation_param->video_mime cannot be NULL";
+ return kSbPlayerOutputModeInvalid;
+ }
+
+ if (!creation_param->max_video_capabilities) {
+ SB_LOG(ERROR) << "creation_param->max_video_capabilities cannot be NULL";
+ return kSbPlayerOutputModeInvalid;
+ }
+
+ auto codec = creation_param->video_sample_info.codec;
+ auto drm_system = creation_param->drm_system;
+
+ SbPlayerOutputMode output_modes_to_check[] = {
+ kSbPlayerOutputModePunchOut, kSbPlayerOutputModeDecodeToTexture,
+ };
+
+ // Check |kSbPlayerOutputModeDecodeToTexture| first if the caller prefers it.
+ if (creation_param->output_mode == kSbPlayerOutputModeDecodeToTexture) {
+ std::swap(output_modes_to_check[0], output_modes_to_check[1]);
+ }
+
+ if (VideoDecoder::OutputModeSupported(output_modes_to_check[0], codec,
+ drm_system)) {
+ return output_modes_to_check[0];
+ }
+
+ if (VideoDecoder::OutputModeSupported(output_modes_to_check[1], codec,
+ drm_system)) {
+ return output_modes_to_check[1];
+ }
+
+ SB_NOTREACHED();
+ return kSbPlayerOutputModeInvalid;
+}
+
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
diff --git a/src/starboard/shared/starboard/player/player_output_mode_supported.cc b/src/starboard/shared/starboard/player/player_output_mode_supported.cc
index e3af869..beadfb7 100644
--- a/src/starboard/shared/starboard/player/player_output_mode_supported.cc
+++ b/src/starboard/shared/starboard/player/player_output_mode_supported.cc
@@ -18,6 +18,8 @@
#include "starboard/configuration.h"
#include "starboard/shared/starboard/player/filter/video_decoder_internal.h"
+#if !SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
bool SbPlayerOutputModeSupported(SbPlayerOutputMode output_mode,
SbMediaVideoCodec codec,
SbDrmSystem drm_system) {
@@ -25,3 +27,4 @@
OutputModeSupported(output_mode, codec, drm_system);
}
+#endif // !SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
diff --git a/src/starboard/shared/stub/player_create.cc b/src/starboard/shared/stub/player_create.cc
index d7d2243..ff11851 100644
--- a/src/starboard/shared/stub/player_create.cc
+++ b/src/starboard/shared/stub/player_create.cc
@@ -14,6 +14,24 @@
#include "starboard/player.h"
+#include "starboard/configuration.h"
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+SbPlayer SbPlayerCreate(
+ SbWindow /*window*/,
+ const SbPlayerCreationParam* /*creation_param*/,
+ SbPlayerDeallocateSampleFunc /*sample_deallocate_func*/,
+ SbPlayerDecoderStatusFunc /*decoder_status_func*/,
+ SbPlayerStatusFunc /*player_status_func*/,
+ SbPlayerErrorFunc /*player_error_func*/,
+ void* /*context*/,
+ SbDecodeTargetGraphicsContextProvider* /*context_provider*/) {
+ return kSbPlayerInvalid;
+}
+
+#else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
SbPlayer SbPlayerCreate(SbWindow /*window*/,
SbMediaVideoCodec /*video_codec*/,
SbMediaAudioCodec /*audio_codec*/,
@@ -34,3 +52,5 @@
SbDecodeTargetGraphicsContextProvider* /*provider*/) {
return kSbPlayerInvalid;
}
+
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
diff --git a/src/starboard/shared/stub/player_get_preferred_output_mode.cc b/src/starboard/shared/stub/player_get_preferred_output_mode.cc
new file mode 100644
index 0000000..f52fcc3
--- /dev/null
+++ b/src/starboard/shared/stub/player_get_preferred_output_mode.cc
@@ -0,0 +1,26 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/player.h"
+
+#include "starboard/configuration.h"
+
+#if SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
+SbPlayerOutputMode SbPlayerGetPreferredOutputMode(
+ const SbPlayerCreationParam* /*creation_param*/) {
+ return kSbPlayerOutputModeInvalid;
+}
+
+#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
diff --git a/src/starboard/shared/stub/player_output_mode_supported.cc b/src/starboard/shared/stub/player_output_mode_supported.cc
index 3b3f7dc..2b470fa 100644
--- a/src/starboard/shared/stub/player_output_mode_supported.cc
+++ b/src/starboard/shared/stub/player_output_mode_supported.cc
@@ -14,8 +14,12 @@
#include "starboard/player.h"
+#if !SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
+
bool SbPlayerOutputModeSupported(SbPlayerOutputMode /*output_mode*/,
SbMediaVideoCodec /*codec*/,
SbDrmSystem /*drm_system*/) {
return false;
}
+
+#endif // !SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
diff --git a/src/starboard/stub/BUILD.gn b/src/starboard/stub/BUILD.gn
index cfeb1ba..be648ee 100644
--- a/src/starboard/stub/BUILD.gn
+++ b/src/starboard/stub/BUILD.gn
@@ -279,6 +279,7 @@
"//starboard/shared/stub/player_destroy.cc",
"//starboard/shared/stub/player_get_current_frame.cc",
"//starboard/shared/stub/player_get_info.cc",
+ "//starboard/shared/stub/player_get_preferred_output_mode.cc",
"//starboard/shared/stub/player_output_mode_supported.cc",
"//starboard/shared/stub/player_seek.cc",
"//starboard/shared/stub/player_set_bounds.cc",
diff --git a/src/starboard/stub/stub_sources.gypi b/src/starboard/stub/stub_sources.gypi
index 572bc18..ac44bed 100644
--- a/src/starboard/stub/stub_sources.gypi
+++ b/src/starboard/stub/stub_sources.gypi
@@ -150,6 +150,7 @@
'<(DEPTH)/starboard/shared/stub/player_get_info.cc',
'<(DEPTH)/starboard/shared/stub/player_get_info2.cc',
'<(DEPTH)/starboard/shared/stub/player_get_maximum_number_of_samples_per_write.cc',
+ '<(DEPTH)/starboard/shared/stub/player_get_preferred_output_mode.cc',
'<(DEPTH)/starboard/shared/stub/player_output_mode_supported.cc',
'<(DEPTH)/starboard/shared/stub/player_seek.cc',
'<(DEPTH)/starboard/shared/stub/player_seek2.cc',
diff --git a/src/starboard/tools/app_launcher_packager.py b/src/starboard/tools/app_launcher_packager.py
index 9be2843..5114a5b 100644
--- a/src/starboard/tools/app_launcher_packager.py
+++ b/src/starboard/tools/app_launcher_packager.py
@@ -142,7 +142,9 @@
for p in starboard.tools.platform.GetAll():
platform_path = os.path.relpath(
starboard.tools.platform.Get(p).path, repo_root)
- platforms_map[p] = platform_path
+ # Store posix paths even on Windows so MH Linux hosts can use them.
+ # The template has code to re-normalize them when used on Windows hosts.
+ platforms_map[p] = platform_path.replace('\\', '/')
template = jinja2.Template(
open(os.path.join(current_dir, 'platform.py.template')).read())
with open(os.path.join(dest_dir, 'platform.py'), 'w+') as f:
diff --git a/src/starboard/tools/platform.py.template b/src/starboard/tools/platform.py.template
index 7a211bc..17d55b5 100644
--- a/src/starboard/tools/platform.py.template
+++ b/src/starboard/tools/platform.py.template
@@ -21,6 +21,7 @@
# The name->platform path mapping.
_PATH_MAP = {{platforms_map}}
+_PATH_MAP = {k:os.path.normpath(v) for k,v in _PATH_MAP.iteritems()}
# Cache of the name->PlatformInfo mapping.
diff --git a/src/third_party/proxy_py/proxy.py b/src/third_party/proxy_py/proxy.py
index 7b4a8ec..6b614a6 100755
--- a/src/third_party/proxy_py/proxy.py
+++ b/src/third_party/proxy_py/proxy.py
@@ -630,10 +630,11 @@
Subclass MUST implement `handle` method. It accepts an instance of accepted `Client` connection.
"""
- def __init__(self, hostname='127.0.0.1', port=8899, backlog=100):
+ def __init__(self, hostname='127.0.0.1', port=8899, backlog=100, client_ips=None):
self.hostname = hostname
self.port = port
self.backlog = backlog
+ self.client_ips = client_ips
self.socket = None
def handle(self, client):
@@ -648,6 +649,12 @@
self.socket.listen(self.backlog)
while True:
conn, addr = self.socket.accept()
+ if self.client_ips and addr[0] not in self.client_ips:
+ logger.warning('Closing socket on rejected client IP %s' % addr[0])
+ conn.shutdown(socket.SHUT_RDWR)
+ conn.close()
+ continue
+ logger.info('Handling socket on accepted client IP %s' % addr[0])
client = Client(conn, addr)
self.handle(client)
except Exception as e:
@@ -665,8 +672,8 @@
def __init__(self, hostname='127.0.0.1', port=8899, backlog=100,
auth_code=None, server_recvbuf_size=8192, client_recvbuf_size=8192,
- host_resolver=None):
- super(HTTP, self).__init__(hostname, port, backlog)
+ host_resolver=None, client_ips=None):
+ super(HTTP, self).__init__(hostname, port, backlog, client_ips)
self.auth_code = auth_code
self.client_recvbuf_size = client_recvbuf_size
self.server_recvbuf_size = server_recvbuf_size
@@ -719,7 +726,9 @@
'that proxy.py can open concurrently.')
parser.add_argument('--log-level', default='INFO', help='DEBUG, INFO (default), WARNING, ERROR, CRITICAL')
parser.add_argument('--host_resolver', default=None, help='Default: No host resolution. '
- 'JSON hosts file used for hostname IP resolution.')
+ 'JSON hosts file used for hostname IP resolution.')
+ parser.add_argument('--client_ips', default=None, nargs='*', help='Default: No client IP restriction. '
+ 'The only client IPs that the proxy will accept.')
args = parser.parse_args()
logging.basicConfig(level=getattr(logging, args.log_level),
@@ -743,7 +752,8 @@
auth_code=auth_code,
server_recvbuf_size=int(args.server_recvbuf_size),
client_recvbuf_size=int(args.client_recvbuf_size),
- host_resolver=host_resolver)
+ host_resolver=host_resolver,
+ client_ips=args.client_ips)
proxy.run()
except KeyboardInterrupt:
pass