Import Cobalt.21.master.0.282262 Includes the following patches: https://cobalt-review.googlesource.com/c/cobalt/+/5810 by rongo.li@mstar.corp-partner.google.com
diff --git a/src/.pre-commit-config.yaml b/src/.pre-commit-config.yaml new file mode 100644 index 0000000..440ebc1 --- /dev/null +++ b/src/.pre-commit-config.yaml
@@ -0,0 +1,54 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +default_stages: [commit] +repos: +- repo: local + hooks: + - id: cpplint + name: cpplint + entry: cpplint + language: system + types: [c++] + args: [--verbose=4, --quiet] + exclude: '.*tests?.(cc|h)$' + stages: [push] + - id: cpplint_test + name: cpplint_test + entry: cpplint + language: system + types: [c++] + args: [--verbose=5, --quiet] + files: '.*tests?.(cc|h)$' + stages: [push] + - id: yapf + name: yapf + entry: yapf + language: system + types: [python] + args: [--style=yapf, -i] + - id: pylint + name: pylint + entry: pylint + language: system + types: [python] + args: [-d W0201] + stages: [push] + - id: clang-format + name: clang-format + entry: third_party/precommit-hooks/clang-format_wrapper.py + language: python + types: [c++] + args: [-i, -style=file] + - id: google-java-format + name: google-java-format + entry: third_party/precommit-hooks/google-java-format_wrapper.py + language: python + types: [java] + args: [-i] + - id: gcheckstyle + name: gcheckstyle + entry: third_party/precommit-hooks/gcheckstyle_wrapper.py + language: python + types: [java] + verbose: true + stages: [push]
diff --git a/src/.pylintrc b/src/.pylintrc new file mode 100644 index 0000000..77b0063 --- /dev/null +++ b/src/.pylintrc
@@ -0,0 +1,305 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Profiled execution. +profile=no + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + + +[MESSAGES CONTROL] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). +# CHANGED: +# C0103: Invalid name "" +# C0111: Missing docstring +# C0302: Too many lines in module (N) +# I0010: Unable to consider inline option '' +# I0011: Locally disabling WNNNN +# +# R0801: Similar lines in N files +# R0901: Too many ancestors (8/7) +# R0902: Too many instance attributes (N/7) +# R0903: Too few public methods (N/2) +# R0904: Too many public methods (N/20) +# R0911: Too many return statements (N/6) +# R0912: Too many branches (N/12) +# R0913: Too many arguments (N/5) +# R0914: Too many local variables (N/15) +# R0915: Too many statements (N/50) +# R0921: Abstract class not referenced +# R0922: Abstract class is only referenced 1 times +# W0122: Use of the exec statement +# W0141: Used builtin function '' +# W0142: Used * or ** magic +# W0402: Uses of a deprecated module 'string' +# W0404: 41: Reimport 'XX' (imported line NN) +# W0511: TODO +# W0603: Using the global statement +# W0703: Catch "Exception" +# W1201: Specify string format arguments as logging function parameters +# +# These should get enabled, but the codebase has too many violations currently. +# bad-continuation +# anomalous-backslash-in-string +# bad-context-manager +# bad-indentation +# bad-str-strip-call +# bad-whitespace +# cell-var-from-loop +# deprecated-lambda +# eval-used +# function-redefined +# import-error +# locally-enabled +# missing-final-newline +# no-init +# no-name-in-module +# no-self-use +# not-callable +# old-style-class +# protected-access +# superfluous-parens +# super-on-old-class +# too-many-function-args +# trailing-whitespace +# unnecessary-semicolon +# unpacking-non-sequence +# unused-import +# useless-else-on-loop +disable=C0103,C0111,C0302,I0010,I0011,R0801,R0901,R0902,R0903,R0904,R0911,R0912,R0913,R0914,R0915,R0921,R0922,W0122,W0141,W0142,W0402,W0404,W0511,W0603,W0703,W1201,bad-continuation,anomalous-backslash-in-string,bad-context-manager,bad-indentation,bad-str-strip-call,bad-whitespace,cell-var-from-loop,deprecated-lambda,eval-used,function-redefined,import-error,locally-enabled,missing-final-newline,no-init,no-name-in-module,no-self-use,not-callable,old-style-class,protected-access,superfluous-parens,super-on-old-class,too-many-function-args,trailing-whitespace,unnecessary-semicolon,unpacking-non-sequence,unused-import,useless-else-on-loop + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html +output-format=text + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +# CHANGED: +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (RP0004). +comment=no + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the beginning of the name of dummy variables +# (i.e. not used). +dummy-variables-rgx=_|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +ignored-classes=SQLObject,twisted.internet.reactor,hashlib,google.appengine.api.memcache + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. Python regular +# expressions are accepted. +generated-members=REQUEST,acl_users,aq_parent,multiprocessing.managers.SyncManager + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +# CHANGED: +indent-string=' ' + + +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__ + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branchs=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception
diff --git a/src/base/files/file_util.cc b/src/base/files/file_util.cc index cb9a0d5..d8e445a 100644 --- a/src/base/files/file_util.cc +++ b/src/base/files/file_util.cc
@@ -21,8 +21,12 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/scoped_blocking_call.h" #include "build/build_config.h" + +#if defined(STARBOARD) +#include "starboard/common/file.h" #include "starboard/memory.h" #include "starboard/types.h" +#endif namespace base {
diff --git a/src/base/memory/ref_counted.h b/src/base/memory/ref_counted.h index f52e803..c19072a 100644 --- a/src/base/memory/ref_counted.h +++ b/src/base/memory/ref_counted.h
@@ -26,7 +26,6 @@ public: bool HasOneRef() const { return ref_count_ == 1; } bool HasAtLeastOneRef() const { return ref_count_ >= 1; } - int RefCounts() const { return ref_count_; } protected: explicit RefCountedBase(StartRefCountFromZeroTag) {
diff --git a/src/base/metrics/persistent_histogram_storage.cc b/src/base/metrics/persistent_histogram_storage.cc index 8abb646..3801baf 100644 --- a/src/base/metrics/persistent_histogram_storage.cc +++ b/src/base/metrics/persistent_histogram_storage.cc
@@ -15,7 +15,7 @@ #include "build/build_config.h" #if defined(STARBOARD) -#include "starboard/file.h" +#include "starboard/common/file.h" #endif namespace {
diff --git a/src/cobalt/CHANGELOG.md b/src/cobalt/CHANGELOG.md index 04eb0a6..f2872b4 100644 --- a/src/cobalt/CHANGELOG.md +++ b/src/cobalt/CHANGELOG.md
@@ -102,6 +102,23 @@ (https://lottiefiles.com/web-player). In order to support Lottie, Cobalt updated its Skia port from m61 to m79. + - **Added support for MediaKeySystemMediaCapability.encryptionScheme.** + + Cobalt now supports `MediaKeySystemMediaCapability.encryptionScheme` for + `Navigator.requestMediaKeySystemAccess()`. `encryptionScheme` can be 'cenc', + 'cbcs', or 'cbcs-1-9'. + The default implementation assumes that: + 1. When the Widevine DRM system is used, all the above encryption schemes + should be supported across all containers and codecs supported by the + platform. + 2. When the PlayReady DRM system is used, only 'cenc' is supported across all + containers and codecs supported by the platform. + + It is possible to customize this behavior via an extension to + `SbMediaCanPlayMimeAndKeySystem()`. Please see the Starboard change log and + the comment of `SbMediaCanPlayMimeAndKeySystem()` in `media.h` for more + details. + ## Version 20 - **Support for QUIC and SPDY is now enabled.**
diff --git a/src/cobalt/audio/async_audio_decoder.cc b/src/cobalt/audio/async_audio_decoder.cc index 174cc57..c7885a1 100644 --- a/src/cobalt/audio/async_audio_decoder.cc +++ b/src/cobalt/audio/async_audio_decoder.cc
@@ -38,7 +38,7 @@ decode_finish_callback.Run(reader->sample_rate(), reader->ResetAndReturnAudioBus()); } else { - decode_finish_callback.Run(0.f, std::unique_ptr<ShellAudioBus>()); + decode_finish_callback.Run(0.f, std::unique_ptr<AudioBus>()); } }
diff --git a/src/cobalt/audio/async_audio_decoder.h b/src/cobalt/audio/async_audio_decoder.h index ced6fed..db8a15a 100644 --- a/src/cobalt/audio/async_audio_decoder.h +++ b/src/cobalt/audio/async_audio_decoder.h
@@ -28,7 +28,7 @@ class AsyncAudioDecoder { public: typedef base::Callback<void(float sample_rate, - std::unique_ptr<ShellAudioBus> audio_bus)> + std::unique_ptr<AudioBus> audio_bus)> DecodeFinishCallback; AsyncAudioDecoder();
diff --git a/src/cobalt/audio/audio_buffer.cc b/src/cobalt/audio/audio_buffer.cc index 1b6ff38..0a4c203 100644 --- a/src/cobalt/audio/audio_buffer.cc +++ b/src/cobalt/audio/audio_buffer.cc
@@ -25,8 +25,7 @@ namespace cobalt { namespace audio { -AudioBuffer::AudioBuffer(float sample_rate, - std::unique_ptr<ShellAudioBus> audio_bus) +AudioBuffer::AudioBuffer(float sample_rate, std::unique_ptr<AudioBus> audio_bus) : sample_rate_(sample_rate), audio_bus_(std::move(audio_bus)) { DCHECK_GT(sample_rate_, 0); DCHECK_GT(length(), 0);
diff --git a/src/cobalt/audio/audio_buffer.h b/src/cobalt/audio/audio_buffer.h index 9028a2b..d20beed 100644 --- a/src/cobalt/audio/audio_buffer.h +++ b/src/cobalt/audio/audio_buffer.h
@@ -39,7 +39,7 @@ // https://www.w3.org/TR/webaudio/#AudioBuffer class AudioBuffer : public script::Wrappable { public: - AudioBuffer(float sample_rate, std::unique_ptr<ShellAudioBus> audio_bus); + AudioBuffer(float sample_rate, std::unique_ptr<AudioBus> audio_bus); // Web API: AudioBuffer // @@ -60,14 +60,14 @@ // Custom, not in any spec // - ShellAudioBus* audio_bus() { return audio_bus_.get(); } + AudioBus* audio_bus() { return audio_bus_.get(); } DEFINE_WRAPPABLE_TYPE(AudioBuffer); private: const float sample_rate_; - std::unique_ptr<ShellAudioBus> audio_bus_; + std::unique_ptr<AudioBus> audio_bus_; DISALLOW_COPY_AND_ASSIGN(AudioBuffer); };
diff --git a/src/cobalt/audio/audio_buffer_source_node.cc b/src/cobalt/audio/audio_buffer_source_node.cc index 654e6a8..df8ca6b 100644 --- a/src/cobalt/audio/audio_buffer_source_node.cc +++ b/src/cobalt/audio/audio_buffer_source_node.cc
@@ -27,7 +27,7 @@ namespace audio { typedef media::InterleavedSincResampler InterleavedSincResampler; -typedef media::ShellAudioBus ShellAudioBus; +typedef media::AudioBus AudioBus; // numberOfInputs : 0 // numberOfOutputs : 1 @@ -115,7 +115,7 @@ state_ = kStopped; } -std::unique_ptr<ShellAudioBus> AudioBufferSourceNode::PassAudioBusFromSource( +std::unique_ptr<AudioBus> AudioBufferSourceNode::PassAudioBusFromSource( int32 number_of_frames, SampleType sample_type, bool* finished) { DCHECK_GT(number_of_frames, 0); DCHECK(finished); @@ -126,7 +126,7 @@ *finished = false; if (state_ == kNone || !buffer_) { - return std::unique_ptr<ShellAudioBus>(); + return std::unique_ptr<AudioBus>(); } if (state_ == kStopped || @@ -140,7 +140,7 @@ base::Unretained(this))); buffer_source_added_ = false; } - return std::unique_ptr<ShellAudioBus>(); + return std::unique_ptr<AudioBus>(); } DCHECK_EQ(state_, kStarted); @@ -151,22 +151,22 @@ int32 frames_to_end = buffer_->length() - read_index_; int32 channel_count = static_cast<int32>(audio_bus->channels()); - std::unique_ptr<ShellAudioBus> result; + std::unique_ptr<AudioBus> result; if (!interleaved_resampler_) { int32 audio_bus_frames = std::min(number_of_frames, frames_to_end); if (sample_type == kSampleTypeInt16) { - result.reset(new ShellAudioBus( - channel_count, audio_bus_frames, - reinterpret_cast<int16*>(audio_bus->interleaved_data()) + - read_index_ * channel_count)); + result.reset( + new AudioBus(channel_count, audio_bus_frames, + reinterpret_cast<int16*>(audio_bus->interleaved_data()) + + read_index_ * channel_count)); } else { DCHECK_EQ(sample_type, kSampleTypeFloat32); - result.reset(new ShellAudioBus( - channel_count, audio_bus_frames, - reinterpret_cast<float*>(audio_bus->interleaved_data()) + - read_index_ * channel_count)); + result.reset( + new AudioBus(channel_count, audio_bus_frames, + reinterpret_cast<float*>(audio_bus->interleaved_data()) + + read_index_ * channel_count)); } read_index_ += audio_bus_frames; return result; @@ -219,8 +219,8 @@ interleaved_resampler_->Resample(interleaved_output.get(), number_of_frames); - result.reset(new ShellAudioBus(channel_count, number_of_frames, - kSampleTypeInt16, kStorageTypeInterleaved)); + result.reset(new AudioBus(channel_count, number_of_frames, kSampleTypeInt16, + kStorageTypeInterleaved)); for (int32 i = 0; i < channel_count * number_of_frames; ++i) { uint8* dest_ptr = result->interleaved_data() + sizeof(int16) * i; *reinterpret_cast<int16*>(dest_ptr) = @@ -229,9 +229,8 @@ } else { DCHECK_EQ(sample_type, kSampleTypeFloat32); - result.reset(new ShellAudioBus(channel_count, number_of_frames, - kSampleTypeFloat32, - kStorageTypeInterleaved)); + result.reset(new AudioBus(channel_count, number_of_frames, + kSampleTypeFloat32, kStorageTypeInterleaved)); interleaved_resampler_->Resample( reinterpret_cast<float*>(result->interleaved_data()), number_of_frames); }
diff --git a/src/cobalt/audio/audio_buffer_source_node.h b/src/cobalt/audio/audio_buffer_source_node.h index 1731aef..b01f54c 100644 --- a/src/cobalt/audio/audio_buffer_source_node.h +++ b/src/cobalt/audio/audio_buffer_source_node.h
@@ -22,8 +22,8 @@ #include "cobalt/audio/audio_buffer.h" #include "cobalt/audio/audio_node.h" #include "cobalt/base/tokens.h" +#include "cobalt/media/base/audio_bus.h" #include "cobalt/media/base/interleaved_sinc_resampler.h" -#include "cobalt/media/base/shell_audio_bus.h" #include "cobalt/script/environment_settings.h" namespace cobalt { @@ -35,7 +35,7 @@ // https://www.w3.org/TR/webaudio/#AudioBufferSourceNode class AudioBufferSourceNode : public AudioNode { typedef media::InterleavedSincResampler InterleavedSincResampler; - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; public: AudioBufferSourceNode(script::EnvironmentSettings* settings, @@ -75,8 +75,9 @@ SetAttributeEventListener(base::Tokens::ended(), event_listener); } - std::unique_ptr<ShellAudioBus> PassAudioBusFromSource( - int32 number_of_frames, SampleType sample_type, bool* finished) override; + std::unique_ptr<AudioBus> PassAudioBusFromSource(int32 number_of_frames, + SampleType sample_type, + bool* finished) override; DEFINE_WRAPPABLE_TYPE(AudioBufferSourceNode); void TraceMembers(script::Tracer* tracer) override;
diff --git a/src/cobalt/audio/audio_context.cc b/src/cobalt/audio/audio_context.cc index e909b72..6c4808e 100644 --- a/src/cobalt/audio/audio_context.cc +++ b/src/cobalt/audio/audio_context.cc
@@ -64,7 +64,7 @@ DCHECK(main_message_loop_->BelongsToCurrentThread()); return scoped_refptr<AudioBuffer>(new AudioBuffer( - sample_rate, std::unique_ptr<ShellAudioBus>(new ShellAudioBus( + sample_rate, std::unique_ptr<AudioBus>(new AudioBus( num_of_channels, length, GetPreferredOutputSampleType(), kStorageTypeInterleaved)))); } @@ -151,7 +151,7 @@ // Success callback and error callback should be scheduled to run on the main // thread's event loop. void AudioContext::DecodeFinish(int callback_id, float sample_rate, - std::unique_ptr<ShellAudioBus> audio_bus) { + std::unique_ptr<AudioBus> audio_bus) { if (!main_message_loop_->BelongsToCurrentThread()) { main_message_loop_->PostTask( FROM_HERE,
diff --git a/src/cobalt/audio/audio_context.h b/src/cobalt/audio/audio_context.h index a4667bf..536b2bd 100644 --- a/src/cobalt/audio/audio_context.h +++ b/src/cobalt/audio/audio_context.h
@@ -190,7 +190,7 @@ void DecodeAudioDataInternal(std::unique_ptr<DecodeCallbackInfo> info); void DecodeFinish(int callback_id, float sample_rate, - std::unique_ptr<ShellAudioBus> audio_bus); + std::unique_ptr<AudioBus> audio_bus); script::GlobalEnvironment* global_environment_;
diff --git a/src/cobalt/audio/audio_destination_node.cc b/src/cobalt/audio/audio_destination_node.cc index 4107070..e35f1f9 100644 --- a/src/cobalt/audio/audio_destination_node.cc +++ b/src/cobalt/audio/audio_destination_node.cc
@@ -64,8 +64,7 @@ audio_device_to_delete_ = NULL; } -void AudioDestinationNode::FillAudioBus(bool all_consumed, - ShellAudioBus* audio_bus, +void AudioDestinationNode::FillAudioBus(bool all_consumed, AudioBus* audio_bus, bool* silence) { // This is called on Audio thread. AudioLock::AutoLock lock(audio_lock());
diff --git a/src/cobalt/audio/audio_destination_node.h b/src/cobalt/audio/audio_destination_node.h index 8744034..b758d92 100644 --- a/src/cobalt/audio/audio_destination_node.h +++ b/src/cobalt/audio/audio_destination_node.h
@@ -22,7 +22,7 @@ #include "cobalt/audio/audio_device.h" #include "cobalt/audio/audio_helpers.h" #include "cobalt/audio/audio_node.h" -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #include "cobalt/script/environment_settings.h" namespace cobalt { @@ -37,7 +37,7 @@ // https://www.w3.org/TR/webaudio/#AudioDestinationNode class AudioDestinationNode : public AudioNode, public AudioDevice::RenderCallback { - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; public: AudioDestinationNode(script::EnvironmentSettings* settings, @@ -51,14 +51,15 @@ // From AudioNode. void OnInputNodeConnected() override; - std::unique_ptr<ShellAudioBus> PassAudioBusFromSource( - int32 number_of_frames, SampleType sample_type, bool* finished) override { + std::unique_ptr<AudioBus> PassAudioBusFromSource(int32 number_of_frames, + SampleType sample_type, + bool* finished) override { NOTREACHED(); - return std::unique_ptr<ShellAudioBus>(); + return std::unique_ptr<AudioBus>(); } // From AudioDevice::RenderCallback. - void FillAudioBus(bool all_consumed, ShellAudioBus* audio_bus, + void FillAudioBus(bool all_consumed, AudioBus* audio_bus, bool* silence) override; DEFINE_WRAPPABLE_TYPE(AudioDestinationNode);
diff --git a/src/cobalt/audio/audio_device.cc b/src/cobalt/audio/audio_device.cc index d253f51..b177d07 100644 --- a/src/cobalt/audio/audio_device.cc +++ b/src/cobalt/audio/audio_device.cc
@@ -27,7 +27,7 @@ namespace cobalt { namespace audio { -typedef media::ShellAudioBus ShellAudioBus; +typedef media::AudioBus AudioBus; namespace { const int kRenderBufferSizeFrames = 1024; @@ -69,7 +69,7 @@ // The |render_callback_| returns audio data in planar form. So we read it // into |input_audio_bus_| and convert it into interleaved form and store in // |output_frame_buffer_|. - ShellAudioBus input_audio_bus_; + AudioBus input_audio_bus_; std::unique_ptr<uint8[]> output_frame_buffer_; @@ -102,7 +102,7 @@ #endif // SB_API_VERSION >= 11 input_audio_bus_(static_cast<size_t>(number_of_channels), static_cast<size_t>(kRenderBufferSizeFrames), - GetPreferredOutputSampleType(), ShellAudioBus::kPlanar), + GetPreferredOutputSampleType(), AudioBus::kPlanar), output_frame_buffer_( new uint8[frames_per_channel_ * number_of_channels_ * GetStarboardSampleTypeSize(output_sample_type_)]) { @@ -226,8 +226,8 @@ for (size_t channel = 0; channel < input_audio_bus_.channels(); ++channel) { *output_buffer = ConvertSample<InputType, OutputType>( input_audio_bus_ - .GetSampleForType<InputType, media::ShellAudioBus::kPlanar>( - channel, frame)); + .GetSampleForType<InputType, media::AudioBus::kPlanar>(channel, + frame)); ++output_buffer; } } @@ -237,7 +237,7 @@ TRACE_EVENT0("cobalt::audio", "AudioDevice::Impl::FillOutputAudioBus()"); const bool is_input_int16 = - input_audio_bus_.sample_type() == media::ShellAudioBus::kInt16; + input_audio_bus_.sample_type() == media::AudioBus::kInt16; const bool is_output_int16 = output_sample_type_ == kSbMediaAudioSampleTypeInt16Deprecated;
diff --git a/src/cobalt/audio/audio_device.h b/src/cobalt/audio/audio_device.h index b7974a7..1ccc7f9 100644 --- a/src/cobalt/audio/audio_device.h +++ b/src/cobalt/audio/audio_device.h
@@ -19,7 +19,7 @@ #include <vector> #include "base/basictypes.h" -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" namespace cobalt { namespace audio { @@ -28,7 +28,7 @@ public: class RenderCallback { public: - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; // |all_consumed| will be set to true if all audio frames has been consumed. // This gives the AudioDestinationNode a chance to decide if the AudioDevice @@ -38,7 +38,7 @@ // |silence| will be set to true before calling if |audio_buffer| contains // only silence samples, it will be set to |false| otherwise. It will be // set to false on return if |audio_buffer| has been modified. - virtual void FillAudioBus(bool all_consumed, ShellAudioBus* audio_buffer, + virtual void FillAudioBus(bool all_consumed, AudioBus* audio_buffer, bool* silence) = 0; protected:
diff --git a/src/cobalt/audio/audio_file_reader.h b/src/cobalt/audio/audio_file_reader.h index f53eae4..6a20209 100644 --- a/src/cobalt/audio/audio_file_reader.h +++ b/src/cobalt/audio/audio_file_reader.h
@@ -35,7 +35,7 @@ virtual int32 number_of_channels() const = 0; virtual SampleType sample_type() const = 0; - virtual std::unique_ptr<ShellAudioBus> ResetAndReturnAudioBus() = 0; + virtual std::unique_ptr<AudioBus> ResetAndReturnAudioBus() = 0; }; } // namespace audio
diff --git a/src/cobalt/audio/audio_file_reader_wav.cc b/src/cobalt/audio/audio_file_reader_wav.cc index 94c0bf9..f92b8bd 100644 --- a/src/cobalt/audio/audio_file_reader_wav.cc +++ b/src/cobalt/audio/audio_file_reader_wav.cc
@@ -192,9 +192,8 @@ static_cast<int32>(size / (bytes_per_src_sample * number_of_channels_)); // We store audio samples in the current platform's preferred format. - audio_bus_.reset(new ShellAudioBus(number_of_channels_, number_of_frames_, - sample_type_, - ShellAudioBus::kInterleaved)); + audio_bus_.reset(new AudioBus(number_of_channels_, number_of_frames_, + sample_type_, AudioBus::kInterleaved)); // Both the source data and the destination data are stored in interleaved. #if SB_IS(LITTLE_ENDIAN)
diff --git a/src/cobalt/audio/audio_file_reader_wav.h b/src/cobalt/audio/audio_file_reader_wav.h index 460f268..bf3b95a 100644 --- a/src/cobalt/audio/audio_file_reader_wav.h +++ b/src/cobalt/audio/audio_file_reader_wav.h
@@ -36,7 +36,7 @@ int32 number_of_channels() const override { return number_of_channels_; } SampleType sample_type() const override { return sample_type_; } - std::unique_ptr<ShellAudioBus> ResetAndReturnAudioBus() override { + std::unique_ptr<AudioBus> ResetAndReturnAudioBus() override { return std::move(audio_bus_); } @@ -52,7 +52,7 @@ bool is_valid() { return audio_bus_ != NULL; } - std::unique_ptr<ShellAudioBus> audio_bus_; + std::unique_ptr<AudioBus> audio_bus_; float sample_rate_; int32 number_of_frames_; int32 number_of_channels_;
diff --git a/src/cobalt/audio/audio_helpers.h b/src/cobalt/audio/audio_helpers.h index b4dd6f9..dc98086 100644 --- a/src/cobalt/audio/audio_helpers.h +++ b/src/cobalt/audio/audio_helpers.h
@@ -15,7 +15,7 @@ #ifndef COBALT_AUDIO_AUDIO_HELPERS_H_ #define COBALT_AUDIO_AUDIO_HELPERS_H_ -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #if defined(OS_STARBOARD) #include "starboard/audio_sink.h" @@ -25,13 +25,13 @@ namespace cobalt { namespace audio { -typedef media::ShellAudioBus ShellAudioBus; -typedef media::ShellAudioBus::SampleType SampleType; -typedef media::ShellAudioBus::StorageType StorageType; -const SampleType kSampleTypeInt16 = media::ShellAudioBus::kInt16; -const SampleType kSampleTypeFloat32 = media::ShellAudioBus::kFloat32; -const StorageType kStorageTypeInterleaved = media::ShellAudioBus::kInterleaved; -const StorageType kStorageTypePlanar = media::ShellAudioBus::kPlanar; +typedef media::AudioBus AudioBus; +typedef media::AudioBus::SampleType SampleType; +typedef media::AudioBus::StorageType StorageType; +const SampleType kSampleTypeInt16 = media::AudioBus::kInt16; +const SampleType kSampleTypeFloat32 = media::AudioBus::kFloat32; +const StorageType kStorageTypeInterleaved = media::AudioBus::kInterleaved; +const StorageType kStorageTypePlanar = media::AudioBus::kPlanar; const float kMaxInt16AsFloat32 = 32767.0f; @@ -52,7 +52,7 @@ #endif // Get the size in bytes of an internal sample type, which is an alias for -// media::ShellAudioBus::SampleType. +// media::AudioBus::SampleType. inline size_t GetSampleTypeSize(SampleType sample_type) { switch (sample_type) { case kSampleTypeInt16:
diff --git a/src/cobalt/audio/audio_node.h b/src/cobalt/audio/audio_node.h index 1e9c1dd..925356c 100644 --- a/src/cobalt/audio/audio_node.h +++ b/src/cobalt/audio/audio_node.h
@@ -27,7 +27,7 @@ #include "cobalt/audio/audio_node_output.h" #include "cobalt/dom/dom_exception.h" #include "cobalt/dom/event_target.h" -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #include "cobalt/script/environment_settings.h" namespace cobalt { @@ -49,7 +49,7 @@ // (if it has any). // https://www.w3.org/TR/webaudio/#AudioNode-section class AudioNode : public dom::EventTarget { - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; public: AudioNode(script::EnvironmentSettings* settings, AudioContext* context); @@ -108,7 +108,7 @@ // Called when a new input node has been connected. virtual void OnInputNodeConnected() {} - virtual std::unique_ptr<ShellAudioBus> PassAudioBusFromSource( + virtual std::unique_ptr<AudioBus> PassAudioBusFromSource( int32 number_of_frames, SampleType sample_type, bool* finished) = 0; AudioLock* audio_lock() const { return audio_lock_.get(); }
diff --git a/src/cobalt/audio/audio_node_input.cc b/src/cobalt/audio/audio_node_input.cc index f8f5503..977d67e 100644 --- a/src/cobalt/audio/audio_node_input.cc +++ b/src/cobalt/audio/audio_node_input.cc
@@ -26,12 +26,12 @@ namespace { -typedef media::ShellAudioBus ShellAudioBus; +typedef media::AudioBus AudioBus; void MixAudioBufferBasedOnInterpretation( const float* speaker, const float* discrete, - const AudioNodeChannelInterpretation& interpretation, ShellAudioBus* source, - ShellAudioBus* output_audio_data) { + const AudioNodeChannelInterpretation& interpretation, AudioBus* source, + AudioBus* output_audio_data) { const float* kMatrix = interpretation == kAudioNodeChannelInterpretationSpeakers ? speaker : discrete; @@ -49,7 +49,7 @@ // Up down mix equations for mono, stereo, quad, 5.1: // https://www.w3.org/TR/webaudio/#ChannelLayouts void MixAudioBuffer(const AudioNodeChannelInterpretation& interpretation, - ShellAudioBus* source, ShellAudioBus* output_audio_data) { + AudioBus* source, AudioBus* output_audio_data) { DCHECK_GT(source->channels(), 0u); DCHECK_GT(output_audio_data->channels(), 0u); DCHECK(interpretation == kAudioNodeChannelInterpretationSpeakers || @@ -224,8 +224,8 @@ } } -void AudioNodeInput::FillAudioBus(ShellAudioBus* output_audio_bus, - bool* silence, bool* all_finished) { +void AudioNodeInput::FillAudioBus(AudioBus* output_audio_bus, bool* silence, + bool* all_finished) { DCHECK(silence); DCHECK(all_finished); @@ -247,7 +247,7 @@ for (std::set<AudioNodeOutput*>::iterator iter = outputs_.begin(); iter != outputs_.end(); ++iter) { bool finished = false; - std::unique_ptr<ShellAudioBus> audio_bus = (*iter)->PassAudioBusFromSource( + std::unique_ptr<AudioBus> audio_bus = (*iter)->PassAudioBusFromSource( static_cast<int32>(output_audio_bus->frames()), output_audio_bus->sample_type(), &finished); *all_finished &= finished;
diff --git a/src/cobalt/audio/audio_node_input.h b/src/cobalt/audio/audio_node_input.h index 74aca8b..1c5bee1 100644 --- a/src/cobalt/audio/audio_node_input.h +++ b/src/cobalt/audio/audio_node_input.h
@@ -20,7 +20,7 @@ #include "base/memory/ref_counted.h" #include "cobalt/audio/audio_buffer.h" -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" namespace cobalt { namespace audio { @@ -36,7 +36,7 @@ // number can change depending on the connection(s) made to the input. If the // input has no connections, then it has one channel which is silent. class AudioNodeInput : public base::RefCountedThreadSafe<AudioNodeInput> { - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; public: explicit AudioNodeInput(AudioNode* owner_node) : owner_node_(owner_node) {} @@ -50,8 +50,7 @@ // For each input, an AudioNode performs a mixing of all connections to that // input. FillAudioBus() performs that action. In the case of multiple // connections, it sums the result into |audio_bus|. - void FillAudioBus(ShellAudioBus* audio_bus, bool* silence, - bool* all_finished); + void FillAudioBus(AudioBus* audio_bus, bool* silence, bool* all_finished); private: AudioNode* const owner_node_;
diff --git a/src/cobalt/audio/audio_node_input_output_test.cc b/src/cobalt/audio/audio_node_input_output_test.cc index 970254a..41a2ca2 100644 --- a/src/cobalt/audio/audio_node_input_output_test.cc +++ b/src/cobalt/audio/audio_node_input_output_test.cc
@@ -27,18 +27,18 @@ #include "cobalt/script/typed_arrays.h" #include "testing/gtest/include/gtest/gtest.h" -// TODO: Consolidate ShellAudioBus creation code +// TODO: Consolidate AudioBus creation code namespace cobalt { namespace audio { -typedef media::ShellAudioBus ShellAudioBus; +typedef media::AudioBus AudioBus; constexpr int kRenderBufferSizeFrames = 32; class AudioDestinationNodeMock : public AudioNode, public AudioDevice::RenderCallback { - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; public: AudioDestinationNodeMock(script::EnvironmentSettings* settings, @@ -50,14 +50,15 @@ } // From AudioNode. - std::unique_ptr<ShellAudioBus> PassAudioBusFromSource( - int32 number_of_frames, SampleType sample_type, bool* finished) override { + std::unique_ptr<AudioBus> PassAudioBusFromSource(int32 number_of_frames, + SampleType sample_type, + bool* finished) override { NOTREACHED(); - return std::unique_ptr<ShellAudioBus>(); + return std::unique_ptr<AudioBus>(); } // From AudioDevice::RenderCallback. - void FillAudioBus(bool all_consumed, ShellAudioBus* audio_bus, + void FillAudioBus(bool all_consumed, AudioBus* audio_bus, bool* silence) override { AudioLock::AutoLock lock(audio_lock()); @@ -68,9 +69,9 @@ }; void FillAudioBusFromOneSource( - std::unique_ptr<ShellAudioBus> src_data, - const AudioNodeChannelInterpretation& interpretation, - ShellAudioBus* audio_bus, bool* silence) { + std::unique_ptr<AudioBus> src_data, + const AudioNodeChannelInterpretation& interpretation, AudioBus* audio_bus, + bool* silence) { dom::testing::StubEnvironmentSettings environment_settings; scoped_refptr<AudioContext> audio_context( @@ -139,11 +140,11 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -180,12 +181,12 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -219,12 +220,12 @@ src_data_in_float[i] = 50.0f; } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -254,12 +255,12 @@ src_data_in_float[i] = 50.0f; } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -292,12 +293,12 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -334,12 +335,12 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -376,12 +377,12 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -418,12 +419,12 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -460,12 +461,12 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -498,12 +499,12 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -536,12 +537,12 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -574,12 +575,12 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -612,12 +613,12 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -650,12 +651,12 @@ } } - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfFrames, src_data_in_float)); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; FillAudioBusFromOneSource(std::move(src_data), kInterpretation, @@ -691,8 +692,8 @@ } } - std::unique_ptr<ShellAudioBus> src_data_1(new ShellAudioBus( - kNumOfSrcChannels, kNumOfFrames_1, src_data_in_float_1)); + std::unique_ptr<AudioBus> src_data_1( + new AudioBus(kNumOfSrcChannels, kNumOfFrames_1, src_data_in_float_1)); scoped_refptr<AudioBufferSourceNode> source_1( audio_context->CreateBufferSource(environment_settings())); scoped_refptr<AudioBuffer> buffer_1( @@ -709,8 +710,8 @@ } } - std::unique_ptr<ShellAudioBus> src_data_2(new ShellAudioBus( - kNumOfSrcChannels, kNumOfFrames_2, src_data_in_float_2)); + std::unique_ptr<AudioBus> src_data_2( + new AudioBus(kNumOfSrcChannels, kNumOfFrames_2, src_data_in_float_2)); scoped_refptr<AudioBufferSourceNode> source_2( audio_context->CreateBufferSource(environment_settings())); scoped_refptr<AudioBuffer> buffer_2( @@ -726,9 +727,9 @@ source_1->Start(0, 0, NULL); source_2->Start(0, 0, NULL); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kPlanar)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kRenderBufferSizeFrames, + AudioBus::kFloat32, AudioBus::kPlanar)); audio_bus->ZeroAllFrames(); bool silence = true; destination->FillAudioBus(true, audio_bus.get(), &silence); @@ -788,9 +789,9 @@ scoped_refptr<AudioContext> audio_context( new AudioContext(environment_settings())); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kPlanar)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfChannels, kRenderBufferSizeFrames, AudioBus::kFloat32, + AudioBus::kPlanar)); audio_bus->ZeroAllFrames(); scoped_refptr<AudioBuffer> buffer( new AudioBuffer(audio_context->sample_rate(), std::move(audio_bus))); @@ -828,9 +829,9 @@ scoped_refptr<AudioContext> audio_context( new AudioContext(environment_settings())); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfChannels, kRenderBufferSizeFrames, - ShellAudioBus::kFloat32, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfChannels, kRenderBufferSizeFrames, AudioBus::kFloat32, + AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); scoped_refptr<AudioBuffer> buffer( new AudioBuffer(audio_context->sample_rate(), std::move(audio_bus))); @@ -868,9 +869,9 @@ scoped_refptr<AudioContext> audio_context( new AudioContext(environment_settings())); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfChannels, kRenderBufferSizeFrames, - ShellAudioBus::kInt16, ShellAudioBus::kPlanar)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfChannels, kRenderBufferSizeFrames, AudioBus::kInt16, + AudioBus::kPlanar)); audio_bus->ZeroAllFrames(); scoped_refptr<AudioBuffer> buffer( @@ -911,9 +912,9 @@ scoped_refptr<AudioContext> audio_context( new AudioContext(environment_settings())); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfChannels, kRenderBufferSizeFrames, - ShellAudioBus::kInt16, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfChannels, kRenderBufferSizeFrames, AudioBus::kInt16, + AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); scoped_refptr<AudioBuffer> buffer( @@ -966,9 +967,9 @@ for (size_t buffer_sample_rate : kBufferSampleRateArr) { for (SampleType sample_type : kSampleTypeArr) { - std::unique_ptr<ShellAudioBus> src_data( - new ShellAudioBus(kNumOfSrcChannels, kNumOfSrcFrames, sample_type, - ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> src_data( + new AudioBus(kNumOfSrcChannels, kNumOfSrcFrames, sample_type, + AudioBus::kInterleaved)); src_data->ZeroAllFrames(); scoped_refptr<AudioBuffer> buffer( new AudioBuffer(buffer_sample_rate, std::move(src_data))); @@ -988,9 +989,9 @@ source->Connect(destination, 0, 0, NULL); source->Start(0, 0, NULL); - std::unique_ptr<ShellAudioBus> audio_bus( - new ShellAudioBus(kNumOfDestChannels, kNumOfDestFrames, sample_type, - ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> audio_bus( + new AudioBus(kNumOfDestChannels, kNumOfDestFrames, sample_type, + AudioBus::kInterleaved)); audio_bus->ZeroAllFrames(); bool silence = true; destination->FillAudioBus(true, audio_bus.get(), &silence);
diff --git a/src/cobalt/audio/audio_node_output.cc b/src/cobalt/audio/audio_node_output.cc index 8ab0f43..ed6c507 100644 --- a/src/cobalt/audio/audio_node_output.cc +++ b/src/cobalt/audio/audio_node_output.cc
@@ -24,7 +24,7 @@ namespace cobalt { namespace audio { -typedef media::ShellAudioBus ShellAudioBus; +typedef media::AudioBus AudioBus; AudioNodeOutput::~AudioNodeOutput() { owner_node_->audio_lock()->AssertLocked(); @@ -57,7 +57,7 @@ } } -std::unique_ptr<ShellAudioBus> AudioNodeOutput::PassAudioBusFromSource( +std::unique_ptr<AudioBus> AudioNodeOutput::PassAudioBusFromSource( int32 number_of_frames, SampleType sample_type, bool* finished) { // This is called by Audio thread. owner_node_->audio_lock()->AssertLocked();
diff --git a/src/cobalt/audio/audio_node_output.h b/src/cobalt/audio/audio_node_output.h index 4122390..1774ce4 100644 --- a/src/cobalt/audio/audio_node_output.h +++ b/src/cobalt/audio/audio_node_output.h
@@ -22,7 +22,7 @@ #include "base/memory/ref_counted.h" #include "cobalt/audio/audio_buffer.h" #include "cobalt/audio/audio_helpers.h" -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" namespace cobalt { namespace audio { @@ -33,7 +33,7 @@ // This represents the output coming out of the AudioNode. // It may be connected to one or more AudioNodeInputs. class AudioNodeOutput : public base::RefCountedThreadSafe<AudioNodeOutput> { - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; public: explicit AudioNodeOutput(AudioNode* owner_node) : owner_node_(owner_node) {} @@ -44,9 +44,9 @@ void DisconnectAll(); - std::unique_ptr<ShellAudioBus> PassAudioBusFromSource(int32 number_of_frames, - SampleType sample_type, - bool* finished); + std::unique_ptr<AudioBus> PassAudioBusFromSource(int32 number_of_frames, + SampleType sample_type, + bool* finished); private: AudioNode* const owner_node_;
diff --git a/src/cobalt/base/localized_strings.cc b/src/cobalt/base/localized_strings.cc index 1c590a4..3388ca7 100644 --- a/src/cobalt/base/localized_strings.cc +++ b/src/cobalt/base/localized_strings.cc
@@ -17,8 +17,8 @@ #include <algorithm> #include "base/logging.h" +#include "starboard/common/file.h" #include "starboard/common/log.h" -#include "starboard/file.h" #include "starboard/system.h" #include "starboard/types.h"
diff --git a/src/cobalt/base/path_provider.cc b/src/cobalt/base/path_provider.cc index ae07949..6dfbbe7 100644 --- a/src/cobalt/base/path_provider.cc +++ b/src/cobalt/base/path_provider.cc
@@ -31,6 +31,9 @@ base::FilePath directory(path.get()); if (base::PathExists(directory) || base::CreateDirectory(directory)) { return directory; + } else { + DLOG(ERROR) << "Attempt to open or create this path failed: " + + directory.value(); } } return base::FilePath();
diff --git a/src/cobalt/black_box_tests/black_box_tests.py b/src/cobalt/black_box_tests/black_box_tests.py index 220c342..60f5596 100644 --- a/src/cobalt/black_box_tests/black_box_tests.py +++ b/src/cobalt/black_box_tests/black_box_tests.py
@@ -30,6 +30,7 @@ from starboard.tools import abstract_launcher from starboard.tools import build from starboard.tools import command_line +from starboard.tools import log_level _DISABLED_BLACKBOXTEST_CONFIGS = [ 'android-arm/devel', @@ -294,13 +295,7 @@ 'specified, all IPs will be allowed to connect.')) args, _ = parser.parse_known_args() - # This format matches Cobalt's console log format. - logging_format = ('[%(process)d:%(asctime)s.%(msecs)03d...:' - '%(levelname)s:%(filename)s(%(lineno)s)] %(message)s') - logging.basicConfig( - level=logging.INFO, format=logging_format, datefmt='%m%d/%H%M%S') - if args.verbose: - logging.getLogger().setLevel(logging.DEBUG) + log_level.InitializeLogging(args) test_object = BlackBoxTests(args.server_binding_address, args.proxy_address, args.proxy_port, args.test_name,
diff --git a/src/cobalt/black_box_tests/testdata/pointer_test.html b/src/cobalt/black_box_tests/testdata/pointer_test.html index 1f1b275..340e5da 100644 --- a/src/cobalt/black_box_tests/testdata/pointer_test.html +++ b/src/cobalt/black_box_tests/testdata/pointer_test.html
@@ -98,14 +98,10 @@ ['pointerover', 'top', 'bubbling'], ['pointerover', 'outer', 'bubbling'], ['pointerenter', 'top_two', 'at target'], - ['pointerenter', 'top', 'at target'], - ['pointerenter', 'outer', 'at target'], ['mouseover', 'top_two', 'at target'], ['mouseover', 'top', 'bubbling'], ['mouseover', 'outer', 'bubbling'], ['mouseenter', 'top_two', 'at target'], - ['mouseenter', 'top', 'at target'], - ['mouseenter', 'outer', 'at target'], // actions.move_to_element_with_offset(top_two, 10, 10).pause(_SLEEP_AFTER_MOVE_TIME) ['pointermove', 'top_two', 'at target'], ['pointermove', 'top', 'bubbling'], @@ -139,14 +135,10 @@ ['pointerover', 'top', 'bubbling'], ['pointerover', 'outer', 'bubbling'], ['pointerenter', 'top_one', 'at target'], - ['pointerenter', 'top', 'at target'], - ['pointerenter', 'outer', 'at target'], ['mouseover', 'top_one', 'at target'], ['mouseover', 'top', 'bubbling'], ['mouseover', 'outer', 'bubbling'], ['mouseenter', 'top_one', 'at target'], - ['mouseenter', 'top', 'at target'], - ['mouseenter', 'outer', 'at target'], // actions.click(top_three) ['pointerout', 'top_one', 'at target'], ['pointerout', 'top', 'bubbling'], @@ -166,14 +158,10 @@ ['pointerover', 'top', 'bubbling'], ['pointerover', 'outer', 'bubbling'], ['pointerenter', 'top_three', 'at target'], - ['pointerenter', 'top', 'at target'], - ['pointerenter', 'outer', 'at target'], ['mouseover', 'top_three', 'at target'], ['mouseover', 'top', 'bubbling'], ['mouseover', 'outer', 'bubbling'], ['mouseenter', 'top_three', 'at target'], - ['mouseenter', 'top', 'at target'], - ['mouseenter', 'outer', 'at target'], ['pointerdown', 'top_three', 'at target'], ['pointerdown', 'top', 'bubbling'], ['pointerdown', 'outer', 'bubbling'], @@ -208,14 +196,10 @@ ['pointerover', 'top', 'bubbling'], ['pointerover', 'outer', 'bubbling'], ['pointerenter', 'top_four', 'at target'], - ['pointerenter', 'top', 'at target'], - ['pointerenter', 'outer', 'at target'], ['mouseover', 'top_four', 'at target'], ['mouseover', 'top', 'bubbling'], ['mouseover', 'outer', 'bubbling'], ['mouseenter', 'top_four', 'at target'], - ['mouseenter', 'top', 'at target'], - ['mouseenter', 'outer', 'at target'], ['pointerdown', 'top_four', 'at target'], ['pointerdown', 'top', 'bubbling'], ['pointerdown', 'outer', 'bubbling'], @@ -257,14 +241,10 @@ ['pointerover', 'top', 'bubbling'], ['pointerover', 'outer', 'bubbling'], ['pointerenter', 'top_six', 'at target'], - ['pointerenter', 'top', 'at target'], - ['pointerenter', 'outer', 'at target'], ['mouseover', 'top_six', 'at target'], ['mouseover', 'top', 'bubbling'], ['mouseover', 'outer', 'bubbling'], ['mouseenter', 'top_six', 'at target'], - ['mouseenter', 'top', 'at target'], - ['mouseenter', 'outer', 'at target'], // actions.move_to_element(bottom_six).pause(_SLEEP_AFTER_MOVE_TIME) ['pointerout', 'top_six', 'at target'], ['pointerout', 'top', 'bubbling'], @@ -287,13 +267,11 @@ ['pointerover', 'outer', 'bubbling'], ['pointerenter', 'bottom_six', 'at target'], ['pointerenter', 'bottom', 'at target'], - ['pointerenter', 'outer', 'at target'], ['mouseover', 'bottom_six', 'at target'], ['mouseover', 'bottom', 'bubbling'], ['mouseover', 'outer', 'bubbling'], ['mouseenter', 'bottom_six', 'at target'], ['mouseenter', 'bottom', 'at target'], - ['mouseenter', 'outer', 'at target'], // actions.click(bottom_five) ['pointerout', 'bottom_six', 'at target'], ['pointerout', 'bottom', 'bubbling'], @@ -313,14 +291,10 @@ ['pointerover', 'bottom', 'bubbling'], ['pointerover', 'outer', 'bubbling'], ['pointerenter', 'bottom_five', 'at target'], - ['pointerenter', 'bottom', 'at target'], - ['pointerenter', 'outer', 'at target'], ['mouseover', 'bottom_five', 'at target'], ['mouseover', 'bottom', 'bubbling'], ['mouseover', 'outer', 'bubbling'], ['mouseenter', 'bottom_five', 'at target'], - ['mouseenter', 'bottom', 'at target'], - ['mouseenter', 'outer', 'at target'], ['pointerdown', 'bottom_five', 'at target'], ['pointerdown', 'bottom', 'bubbling'], ['pointerdown', 'outer', 'bubbling'], @@ -349,14 +323,10 @@ ['pointerover', 'bottom', 'bubbling'], ['pointerover', 'outer', 'bubbling'], ['pointerenter', 'bottom_four', 'at target'], - ['pointerenter', 'bottom', 'at target'], - ['pointerenter', 'outer', 'at target'], ['mouseover', 'bottom_four', 'at target'], ['mouseover', 'bottom', 'bubbling'], ['mouseover', 'outer', 'bubbling'], ['mouseenter', 'bottom_four', 'at target'], - ['mouseenter', 'bottom', 'at target'], - ['mouseenter', 'outer', 'at target'], ['pointerdown', 'bottom_four', 'at target'], ['pointerdown', 'bottom', 'bubbling'], ['pointerdown', 'outer', 'bubbling'], @@ -383,12 +353,8 @@ ['mousemove', 'bottom_two', 'at target'], ['pointerover', 'bottom_two', 'at target'], ['pointerenter', 'bottom_two', 'at target'], - ['pointerenter', 'bottom', 'at target'], - ['pointerenter', 'outer', 'at target'], ['mouseover', 'bottom_two', 'at target'], ['mouseenter', 'bottom_two', 'at target'], - ['mouseenter', 'bottom', 'at target'], - ['mouseenter', 'outer', 'at target'], // actions.move_to_element(bottom_one).pause(_SLEEP_AFTER_MOVE_TIME) ['pointerout', 'bottom_two', 'at target'], ['pointerleave', 'bottom_two', 'at target'], @@ -398,12 +364,8 @@ ['mousemove', 'bottom_one', 'at target'], ['pointerover', 'bottom_one', 'at target'], ['pointerenter', 'bottom_one', 'at target'], - ['pointerenter', 'bottom', 'at target'], - ['pointerenter', 'outer', 'at target'], ['mouseover', 'bottom_one', 'at target'], ['mouseenter', 'bottom_one', 'at target'], - ['mouseenter', 'bottom', 'at target'], - ['mouseenter', 'outer', 'at target'], // find_element_by_id(runner, 'end').click() ['pointerout', 'bottom_one', 'at target'], ['pointerleave', 'bottom_one', 'at target'], @@ -418,11 +380,9 @@ ['pointerover', 'end', 'at target'], ['pointerover', 'outer', 'bubbling'], ['pointerenter', 'end', 'at target'], - ['pointerenter', 'outer', 'at target'], ['mouseover', 'end', 'at target'], ['mouseover', 'outer', 'bubbling'], ['mouseenter', 'end', 'at target'], - ['mouseenter', 'outer', 'at target'], ['pointerdown', 'end', 'at target'], ['pointerdown', 'outer', 'bubbling'], ['mousedown', 'end', 'at target'], @@ -489,33 +449,72 @@ e.target.setPointerCapture(e.pointerId); } - function SetHandlers(event, classname, callback) { - var elements = document.getElementsByClassName(classname); + // If the event type has value 'type', then report an error if the + // 'name' property on the event target already has 'value'. Otherwise, + // set it to the 'value'. This is used to detect erroneous boundary + // events (enter/leave, over/out), and up/down event sequences on an + // element. + function TrackAndVerifyTargetState(event, type, name, value) { + if (event.type == type) { + if (event.target[name] == value) { + console.log('ERROR: ' + type + 'event received while ' + + name + ' == ' + event.target[name]); + assertTrue(event.target[name] != value); + } + event.target[name] = value; + } + } + + function CheckState(e) { + // Check the target element state when the event is 'at target'. + if (e.eventPhase == 2) { + // Verify that there is not a duplicated or missing event for enter, + // leave, over, out, up, or down. + TrackAndVerifyTargetState(e, 'mouseenter', 'mouseenter', true); + TrackAndVerifyTargetState(e, 'mouseleave', 'mouseenter', false); + TrackAndVerifyTargetState(e, 'mouseover', 'mouseover', true); + TrackAndVerifyTargetState(e, 'mouseout', 'mouseover', false); + TrackAndVerifyTargetState(e, 'mousedown', 'mousedown', true); + TrackAndVerifyTargetState(e, 'mouseup', 'mousedown', false); + + TrackAndVerifyTargetState(e, 'pointerenter', 'pointerenter', true); + TrackAndVerifyTargetState(e, 'pointerleave', 'pointerenter', false); + TrackAndVerifyTargetState(e, 'pointerover', 'pointerover', true); + TrackAndVerifyTargetState(e, 'pointerout', 'pointerover', false); + TrackAndVerifyTargetState(e, 'pointerdown', 'pointerdown', true); + TrackAndVerifyTargetState(e, 'pointerup', 'pointerdown', false); + } + } + + function SetHandlers(event, selector, callback) { + var elements = document.querySelectorAll(selector); for (var i = 0; i < elements.length; ++i) { elements[i].addEventListener(event, callback); } } - function SetAllHandlers(prefix, classname, callback) { - SetHandlers(prefix + 'enter', classname, callback); - SetHandlers(prefix + 'leave', classname, callback); - SetHandlers(prefix + 'over', classname, callback); - SetHandlers(prefix + 'out', classname, callback); - SetHandlers(prefix + 'down', classname, callback); - SetHandlers(prefix + 'up', classname, callback); - SetHandlers(prefix + 'move', classname, callback); + function SetAllHandlers(prefix, selector, callback) { + SetHandlers(prefix + 'enter', selector, callback); + SetHandlers(prefix + 'leave', selector, callback); + SetHandlers(prefix + 'over', selector, callback); + SetHandlers(prefix + 'out', selector, callback); + SetHandlers(prefix + 'down', selector, callback); + SetHandlers(prefix + 'up', selector, callback); + SetHandlers(prefix + 'move', selector, callback); } window.onload = function() { - SetAllHandlers('mouse', 'track', LogEvent); - SetAllHandlers('pointer', 'track', LogEvent); - SetHandlers('click', 'track', LogEvent); - SetAllHandlers('mouse', 'cancel', Cancel); - SetAllHandlers('pointer', 'cancel', Cancel); - SetAllHandlers('mouse', 'stop', Stop); - SetAllHandlers('pointer', 'stop', Stop); - SetHandlers('pointerdown', 'capture', Capture); - SetHandlers('click', 'end', EndTest); + SetAllHandlers('mouse', '.track', LogEvent); + SetAllHandlers('pointer', '.track', LogEvent); + SetHandlers('click', '.track', LogEvent); + SetAllHandlers('mouse', '.cancel', Cancel); + SetAllHandlers('pointer', '.cancel', Cancel); + SetAllHandlers('mouse', '.stop', Stop); + SetAllHandlers('pointer', '.stop', Stop); + SetHandlers('pointerdown', '.capture', Capture); + SetHandlers('click', '.end', EndTest); + SetAllHandlers('mouse', '*', CheckState); + SetAllHandlers('pointer', '*', CheckState); console.log("Setup finished"); setupFinished(); }
diff --git a/src/cobalt/black_box_tests/tests/pointer_test.py b/src/cobalt/black_box_tests/tests/pointer_test.py index 706bbc5..02e9a00 100644 --- a/src/cobalt/black_box_tests/tests/pointer_test.py +++ b/src/cobalt/black_box_tests/tests/pointer_test.py
@@ -44,8 +44,7 @@ class PointerTest(black_box_tests.BlackBoxTestCase): """Tests pointer and mouse event.""" - def test_simple(self): - + def test_pointer_events(self): try: with ThreadedWebServer( binding_address=self.GetBindingAddress()) as server:
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc index f0a72e0..27edd11 100644 --- a/src/cobalt/browser/application.cc +++ b/src/cobalt/browser/application.cc
@@ -1381,3 +1381,9 @@ } // namespace browser } // namespace cobalt + +const char* GetCobaltUserAgentString() { + static std::string ua = cobalt::browser::CreateUserAgentString( + cobalt::browser::GetUserAgentPlatformInfoFromSystem()); + return ua.c_str(); +}
diff --git a/src/cobalt/browser/application.h b/src/cobalt/browser/application.h index 2b93e86..6f8ed3c 100644 --- a/src/cobalt/browser/application.h +++ b/src/cobalt/browser/application.h
@@ -231,4 +231,9 @@ } // namespace browser } // namespace cobalt + +extern "C" { +SB_IMPORT const char* GetCobaltUserAgentString(); +} + #endif // COBALT_BROWSER_APPLICATION_H_
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc index 66b62b6..6d14fbe 100644 --- a/src/cobalt/browser/browser_module.cc +++ b/src/cobalt/browser/browser_module.cc
@@ -433,7 +433,8 @@ base::Unretained(this)), network_module_, GetViewportSize(), GetResourceProvider(), kLayoutMaxRefreshFrequencyInHz, - base::Bind(&BrowserModule::CreateDebugClient, base::Unretained(this)))); + base::Bind(&BrowserModule::CreateDebugClient, base::Unretained(this)), + base::Bind(&BrowserModule::OnMaybeFreeze, base::Unretained(this)))); lifecycle_observers_.AddObserver(debug_console_.get()); #endif // defined(ENABLE_DEBUGGER) @@ -563,17 +564,18 @@ DestroySplashScreen(base::TimeDelta()); if (options_.enable_splash_screen_on_reloads || main_web_module_generation_ == 1) { - base::Optional<std::string> key = SplashScreenCache::GetKeyForStartUrl(url); + splash_screen_cache_->SetUrl(url); if (fallback_splash_screen_url_ || - (key && splash_screen_cache_->IsSplashScreenCached(*key))) { + splash_screen_cache_->IsSplashScreenCached()) { splash_screen_.reset(new SplashScreen( application_state_, base::Bind(&BrowserModule::QueueOnSplashScreenRenderTreeProduced, base::Unretained(this)), network_module_, viewport_size, GetResourceProvider(), - kLayoutMaxRefreshFrequencyInHz, fallback_splash_screen_url_, url, + kLayoutMaxRefreshFrequencyInHz, fallback_splash_screen_url_, splash_screen_cache_.get(), - base::Bind(&BrowserModule::DestroySplashScreen, weak_this_))); + base::Bind(&BrowserModule::DestroySplashScreen, weak_this_), + base::Bind(&BrowserModule::OnMaybeFreeze, base::Unretained(this)))); lifecycle_observers_.AddObserver(splash_screen_.get()); } } @@ -629,6 +631,10 @@ options.debugger_state = debugger_state.get(); #endif // ENABLE_DEBUGGER + // Pass down this callback from to Web module. + options_.web_module_options.maybe_freeze_callback = + base::Bind(&BrowserModule::OnMaybeFreeze, base::Unretained(this)); + web_module_.reset(new WebModule( url, application_state_, base::Bind(&BrowserModule::QueueOnRenderTreeProduced, @@ -1466,6 +1472,7 @@ DCHECK(application_state_ == base::kApplicationStateBlurred); application_state_ = base::kApplicationStateConcealed; ConcealInternal(); + OnMaybeFreeze(); } void BrowserModule::Focus() { @@ -1795,6 +1802,35 @@ Unfreeze(GetResourceProvider())); } +void BrowserModule::OnMaybeFreeze() { + TRACE_EVENT0("cobalt::browser", "BrowserModule::MaybeFreeze()"); + if (base::MessageLoop::current() != self_message_loop_) { + self_message_loop_->task_runner()->PostTask( + FROM_HERE, + base::Bind(&BrowserModule::OnMaybeFreeze, base::Unretained(this))); + return; + } + + bool splash_screen_ready_to_freeze = splash_screen_ ? + splash_screen_->IsReadyToFreeze() : true; +#if defined(ENABLE_DEBUGGER) + bool debug_console_ready_to_freeze = debug_console_ ? + debug_console_->IsReadyToFreeze() : true; +#endif // defined(ENABLE_DEBUGGER) + bool web_module_ready_to_freeze = web_module_->IsReadyToFreeze(); + if (splash_screen_ready_to_freeze && +#if defined(ENABLE_DEBUGGER) + debug_console_ready_to_freeze && +#endif // defined(ENABLE_DEBUGGER) + web_module_ready_to_freeze) { +#if SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION || \ + SB_HAS(CONCEALED_STATE) + SbSystemRequestFreeze(); +#endif // SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION || + // SB_HAS(CONCEALED_STATE) + } +} + ViewportSize BrowserModule::GetViewportSize() { // We trust the renderer module for width and height the most, if it exists. if (renderer_module_) {
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h index 194810a..2d9b43f 100644 --- a/src/cobalt/browser/browser_module.h +++ b/src/cobalt/browser/browser_module.h
@@ -426,6 +426,11 @@ // the app state update. void UnfreezeInternal(); + // Check debug console, splash screen and web module if they are + // ready to freeze at Concealed state. If so, call SystemRequestFreeze + // to freeze Cobalt. + void OnMaybeFreeze(); + // Gets a viewport size to use for now. This may change depending on the // current application state. While concealed, this returns the requested // viewport size. If there was no requested viewport size, it returns a
diff --git a/src/cobalt/browser/debug_console.cc b/src/cobalt/browser/debug_console.cc index 0503509..5716112 100644 --- a/src/cobalt/browser/debug_console.cc +++ b/src/cobalt/browser/debug_console.cc
@@ -110,7 +110,8 @@ network::NetworkModule* network_module, const cssom::ViewportSize& window_dimensions, render_tree::ResourceProvider* resource_provider, float layout_refresh_rate, - const debug::CreateDebugClientCallback& create_debug_client_callback) { + const debug::CreateDebugClientCallback& create_debug_client_callback, + const base::Closure& maybe_freeze_callback) { mode_ = GetInitialMode(); WebModule::Options web_module_options; @@ -134,6 +135,10 @@ base::Bind(&CreateDebugHub, base::Bind(&DebugConsole::GetMode, base::Unretained(this)), create_debug_client_callback); + + // Pass down this callback from Browser module to Web module eventually. + web_module_options.maybe_freeze_callback = maybe_freeze_callback; + web_module_.reset(new WebModule( GURL(kInitialDebugConsoleUrl), initial_application_state, render_tree_produced_callback,
diff --git a/src/cobalt/browser/debug_console.h b/src/cobalt/browser/debug_console.h index 8d573e2..7983443 100644 --- a/src/cobalt/browser/debug_console.h +++ b/src/cobalt/browser/debug_console.h
@@ -51,7 +51,8 @@ const cssom::ViewportSize& window_dimensions, render_tree::ResourceProvider* resource_provider, float layout_refresh_rate, - const debug::CreateDebugClientCallback& create_debug_client_callback); + const debug::CreateDebugClientCallback& create_debug_client_callback, + const base::Closure& maybe_freeze_callback); ~DebugConsole(); // Filters a key event. @@ -109,6 +110,10 @@ void ReduceMemory() { web_module_->ReduceMemory(); } + bool IsReadyToFreeze() { + return web_module_->IsReadyToFreeze(); + } + private: void OnError(const GURL& url, const std::string& error) { LOG(ERROR) << error;
diff --git a/src/cobalt/browser/splash_screen.cc b/src/cobalt/browser/splash_screen.cc index 962142f..7d18340 100644 --- a/src/cobalt/browser/splash_screen.cc +++ b/src/cobalt/browser/splash_screen.cc
@@ -57,10 +57,10 @@ const cssom::ViewportSize& window_dimensions, render_tree::ResourceProvider* resource_provider, float layout_refresh_rate, const base::Optional<GURL>& fallback_splash_screen_url, - const GURL& initial_main_web_module_url, SplashScreenCache* splash_screen_cache, const base::Callback<void(base::TimeDelta)>& - on_splash_screen_shutdown_complete) + on_splash_screen_shutdown_complete, + const base::Closure& maybe_freeze_callback) : render_tree_produced_callback_(render_tree_produced_callback), self_message_loop_(base::MessageLoop::current()), on_splash_screen_shutdown_complete_(on_splash_screen_shutdown_complete), @@ -76,15 +76,10 @@ base::ThreadPriority::HIGHEST; base::Optional<GURL> url_to_pass = fallback_splash_screen_url; - // Use the cached URL rather than the passed in URL if it exists. - base::Optional<std::string> key = - SplashScreenCache::GetKeyForStartUrl(initial_main_web_module_url); DCHECK(fallback_splash_screen_url || - (key && splash_screen_cache && - splash_screen_cache->IsSplashScreenCached(*key))); - if (key && splash_screen_cache && - splash_screen_cache->IsSplashScreenCached(*key)) { - url_to_pass = GURL(loader::kCacheScheme + ("://" + *key)); + (splash_screen_cache && splash_screen_cache->IsSplashScreenCached())); + if (splash_screen_cache && splash_screen_cache->IsSplashScreenCached()) { + url_to_pass = splash_screen_cache->GetCachedSplashScreenUrl(); web_module_options.can_fetch_cache = true; web_module_options.splash_screen_cache = splash_screen_cache; } @@ -99,6 +94,9 @@ // module contents, make sure blending is enabled for its background. web_module_options.clear_window_with_background_color = false; + // Pass down this callback from Browser module to Web module eventually. + web_module_options.maybe_freeze_callback = maybe_freeze_callback; + DCHECK(url_to_pass); web_module_.reset(new WebModule( *url_to_pass, initial_application_state, render_tree_produced_callback_,
diff --git a/src/cobalt/browser/splash_screen.h b/src/cobalt/browser/splash_screen.h index d6e08a4..381280f 100644 --- a/src/cobalt/browser/splash_screen.h +++ b/src/cobalt/browser/splash_screen.h
@@ -42,10 +42,10 @@ render_tree::ResourceProvider* resource_provider, float layout_refresh_rate, const base::Optional<GURL>& fallback_splash_screen_url, - const GURL& initial_main_web_module_url, cobalt::browser::SplashScreenCache* splash_screen_cache, const base::Callback<void(base::TimeDelta)>& - on_splash_screen_shutdown_complete); + on_splash_screen_shutdown_complete, + const base::Closure& maybe_freeze_callback); ~SplashScreen(); void SetSize(const cssom::ViewportSize& viewport_size) { @@ -80,6 +80,8 @@ WebModule& web_module() { return *web_module_; } + bool IsReadyToFreeze() { return web_module_->IsReadyToFreeze(); } + private: // Run when window.close() is called by the WebModule. void OnWindowClosed();
diff --git a/src/cobalt/browser/splash_screen_cache.cc b/src/cobalt/browser/splash_screen_cache.cc index 43cb6f7..5cf8299 100644 --- a/src/cobalt/browser/splash_screen_cache.cc +++ b/src/cobalt/browser/splash_screen_cache.cc
@@ -23,10 +23,10 @@ #include "base/strings/string_util.h" #include "base/synchronization/lock.h" #include "cobalt/base/get_application_key.h" +#include "starboard/common/file.h" #include "starboard/common/string.h" #include "starboard/configuration_constants.h" #include "starboard/directory.h" -#include "starboard/file.h" namespace cobalt { namespace browser { @@ -59,10 +59,10 @@ base::AutoLock lock(lock_); } -bool SplashScreenCache::CacheSplashScreen(const std::string& key, - const std::string& content) const { +bool SplashScreenCache::CacheSplashScreen(const std::string& content) const { base::AutoLock lock(lock_); - if (key.empty()) { + base::Optional<std::string> key = GetKeyForStartUrl(url_); + if (!key) { return false; } @@ -76,10 +76,11 @@ kSbFileMaxPath)) { return false; } - if (!CreateDirsForKey(key)) { + if (!CreateDirsForKey(key.value())) { return false; } - std::string full_path = std::string(path.data()) + kSbFileSepString + key; + std::string full_path = + std::string(path.data()) + kSbFileSepString + key.value(); starboard::ScopedFile cache_file( full_path.c_str(), kSbFileCreateAlways | kSbFileWrite, NULL, NULL); @@ -87,15 +88,18 @@ static_cast<int>(content.size())) > 0; } -bool SplashScreenCache::IsSplashScreenCached(const std::string& key) const { +bool SplashScreenCache::IsSplashScreenCached() const { base::AutoLock lock(lock_); std::vector<char> path(kSbFileMaxPath, 0); if (!SbSystemGetPath(kSbSystemPathCacheDirectory, path.data(), kSbFileMaxPath)) { return false; } - std::string full_path = std::string(path.data()) + kSbFileSepString + key; - return !key.empty() && SbFileExists(full_path.c_str()); + base::Optional<std::string> key = GetKeyForStartUrl(url_); + if (!key) return false; + std::string full_path = + std::string(path.data()) + kSbFileSepString + key.value(); + return SbFileExists(full_path.c_str()); } int SplashScreenCache::ReadCachedSplashScreen(
diff --git a/src/cobalt/browser/splash_screen_cache.h b/src/cobalt/browser/splash_screen_cache.h index deacfc8..336d124 100644 --- a/src/cobalt/browser/splash_screen_cache.h +++ b/src/cobalt/browser/splash_screen_cache.h
@@ -20,6 +20,7 @@ #include "base/optional.h" #include "base/synchronization/lock.h" +#include "cobalt/loader/cache_fetcher.h" #include "url/gurl.h" namespace cobalt { @@ -36,25 +37,35 @@ SplashScreenCache(); // Cache the splash screen. - bool CacheSplashScreen(const std::string& key, - const std::string& content) const; + bool CacheSplashScreen(const std::string& content) const; // Read the cached the splash screen. int ReadCachedSplashScreen(const std::string& key, std::unique_ptr<char[]>* result) const; - // Determine if a splash screen is cached corresponding to the key. - bool IsSplashScreenCached(const std::string& key) const; + // Determine if a splash screen is cached corresponding to the current url. + bool IsSplashScreenCached() const; + // Set the URL of the currently requested splash screen. + void SetUrl(const GURL& url) { url_ = url; } + + // Get the cache location of the currently requested splash screen. + GURL GetCachedSplashScreenUrl() { + base::Optional<std::string> key = GetKeyForStartUrl(url_); + return GURL(loader::kCacheScheme + ("://" + *key)); + } + + private: // Get the key that corresponds to a starting URL. Optionally create // subdirectories along the path. static base::Optional<std::string> GetKeyForStartUrl(const GURL& url); - private: // Lock to protect access to the cache file. mutable base::Lock lock_; // Hash of the last read page contents. mutable uint32_t last_page_hash_; + // Latest url that was navigated to. + GURL url_; }; } // namespace browser
diff --git a/src/cobalt/browser/user_agent_string.cc b/src/cobalt/browser/user_agent_string.cc index 2e7f57d..8e973b5 100644 --- a/src/cobalt/browser/user_agent_string.cc +++ b/src/cobalt/browser/user_agent_string.cc
@@ -224,10 +224,15 @@ std::string os_name_and_version = platform_info.os_name_and_version; #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kUserAgentOsNameVersion)) { - os_name_and_version = - command_line->GetSwitchValueASCII(switches::kUserAgentOsNameVersion); + // Because we add Cobalt's user agent string to Crashpad before we actually + // start Cobalt, the command line won't be initialized when we first try to + // get the user agent string. + if (base::CommandLine::InitializedForCurrentProcess()) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kUserAgentOsNameVersion)) { + os_name_and_version = + command_line->GetSwitchValueASCII(switches::kUserAgentOsNameVersion); + } } #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc index 3f8186d..d852db5 100644 --- a/src/cobalt/browser/web_module.cc +++ b/src/cobalt/browser/web_module.cc
@@ -86,23 +86,18 @@ // deeper than this could be discarded, and will not be rendered. const int kDOMMaxElementDepth = 32; -bool CacheUrlContent(SplashScreenCache* splash_screen_cache, const GURL& url, +void CacheUrlContent(SplashScreenCache* splash_screen_cache, const std::string& content) { - base::Optional<std::string> key = SplashScreenCache::GetKeyForStartUrl(url); - if (key) { - return splash_screen_cache->SplashScreenCache::CacheSplashScreen(*key, - content); - } - return false; + splash_screen_cache->SplashScreenCache::CacheSplashScreen(content); } -base::Callback<bool(const GURL&, const std::string&)> CacheUrlContentCallback( +base::Callback<void(const std::string&)> CacheUrlContentCallback( SplashScreenCache* splash_screen_cache) { // This callback takes in first the url, then the content string. if (splash_screen_cache) { return base::Bind(CacheUrlContent, base::Unretained(splash_screen_cache)); } else { - return base::Callback<bool(const GURL&, const std::string&)>(); + return base::Callback<void(const std::string&)>(); } } @@ -242,6 +237,10 @@ void CancelSynchronousLoads(); + void IsReadyToFreeze(volatile bool* is_ready_to_freeze) { + *is_ready_to_freeze = !media_session_client_->is_active(); + } + private: class DocumentLoadedObserver; @@ -593,6 +592,8 @@ media_session_client_ = media_session::MediaSessionClient::Create(); media_session_client_->SetMediaPlayerFactory(data.web_media_player_factory); + media_session_client_->SetMaybeFreezeCallback( + data.options.maybe_freeze_callback); system_caption_settings_ = new cobalt::dom::captions::SystemCaptionSettings( environment_settings_.get()); @@ -1692,5 +1693,16 @@ base::Unretained(impl_.get()), callback)); } +bool WebModule::IsReadyToFreeze() { + DCHECK_NE(base::MessageLoop::current(), message_loop()); + + volatile bool is_ready_to_freeze = false; + message_loop()->task_runner()->PostBlockingTask( + FROM_HERE, base::Bind(&WebModule::Impl::IsReadyToFreeze, + base::Unretained(impl_.get()), + &is_ready_to_freeze)); + return is_ready_to_freeze; +} + } // namespace browser } // namespace cobalt
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h index cc09c00..afbb6a7 100644 --- a/src/cobalt/browser/web_module.h +++ b/src/cobalt/browser/web_module.h
@@ -270,6 +270,11 @@ // there is no state to restore. debug::backend::DebuggerState* debugger_state = nullptr; #endif // defined(ENABLE_DEBUGGER) + + // This callback is for checking the mediasession actions transitions. When + // there is no playback during Concealed state, we should provide a chance + // for Cobalt to freeze. + base::Closure maybe_freeze_callback; }; typedef layout::LayoutManager::LayoutResults LayoutResults; @@ -397,6 +402,9 @@ void RequestJavaScriptHeapStatistics( const JavaScriptHeapStatisticsCallback& callback); + // Indicate the web module is ready to freeze. + bool IsReadyToFreeze(); + private: // Data required to construct a WebModule, initialized in the constructor and // passed to |Initialize|.
diff --git a/src/cobalt/build/all.gyp b/src/cobalt/build/all.gyp index f798b39..79ece6f 100644 --- a/src/cobalt/build/all.gyp +++ b/src/cobalt/build/all.gyp
@@ -66,6 +66,7 @@ '<(DEPTH)/cobalt/network/network.gyp:*', '<(DEPTH)/cobalt/overlay_info/overlay_info.gyp:*', '<(DEPTH)/cobalt/render_tree/render_tree.gyp:*', + '<(DEPTH)/cobalt/renderer/backend/backend.gyp:graphics_system_test_deploy', '<(DEPTH)/cobalt/renderer/renderer.gyp:*', '<(DEPTH)/cobalt/renderer/sandbox/sandbox.gyp:*', '<(DEPTH)/cobalt/samples/simple_example/simple_example.gyp:*', @@ -89,7 +90,7 @@ '<(DEPTH)/net/net.gyp:net_unittests_deploy', '<(DEPTH)/sql/sql.gyp:sql_unittests_deploy', '<(DEPTH)/starboard/elf_loader/elf_loader.gyp:elf_loader_test_deploy', - '<(DEPTH)/starboard/loader_app/loader_app.gyp:loader_app', + '<(DEPTH)/starboard/loader_app/loader_app.gyp:loader_app_tests_deploy', '<(DEPTH)/starboard/nplb/nplb_evergreen_compat_tests/nplb_evergreen_compat_tests.gyp:nplb_evergreen_compat_tests_deploy', ], 'conditions': [
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id index 28196cb..a485246 100644 --- a/src/cobalt/build/build.id +++ b/src/cobalt/build/build.id
@@ -1 +1 @@ -278102 \ No newline at end of file +282262 \ No newline at end of file
diff --git a/src/cobalt/configuration/configuration.cc b/src/cobalt/configuration/configuration.cc index 1502037..9c5087c 100644 --- a/src/cobalt/configuration/configuration.cc +++ b/src/cobalt/configuration/configuration.cc
@@ -25,7 +25,8 @@ Configuration* Configuration::configuration_ = nullptr; Configuration* Configuration::GetInstance() { - return base::Singleton<Configuration>::get(); + return base::Singleton<Configuration, + base::LeakySingletonTraits<Configuration>>::get(); } Configuration::Configuration() {
diff --git a/src/cobalt/content/fonts/font_files/NotoColorEmoji.woff2 b/src/cobalt/content/fonts/font_files/NotoColorEmoji.woff2 index 9cac5c0..72a6830 100644 --- a/src/cobalt/content/fonts/font_files/NotoColorEmoji.woff2 +++ b/src/cobalt/content/fonts/font_files/NotoColorEmoji.woff2 Binary files differ
diff --git a/src/cobalt/demos/content/background-mode-demo/background-mode-demo.html b/src/cobalt/demos/content/background-mode-demo/background-mode-demo.html new file mode 100644 index 0000000..058300b --- /dev/null +++ b/src/cobalt/demos/content/background-mode-demo/background-mode-demo.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html> +<head> + <title>Loop Playback</title> + <style> + body { + background-color: rgb(255, 255, 255); + color: #0047ab; + font-size: 50px; + } + video { + transform: translateX(100px) rotate(3deg); + } + </style> +</head> +<body> + Loop Playback + <script type="text/javascript" src="background-mode-demo.js"></script> + <div>Playback Actions: + <span id='info' style='white-space: pre; background-color:#00FF00'></span> + </div> +</body> +</html>
diff --git a/src/cobalt/demos/content/background-mode-demo/background-mode-demo.js b/src/cobalt/demos/content/background-mode-demo/background-mode-demo.js new file mode 100644 index 0000000..6de9271 --- /dev/null +++ b/src/cobalt/demos/content/background-mode-demo/background-mode-demo.js
@@ -0,0 +1,188 @@ +// Copyright 2018 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. + +// The page simply plays an audio or a video stream in a loop, it can be used +// in the following forms: +// background-mode-demo.html&type=video +// background-mode-demo.html&type=audio +// If the stream is adaptive, it has to be fit in memory as this demo will +// download the whole stream at once. + +var video = null; +var type = null; + +let playlist = getPlaylist(); +let index = 0; + +var kAdaptiveAudioChunkSize = 720 * 1024; + +function downloadAndAppend(url, begin, end, source_buffer, callback) { + var xhr = new XMLHttpRequest; + xhr.open('GET', url, true); + xhr.responseType = 'arraybuffer'; + xhr.addEventListener('load', function(e) { + var onupdateend = function() { + source_buffer.removeEventListener('updateend', onupdateend); + callback(); + }; + source_buffer.addEventListener('updateend', onupdateend); + source_buffer.appendBuffer(new Uint8Array(e.target.response)); + }); + + xhr.setRequestHeader('Range', ('bytes=' + begin +'-' + end)); + xhr.send(); +} + +function createVideoElement() { + var video = document.createElement('video'); + video.autoplay = true; + video.style.width = '1280px'; + video.style.height = '720px'; + document.body.appendChild(video); + + return video; +} + +function onVideoEnded() { + startNextVideo(); +} + +function startAdaptiveVideo() { + video.src = ''; + video.load(); + var mediasource = new MediaSource; + mediasource.addEventListener('sourceopen', function () { + if (type == 'audio') { + var audio_source_buffer = mediasource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"'); + downloadAndAppend('../media-element-demo/dash-audio.mp4', 0, kAdaptiveAudioChunkSize * 10, audio_source_buffer, function () { + mediasource.endOfStream(); + }); + } + + if (type == 'video') { + var video_source_buffer = mediasource.addSourceBuffer('video/mp4; codecs="avc1.640028"'); + var audio_source_buffer = mediasource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"'); + downloadAndAppend('../media-element-demo/dash-video-1080p.mp4', 0, 15 * 1024 * 1024, video_source_buffer, function () { + video_source_buffer.abort(); + // Append the first two segments of the 240p video so we can see the transition. + downloadAndAppend('../media-element-demo/dash-audio.mp4', 0, kAdaptiveAudioChunkSize * 10, audio_source_buffer, function () { + mediasource.endOfStream(); + }); + }); + } + }) + + video.src = window.URL.createObjectURL(mediasource); + video.addEventListener('ended', onVideoEnded); +} + + +function startNextVideo() { + startAdaptiveVideo(); +} + +function main() { + var get_parameters = window.location.search.substr(1).split('&'); + for (var param of get_parameters) { + splitted = param.split('='); + if (splitted[0] == 'type') { + type = splitted[1]; + } + } + + if (type != 'audio' && type != 'video') { + throw "invalid type " + type; + } + + video = createVideoElement(); + startNextVideo(); + updateMetadata(); +} + +main(); + +// MeidaSession +function updateMetadata() { + let track = playlist[index]; + + navigator.mediaSession.metadata = new MediaMetadata({ + title: track.title, + artist: track.artist, + //artwork: track.artwork + }); + navigator.mediaSession.playbackState = "playing"; +} + +let defaultSkipTime = 10; + +navigator.mediaSession.setActionHandler('seekbackward', function(event) { + const skipTime = event.seekOffset || defaultSkipTime; + video.currentTime = Math.max(video.currentTime - skipTime, 0); + updatePositionState(); +}); + +navigator.mediaSession.setActionHandler('seekforward', function(event) { + const skipTime = event.seekOffset || defaultSkipTime; + video.currentTime = Math.min(video.currentTime + skipTime, video.duration); + updatePositionState(); +}); + +navigator.mediaSession.setActionHandler('play', function() { + log_info('TimeStamp: ' + getTime() + ' seconds' + ' play'); + video.play(); + navigator.mediaSession.playbackState = "playing"; +}); + +navigator.mediaSession.setActionHandler('pause', function() { + log_info('TimeStamp: ' + getTime() + ' seconds' + ' pause'); + video.pause(); + navigator.mediaSession.playbackState = "paused"; +}); + + +try { + navigator.mediaSession.setActionHandler('stop', function() { + log_info('TimeStamp: ' + getTime() + ' seconds' + ' stop'); + }); +} catch(error) { +} + +try { + navigator.mediaSession.setActionHandler('seekto', function(event) { + if (event.fastSeek && ('fastSeek' in video)) { + video.fastSeek(event.seekTime); + return; + } + video.currentTime = event.seekTime; + updatePositionState(); + }); +} catch(error) { +} + +function getPlaylist() { + return [{ + title: 'Background mode demo', + artist: 'Cobalt', + }]; +} + +function log_info(message) { + console.warn(message); + document.getElementById('info').innerHTML += message + '.\n'; +} + +function getTime() { + return Math.floor(Date.now() / 1000 | 0); +} +
diff --git a/src/cobalt/demos/content/media-element-demo/key-systems.html b/src/cobalt/demos/content/media-element-demo/key-systems.html new file mode 100644 index 0000000..7358ca5 --- /dev/null +++ b/src/cobalt/demos/content/media-element-demo/key-systems.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> + <title>Media Element Demo</title> + <style> + .title { + background-color: #FFF; + color: #0047ab; + font-size: 20px; + } + .query { + } + .result-success { + background-color: rgb(0, 128, 0); + } + .result-failure { + background-color: rgb(128, 0, 0); + } + body { + background-color: #FFF; + font-size: 20px; + } + </style> +</head> +<body> + <span class="title">Queries on Key Systems</span> + <script type="text/javascript" src="key-systems.js"></script> +</body> +</html>
diff --git a/src/cobalt/demos/content/media-element-demo/key-systems.js b/src/cobalt/demos/content/media-element-demo/key-systems.js new file mode 100644 index 0000000..ec8f149 --- /dev/null +++ b/src/cobalt/demos/content/media-element-demo/key-systems.js
@@ -0,0 +1,111 @@ +// 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. + +function getRepresentation(keySystem, audioMime, videoMime, encryptionScheme) { + var representation = keySystem; + if (typeof audioMime !== 'undefined') { + representation += ', ' + audioMime; + } + if (typeof videoMime !== 'undefined') { + representation += ', ' + videoMime; + } + if (typeof encryptionScheme !== 'undefined') { + representation += ', encryptionscheme="' + encryptionScheme + '"'; + } + return representation; +} + +function checkForSupport(keySystem, audioMime, videoMime, encryptionScheme, + expectedResult) { + var configs = [{ + initDataTypes: ['cenc', 'sinf', 'webm'], + audioCapabilities: [], + videoCapabilities: [], + }]; + if (typeof audioMime !== 'undefined') { + configs[0].audioCapabilities.push( + {contentType: audioMime, encryptionScheme: encryptionScheme}); + } + if (typeof videoMime !== 'undefined') { + configs[0].videoCapabilities.push( + {contentType: videoMime, encryptionScheme: encryptionScheme}); + } + var representation = getRepresentation(keySystem, audioMime, videoMime, + encryptionScheme); + navigator.requestMediaKeySystemAccess(keySystem, configs) + .then(onKeySystemAccess.bind(this, representation, expectedResult), + onFailure.bind(this, representation, expectedResult)); +} + +function addQueryResult(query, result, expectedResult) { + var row = document.createElement('div'); + + var cell = document.createElement('span'); + cell.className = 'query'; + cell.textContent = query + ' => '; + row.appendChild(cell); + + cell = document.createElement('span'); + cell.className = result == expectedResult ? 'result-success' : + 'result-failure'; + cell.textContent = result; + row.appendChild(cell); + + document.body.appendChild(row); +} + +function onKeySystemAccess(representation, expectedResult, keySystemAccess) { + addQueryResult(representation, 'supported', expectedResult); +} + +function onFailure(representation, expectedResult) { + addQueryResult(representation, 'not supported', expectedResult); +} + +checkForSupport('com.widevine.alpha.invalid', 'audio/mp4; codecs="mp4a.40.2"', + undefined, undefined, 'not supported'); +checkForSupport('com.widevine.alpha.invalid', undefined, + 'video/webm; codecs="vp9"', undefined, 'not supported'); + +// 'invalid-scheme' is not a valid scheme. +checkForSupport('com.widevine.alpha', 'audio/mp4; codecs="mp4a.40.2"', + undefined, 'invalid-scheme', 'not supported'); +checkForSupport('com.widevine.alpha', undefined, 'video/webm; codecs="vp9"', + 'invalid-scheme', 'not supported'); + +checkForSupport('com.widevine.alpha', 'audio/mp4; codecs="mp4a.40.2"', + undefined, undefined, 'supported'); +checkForSupport('com.widevine.alpha', undefined, 'video/webm; codecs="vp9"', + undefined, 'supported'); + +// Empty string is not a valid scheme. +checkForSupport('com.widevine.alpha', 'audio/mp4; codecs="mp4a.40.2"', + undefined, '', 'not supported'); +checkForSupport('com.widevine.alpha', undefined, 'video/webm; codecs="vp9"', + '', 'not supported'); + +checkForSupport('com.widevine.alpha', 'audio/mp4; codecs="mp4a.40.2"', + undefined, 'cenc', 'supported'); +checkForSupport('com.widevine.alpha', undefined, 'video/webm; codecs="vp9"', + 'cenc', 'supported'); + +checkForSupport('com.widevine.alpha', 'audio/mp4; codecs="mp4a.40.2"', + undefined, 'cbcs', 'supported'); +checkForSupport('com.widevine.alpha', undefined, 'video/webm; codecs="vp9"', + 'cbcs', 'supported'); + +checkForSupport('com.widevine.alpha', 'audio/mp4; codecs="mp4a.40.2"', + undefined, 'cbcs-1-9', 'supported'); +checkForSupport('com.widevine.alpha', undefined, 'video/webm; codecs="vp9"', + 'cbcs-1-9', 'supported');
diff --git a/src/cobalt/doc/resources/devtools-overlay-console-modes.png b/src/cobalt/doc/resources/devtools-overlay-console-modes.png new file mode 100644 index 0000000..5103358 --- /dev/null +++ b/src/cobalt/doc/resources/devtools-overlay-console-modes.png Binary files differ
diff --git a/src/cobalt/doc/web_debugging.md b/src/cobalt/doc/web_debugging.md index c4711db..5090e4f 100644 --- a/src/cobalt/doc/web_debugging.md +++ b/src/cobalt/doc/web_debugging.md
@@ -102,28 +102,146 @@ ### Console -Cobalt has two consoles: -* Overlay console in Cobalt itself (shown with ctrl-O or F1). -* Remote console shown in a connected DevTools session. +Cobalt has two types of consoles: + +* Overlay Console: shown at runtime of Cobalt. It has multiple mode that it + can cycle between as well: + * HUD + * HUD & Debug Console + * Media Console +* Remote Console: shown in a connected devtools session. Both console UIs show messages logged from JavaScript (with `console.log()`, etc.), and have a command line to evaluate arbitrary JavaScript in the context of the page being debugged. +#### Overlay Console + The overlay console also shows non-JavaScript logging from Cobalt itself, which is mostly interesting to Cobalt developers rather than web app developers. +The various modes of the overlay console are accessed by repeatedly pressing +"`F1`" or "`Ctrl+O`". They cycle in order between: none, HUD, HUD & Debug, and +Media. Alternatively, initial console state can be set with the +`--debug_console=off|hud|debug|media` command-line switch (`--debug_console=on` +is accepted as a legacy option and maps to "debug" setting). + + + +##### HUD overlay + +This brings up an overlay panel which does not block sending input to the +underlying Cobalt app. It serves to display real-time statistics (e.g. memory +usage) and configuration values (e.g. disabled codecs) of the Cobalt app in a +compact string. + +##### Debug Console overlay + +This overlay is interactive and it shows messages from Cobalt, along with logs +from Javacript `console.log()`. While it is active, you cannot interact directly +with the underlying page. + +Additionally, it can act as a JS interpreter that will evaluate arbitrary +expressions on the page being debugged. The output from these JS commands will +also be printed to the Debug console. + +Finally, it has some special debug commands which can be listed by calling +`d.help()`. They are provided by a debug helper object and the list of functions +are invoked by prepending either "`debug`" or "`d`". For example, you can +disable the vp9 codec manually for all future played videos in this session of +Cobalt by sending `debug.disable_media_codecs("vp9")` to the console. + +Note: you can clear the disabled media codecs by sending +`debug.disable_media_codecs("")`. The command takes a semicolon separated list +of codecs as the input list of codecs to disable. + +##### Media Console overlay + +The media console is a specialized console of the debug overlay system, for +playback and media related tasks. The current list of implemented features are: + +* Reading the play/pause state of the primary video +* Reading the current time and duration of the primary video +* Reading the playback rate of the primary video +* Reading the currently disabled codecs for the player +* Toggling between playing and pausing the primary video +* Setting the current playback rate between various presets for the primary + video +* Toggling the enabled/disabled state of the available codecs + +While the media console is shown, it is not possible to interact with the page +below it directly. + +Additionally, the console does not show any meaningful information or +interactions when no video is currently playing (all the readouts are blank or +undefined). A status message of “No primary video.” indicates there is no valid +player element on the current page. + +In the case of multiple videos playing (such as picture in picture), only the +primary (fullscreen) video’s information is shown and the controls are only +enabled for the primary video. + +The list of hotkeys and commands are dynamically generated as they are found to +be available on app startup. + +Basic always-enabled commands are (case-sensitive): + +* "`p`" Toggle the play/pause state +* "`]`" Increase the playback rate +* "`[`" Decrease the playback rate + +The above commands will take effect instantly for the currently playing video. +They have no effect if there is no video playing. + +The following commands are dynamically loaded based on the capability of the +system: + +* "`CTRL+NUM`" Enable/disable specific video codec +* "`ALT+NUM`" Enable/disable specific audio codec + +**Important:** Media Console cannot be used to directly select a specific codec for +playback. See the section below for rough outline of steps to work around this. + +The list of available codecs for any video is chosen based on the decoders on +the platform, and what formats YouTube itself serves. As a result, the only way +to get a particular codec to play is to disable all the options until the +desired codec is the one that is picked. Simply do the following procedure: + +* Pick the video you want to play. +* Enable “stats for nerds” (See [help page for + instructions](https://support.google.com/youtube/answer/7519898)). +* Write down the codecs that are chosen when playing the video, without any + codecs disabled (one for video, and one for audio). +* Disable the default codecs. +* Replay the same video from the browse screen. +* Repeat until you identify all codecs that are available for the video, until + the video is unable to be played. +* Use the above knowledge to disable the codecs to force the player into + choosing a particular codec, by process of elimination. + +**Important:** Disabled codecs only take effect when a video starts playing. +When you play a video, the current list of disabled codecs is used to select an +arbitrary enabled format. When you seek in the video, the disabled codecs list +does not take effect. Only when you exit the player and re-enter by playing a +video will any toggled codecs be affected. + +**Important:** Disabled codecs list is persistent for the app-run. If you +disable “av01”, then until you re-enable it, “av01” formats will never be +chosen. + +**Important:** If you disable all the available codecs, no video codec can be +selected and an error dialog will be shown. This means that YouTube does not +have the video in any other formats, outside of the codecs that are disabled. +The player reports that it cannot play the video in any of the available formats +so playback will fail here, which is intended. + +#### Remote Console + The console in DevTools is a richer UI that can show evaluated objects with an expander so you can dig in to their properties. Logging from JavaScript with `console.log()` can show objects and exceptions as well, in contrast to the text-only messages shown in the console overlay. -> There may be some things (e.g. timers) that still need to be hooked up to the -> V8 backend, so please file a bug if something isn't working as expected. - -> When built with MozJs instead of V8, the functionality of the console is -> limited to showing only text log messages. - Chrome docs: * https://developers.google.com/web/tools/chrome-devtools/console/
diff --git a/src/cobalt/dom/eme/media_key_system_media_capability.idl b/src/cobalt/dom/eme/media_key_system_media_capability.idl index 56e86d5..7f1da60 100644 --- a/src/cobalt/dom/eme/media_key_system_media_capability.idl +++ b/src/cobalt/dom/eme/media_key_system_media_capability.idl
@@ -16,7 +16,11 @@ dictionary MediaKeySystemMediaCapability { DOMString contentType = ""; + // TODO: Implement robustness as per // https://www.w3.org/TR/encrypted-media/#dom-mediakeysystemmediacapability-robustness. // DOMString robustness = ""; + + // https://wicg.github.io/encrypted-media-encryption-scheme/ + DOMString? encryptionScheme = null; };
diff --git a/src/cobalt/dom/html_element.cc b/src/cobalt/dom/html_element.cc index 80f7a7a..ea5606b 100644 --- a/src/cobalt/dom/html_element.cc +++ b/src/cobalt/dom/html_element.cc
@@ -79,6 +79,11 @@ // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex const int32 kUiNavFocusTabIndexThreshold = -2; +// Track which HTMLElement is currently focused by UI navigation so that +// redundant blur / focus events are not fired. Do not de-reference this +// variable -- it is only meant to identify objects. +const HTMLElement* g_ui_nav_focus_ = nullptr; + struct NonTrivialStaticFields { NonTrivialStaticFields() { cssom::PropertyKeyVector computed_style_invalidation_properties; @@ -1027,10 +1032,7 @@ // themselves still need to have their computed style updated, in case the // value of display is changed. if (computed_style()->display() == cssom::KeywordValue::GetNone()) { - if (ui_nav_item_) { - ui_nav_item_->SetEnabled(false); - ui_nav_item_ = nullptr; - } + ReleaseUiNavigationItem(); return; } @@ -1167,15 +1169,19 @@ directionality_ = base::nullopt; } -void HTMLElement::OnUiNavBlur() { Blur(); } +void HTMLElement::OnUiNavBlur() { + if (g_ui_nav_focus_ == this) { + g_ui_nav_focus_ = nullptr; + Blur(); + } +} void HTMLElement::OnUiNavFocus() { - // Ensure the focusing steps do not trigger the UI navigation item to - // force focus again. - if (!ui_nav_focusing_) { - ui_nav_focusing_ = true; + // Suppress the focus event if this is already focused -- i.e. the HTMLElement + // initiated the focus change that resulted in this call to OnUiNavFocus. + if (g_ui_nav_focus_ != this) { + g_ui_nav_focus_ = this; Focus(); - ui_nav_focusing_ = false; } } @@ -1211,12 +1217,7 @@ } HTMLElement::~HTMLElement() { - // Disable any associated navigation item to prevent callbacks during - // destruction. - if (ui_nav_item_) { - ui_nav_item_->SetEnabled(false); - ui_nav_item_ = nullptr; - } + ReleaseUiNavigationItem(); if (IsInDocument()) { dom_stat_tracker_->OnHtmlElementRemovedFromDocument(); @@ -1255,11 +1256,7 @@ // Node::OnRemovedFromDocument(). ClearRuleMatchingStateInternal(false /*invalidate_descendants*/); - // Release the associated navigation item as the object is no longer visible. - if (ui_nav_item_) { - ui_nav_item_->SetEnabled(false); - ui_nav_item_ = nullptr; - } + ReleaseUiNavigationItem(); } void HTMLElement::OnMutation() { InvalidateMatchingRulesRecursively(); } @@ -1340,6 +1337,45 @@ old_active_element->AsHTMLElement()->RunUnFocusingSteps(); } + // Custom, not in any spec. + // Set the focus item for the UI navigation system. Search up the DOM tree to + // find the nearest ancestor that is a UI navigation item if needed. Do this + // step before dispatching events as the event handlers may make UI navigation + // changes. + for (Node* node = this; node; node = node->parent_node()) { + Element* element = node->AsElement(); + if (!element) { + continue; + } + HTMLElement* html_element = element->AsHTMLElement(); + if (!html_element) { + continue; + } + if (!html_element->ui_nav_item_ || + html_element->ui_nav_item_->IsContainer()) { + continue; + } + if (g_ui_nav_focus_ == html_element) { + // UI navigation is already focused on the correct element. + break; + } + // Updating the g_ui_nav_focus_ has the additional effect of suppressing + // the Blur call for the previously focused HTMLElement and the Focus call + // for this HTMLElement as a result of OnUiNavBlur / OnUiNavFocus callbacks + // that result from initiating the UI navigation focus change. + g_ui_nav_focus_ = html_element; + // Only navigation items attached to the root container are interactable. + // If the item is not registered with a container, then force a layout to + // connect items to their containers and eventually to the root container. + scoped_refptr<ui_navigation::NavItem> nav_item = html_element->ui_nav_item_; + if (!nav_item->GetContainerItem()) { + // UI navigation items are updated as part of generating the render tree. + node_document()->DoSynchronousLayoutAndGetRenderTree(); + } + nav_item->Focus(); + break; + } + // focusin: A user agent MUST dispatch this event when an event target is // about to receive focus. This event type MUST be dispatched before the // element is given focus. The event target MUST be the element which is about @@ -1368,18 +1404,6 @@ // Custom, not in any spec. ClearRuleMatchingState(); - - // Set the focus item for the UI navigation system. - if (ui_nav_item_ && !ui_nav_item_->IsContainer() && !ui_nav_focusing_) { - // Only navigation items attached to the root container are interactable. - // If the item is not registered with a container, then force a layout to - // connect items to their containers and eventually to the root container. - if (!ui_nav_item_->GetContainerItem()) { - // UI navigation items are updated as part of generating the render tree. - node_document()->DoSynchronousLayoutAndGetRenderTree(); - } - ui_nav_item_->Focus(); - } } // Algorithm for RunUnFocusingSteps: @@ -2011,6 +2035,11 @@ } } + // Update the UI navigation item and invalidate layout boxes if needed. + if (!UpdateUiNavigationAndReturnIfLayoutBoxesAreValid()) { + invalidation_flags.invalidate_layout_boxes = true; + } + if (invalidation_flags.mark_descendants_as_display_none) { MarkNotDisplayedOnDescendants(); } @@ -2033,9 +2062,6 @@ } } - // Update the UI navigation item. - UpdateUiNavigationType(); - computed_style_valid_ = true; pseudo_elements_computed_styles_valid_ = true; } @@ -2096,7 +2122,7 @@ computed_style()->visibility() == cssom::KeywordValue::GetVisible(); } -void HTMLElement::UpdateUiNavigationType() { +bool HTMLElement::UpdateUiNavigationAndReturnIfLayoutBoxesAreValid() { base::Optional<ui_navigation::NativeItemType> ui_nav_item_type; if (computed_style()->overflow() == cssom::KeywordValue::GetAuto() || computed_style()->overflow() == cssom::KeywordValue::GetScroll()) { @@ -2115,14 +2141,19 @@ if (ui_nav_item_->GetType() == *ui_nav_item_type) { // Keep using the existing navigation item. ui_nav_item_->SetDir(ui_nav_item_dir); - return; + return true; } // The current navigation item isn't of the correct type. Disable it so // that callbacks won't be invoked for it. The object will be destroyed // when all references to it are released. + if (g_ui_nav_focus_ == this) { + g_ui_nav_focus_ = nullptr; + ui_nav_item_->UnfocusAll(); + } ui_nav_item_->SetEnabled(false); ui_nav_item_ = nullptr; } + ui_nav_item_ = new ui_navigation::NavItem( *ui_nav_item_type, base::Bind( @@ -2141,8 +2172,36 @@ FROM_HERE, base::Bind(&HTMLElement::OnUiNavScroll, base::AsWeakPtr(this)))); ui_nav_item_->SetDir(ui_nav_item_dir); + return false; } else if (ui_nav_item_) { // This navigation item is no longer relevant. + if (g_ui_nav_focus_ == this) { + g_ui_nav_focus_ = nullptr; + ui_nav_item_->UnfocusAll(); + } + ui_nav_item_->SetEnabled(false); + ui_nav_item_ = nullptr; + return false; + } + + return true; +} + +void HTMLElement::ReleaseUiNavigationItem() { + if (ui_nav_item_) { + // Make sure layout updates this element. + InvalidateLayoutBoxesOfNodeAndAncestors(); + if (ui_nav_item_->IsContainer()) { + // Make sure layout updates any focus items that may be in this container. + InvalidateLayoutBoxesOfDescendants(); + } + + // Disable the UI navigation item so it won't receive anymore callbacks + // while being released. + if (g_ui_nav_focus_ == this) { + g_ui_nav_focus_ = nullptr; + ui_nav_item_->UnfocusAll(); + } ui_nav_item_->SetEnabled(false); ui_nav_item_ = nullptr; }
diff --git a/src/cobalt/dom/html_element.h b/src/cobalt/dom/html_element.h index 09211ad..3994f6f 100644 --- a/src/cobalt/dom/html_element.h +++ b/src/cobalt/dom/html_element.h
@@ -419,7 +419,8 @@ void ClearRuleMatchingStateInternal(bool invalidate_descendants); // Update the UI navigation item type for this element. - void UpdateUiNavigationType(); + bool UpdateUiNavigationAndReturnIfLayoutBoxesAreValid(); + void ReleaseUiNavigationItem(); // Clear the list of active background images, and notify the animated image // tracker to stop the animations. @@ -515,12 +516,6 @@ // boxes without requiring a new layout. scoped_refptr<ui_navigation::NavItem> ui_nav_item_; - // This temporary flag is used to avoid a cycle on focus changes. When the - // HTML element receives focus, it must inform the UI navigation item. When - // the UI navigation item receives focus (either by calling SetFocus or by an - // update from the UI engine), it will tell the HTML element it was focused. - bool ui_nav_focusing_ = false; - // HTMLElement is a friend of Animatable so that animatable can insert and // remove animations into HTMLElement's set of animations. friend class DOMAnimatable;
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc index 12061ca..beb04c7 100644 --- a/src/cobalt/dom/html_media_element.cc +++ b/src/cobalt/dom/html_media_element.cc
@@ -251,10 +251,9 @@ DLOG_IF(ERROR, !key_system.empty()) << "CanPlayType() only accepts one parameter but (" << key_system << ") is passed as a second parameter."; - const bool kIsProgressive = true; auto support_type = - html_element_context()->can_play_type_handler()->CanPlayType( - mime_type, key_system, kIsProgressive); + html_element_context()->can_play_type_handler()->CanPlayProgressive( + mime_type); std::string result = ""; switch (support_type) { case kSbMediaSupportTypeNotSupported:
diff --git a/src/cobalt/dom/media_source.cc b/src/cobalt/dom/media_source.cc index e94f4c4..57817f4 100644 --- a/src/cobalt/dom/media_source.cc +++ b/src/cobalt/dom/media_source.cc
@@ -269,10 +269,8 @@ DOMSettings* dom_settings = base::polymorphic_downcast<DOMSettings*>(settings); DCHECK(dom_settings->can_play_type_handler()); - const bool kIsProgressive = false; SbMediaSupportType support_type = - dom_settings->can_play_type_handler()->CanPlayType(type.c_str(), "", - kIsProgressive); + dom_settings->can_play_type_handler()->CanPlayAdaptive(type.c_str(), ""); if (support_type == kSbMediaSupportTypeNotSupported) { LOG(INFO) << "MediaSource::IsTypeSupported(" << type << ") -> not supported/false";
diff --git a/src/cobalt/dom/navigator.cc b/src/cobalt/dom/navigator.cc index c57b886..a6d3ce3 100644 --- a/src/cobalt/dom/navigator.cc +++ b/src/cobalt/dom/navigator.cc
@@ -31,12 +31,117 @@ using cobalt::media_session::MediaSession; -namespace { -const char kLicensesRelativePath[] = "/licenses/licenses_cobalt.txt"; -} // namespace - namespace cobalt { namespace dom { +namespace { + +const char kLicensesRelativePath[] = "/licenses/licenses_cobalt.txt"; + +#if !defined(COBALT_BUILD_TYPE_GOLD) + +std::string ToString(const std::string& str, int indent_level); +std::string ToString(const eme::MediaKeySystemMediaCapability& capability, + int indent_level); +std::string ToString(const eme::MediaKeySystemConfiguration& configuration, + int indent_level); + +std::string GetIndent(int indent_level) { + std::string indent; + while (indent_level > 0) { + indent += " "; + --indent_level; + } + return indent; +} + +template <typename T> +std::string ToString(const script::Sequence<T>& sequence, int indent_level) { + std::stringstream ss; + + ss << "{\n"; + + for (auto iter = sequence.begin(); iter != sequence.end(); ++iter) { + ss << ToString(*iter, indent_level + 1) << ",\n"; + } + + ss << GetIndent(indent_level) << "}"; + + return ss.str(); +} + +std::string ToString(const std::string& str, int indent_level) { + return GetIndent(indent_level) + str; +} + +std::string ToString(const eme::MediaKeySystemMediaCapability& capability, + int indent_level) { + return GetIndent(indent_level) + '\'' + capability.content_type() + "'/'" + + capability.encryption_scheme().value_or("(null)") + '\''; +} + +std::string ToString(const eme::MediaKeySystemConfiguration& configuration, + int indent_level) { + DCHECK(configuration.has_label()); + + std::stringstream ss; + + ss << GetIndent(indent_level) << "label:'" << configuration.label() + << "': {\n"; + if (configuration.has_init_data_types()) { + ss << GetIndent(indent_level + 1) << "init_data_types: " + << ToString(configuration.init_data_types(), indent_level + 1) << ",\n"; + } + if (configuration.has_audio_capabilities()) { + ss << GetIndent(indent_level + 1) << "audio_capabilities: " + << ToString(configuration.audio_capabilities(), indent_level + 1) + << ",\n"; + } + if (configuration.has_video_capabilities()) { + ss << GetIndent(indent_level + 1) << "video_capabilities: " + << ToString(configuration.video_capabilities(), indent_level + 1) + << ",\n"; + } + ss << GetIndent(indent_level) << "}"; + + return ss.str(); +} + +#endif // !defined(COBALT_BUILD_TYPE_GOLD) + +// This function is used when the underlying SbMediaCanPlayMimeAndKeySystem() +// implementation doesn't support extra attributes on |key_system|, it makes +// decision based on the key system itself. +bool IsEncryptionSchemeSupportedByDefault( + const std::string& key_system, const std::string& encryption_scheme) { + // 1. Playready only supports "cenc". + if (key_system.find("playready") != key_system.npos) { + return encryption_scheme == "cenc"; + } + // 2. Fairplay only supports "cbcs" and "cbcs-1-9". + if (key_system.find("fairplay") != key_system.npos) { + return encryption_scheme == "cbcs" || encryption_scheme == "cbcs-1-9"; + } + // 3. Widevine only supports "cenc", "cbcs" and "cbcs-1-9". + if (key_system.find("widevine") != key_system.npos) { + return encryption_scheme == "cenc" || encryption_scheme == "cbcs" || + encryption_scheme == "cbcs-1-9"; + } + + // The key system is unknown, assume only "cenc" is supported. + return encryption_scheme == "cenc"; +} + +bool CanPlay(const media::CanPlayTypeHandler& can_play_type_handler, + const std::string& content_type, const std::string& key_system) { + auto can_play_result = can_play_type_handler.CanPlayAdaptive( + content_type.c_str(), key_system.c_str()); + LOG_IF(INFO, can_play_result == kSbMediaSupportTypeMaybe) + << "CanPlayAdaptive() returns \"maybe\"."; + return can_play_result == kSbMediaSupportTypeProbably || + can_play_result == kSbMediaSupportTypeMaybe; +} + +} // namespace Navigator::Navigator( script::EnvironmentSettings* settings, const std::string& user_agent, @@ -123,17 +228,16 @@ return media_session_; } -namespace { - +// TODO: Move the following two functions to the bottom of the file, in sync +// with the order of declaration. // See // https://www.w3.org/TR/encrypted-media/#get-supported-capabilities-for-audio-video-type. base::Optional<script::Sequence<MediaKeySystemMediaCapability>> -TryGetSupportedCapabilities( +Navigator::TryGetSupportedCapabilities( + const media::CanPlayTypeHandler& can_play_type_handler, const std::string& key_system, const script::Sequence<MediaKeySystemMediaCapability>& - requested_media_capabilities, - const media::CanPlayTypeHandler* can_play_type_handler) { - DCHECK(can_play_type_handler); + requested_media_capabilities) { // 2. Let supported media capabilities be an empty sequence of // MediaKeySystemMediaCapability dictionaries. script::Sequence<MediaKeySystemMediaCapability> supported_media_capabilities; @@ -152,17 +256,10 @@ // 3.13. If the user agent and [CDM] implementation definitely support // playback of encrypted media data for the combination of container, // media types [...]: - const bool kIsProgressive = false; - if (can_play_type_handler->CanPlayType( - content_type.c_str(), key_system.c_str(), kIsProgressive) == - kSbMediaSupportTypeProbably) { - LOG(INFO) << "Navigator::RequestMediaKeySystemAccess(" << content_type - << ", " << key_system << ") -> supported"; + if (CanPlayWithCapability(can_play_type_handler, key_system, + requested_media_capability)) { // 3.13.1. Add requested media capability to supported media capabilities. supported_media_capabilities.push_back(requested_media_capability); - } else { - LOG(INFO) << "Navigator::RequestMediaKeySystemAccess(" << content_type - << ", " << key_system << ") -> not supported"; } } // 4. If supported media capabilities is empty, return null. @@ -179,10 +276,11 @@ // is always given and go straight to "3.1.1.2 Get Supported Configuration and // Consent". See // https://www.w3.org/TR/encrypted-media/#get-supported-configuration-and-consent. -base::Optional<eme::MediaKeySystemConfiguration> TryGetSupportedConfiguration( +base::Optional<eme::MediaKeySystemConfiguration> +Navigator::TryGetSupportedConfiguration( + const media::CanPlayTypeHandler& can_play_type_handler, const std::string& key_system, - const eme::MediaKeySystemConfiguration& candidate_configuration, - const media::CanPlayTypeHandler* can_play_type_handler) { + const eme::MediaKeySystemConfiguration& candidate_configuration) { // 1. Let accumulated configuration be a new MediaKeySystemConfiguration // dictionary. eme::MediaKeySystemConfiguration accumulated_configuration; @@ -225,8 +323,8 @@ // Supported Capabilities for Audio/Video Type" algorithm. base::Optional<script::Sequence<MediaKeySystemMediaCapability>> maybe_video_capabilities = TryGetSupportedCapabilities( - key_system, candidate_configuration.video_capabilities(), - can_play_type_handler); + can_play_type_handler, key_system, + candidate_configuration.video_capabilities()); // 16.2. If video capabilities is null, return NotSupported. if (!maybe_video_capabilities) { return base::nullopt; @@ -249,8 +347,8 @@ // Supported Capabilities for Audio/Video Type" algorithm. base::Optional<script::Sequence<MediaKeySystemMediaCapability>> maybe_audio_capabilities = TryGetSupportedCapabilities( - key_system, candidate_configuration.audio_capabilities(), - can_play_type_handler); + can_play_type_handler, key_system, + candidate_configuration.audio_capabilities()); // 17.2. If audio capabilities is null, return NotSupported. if (!maybe_audio_capabilities) { return base::nullopt; @@ -269,8 +367,6 @@ return accumulated_configuration; } -} // namespace - // See // https://www.w3.org/TR/encrypted-media/#dom-navigator-requestmediakeysystemaccess. script::Handle<Navigator::InterfacePromise> @@ -286,6 +382,12 @@ script_value_factory_ ->CreateInterfacePromise<scoped_refptr<eme::MediaKeySystemAccess>>(); +#if !defined(COBALT_BUILD_TYPE_GOLD) + LOG(INFO) << "Navigator.RequestMediaKeySystemAccess() called with '" + << key_system << "', and\n" + << ToString(supported_configurations, 0); +#endif // !defined(COBALT_BUILD_TYPE_GOLD) + // 1. If |keySystem| is the empty string, return a promise rejected // with a newly created TypeError. // 2. If |supportedConfigurations| is empty, return a promise rejected @@ -302,14 +404,19 @@ // 6.3.3. If supported configuration is not NotSupported: base::Optional<eme::MediaKeySystemConfiguration> maybe_supported_configuration = TryGetSupportedConfiguration( - key_system, supported_configurations.at(configuration_index), - dom_settings->can_play_type_handler()); + *dom_settings->can_play_type_handler(), key_system, + supported_configurations.at(configuration_index)); if (maybe_supported_configuration) { // 6.3.3.1. Let access be a new MediaKeySystemAccess object. scoped_refptr<eme::MediaKeySystemAccess> media_key_system_access( new eme::MediaKeySystemAccess(key_system, *maybe_supported_configuration, script_value_factory_)); +#if !defined(COBALT_BUILD_TYPE_GOLD) + LOG(INFO) << "Navigator.RequestMediaKeySystemAccess() resolved with '" + << media_key_system_access->key_system() << "', and\n" + << ToString(media_key_system_access->GetConfiguration(), 0); +#endif // !defined(COBALT_BUILD_TYPE_GOLD) // 6.3.3.2. Resolve promise. promise->Resolve(media_key_system_access); return promise; @@ -334,5 +441,115 @@ tracer->Trace(system_caption_settings_); } +bool Navigator::CanPlayWithCapability( + const media::CanPlayTypeHandler& can_play_type_handler, + const std::string& key_system, + const MediaKeySystemMediaCapability& media_capability) { + const std::string& content_type = media_capability.content_type(); + + // There is no encryption scheme specified, check directly. + if (!media_capability.encryption_scheme().has_value()) { + if (CanPlay(can_play_type_handler, content_type, key_system)) { + LOG(INFO) << "Navigator::RequestMediaKeySystemAccess(" << content_type + << ", " << key_system << ") -> supported"; + return true; + } + LOG(INFO) << "Navigator::RequestMediaKeySystemAccess(" << content_type + << ", " << key_system << ") -> not supported"; + return false; + } + + if (!key_system_with_attributes_supported_.has_value()) { + if (!CanPlay(can_play_type_handler, content_type, key_system)) { + // If the check on the basic key system fails, we don't even bother to + // check if it supports key system with attributes. + LOG(INFO) << "Navigator::RequestMediaKeySystemAccess(" << content_type + << ", " << key_system << ") -> not supported"; + return false; + } + auto key_system_with_invalid_attribute = + std::string(key_system) + "; invalid_attributes=\"value\""; + // If an implementation supports attributes, it should ignore unknown + // attributes and return true, as the key system has been verified to be + // supported above. + key_system_with_attributes_supported_ = CanPlay( + can_play_type_handler, content_type, key_system_with_invalid_attribute); + if (key_system_with_attributes_supported_.value()) { + LOG(INFO) << "Navigator::RequestMediaKeySystemAccess() will use key" + << " system with attributes."; + } else { + LOG(INFO) << "Navigator::RequestMediaKeySystemAccess() won't use key" + << " system with attributes."; + } + } + + DCHECK(key_system_with_attributes_supported_.has_value()); + + // As a key system with attributes support is optional, and the logic to + // determine whether the encryptionScheme is supported can be quite different + // depending on whether this is supported, we encapsulate the logic into two + // different functions. + if (key_system_with_attributes_supported_.value()) { + return CanPlayWithAttributes(can_play_type_handler, content_type, + key_system, + media_capability.encryption_scheme().value()); + } + + return CanPlayWithoutAttributes(can_play_type_handler, content_type, + key_system, + media_capability.encryption_scheme().value()); +} + +bool Navigator::CanPlayWithoutAttributes( + const media::CanPlayTypeHandler& can_play_type_handler, + const std::string& content_type, const std::string& key_system, + const std::string& encryption_scheme) { + DCHECK(key_system_with_attributes_supported_.has_value()); + DCHECK(!key_system_with_attributes_supported_.value()); + + if (!IsEncryptionSchemeSupportedByDefault(key_system, encryption_scheme)) { + LOG(INFO) << "Navigator::RequestMediaKeySystemAccess() rejects " + << key_system << " because encryptionScheme \"" + << encryption_scheme << "\" is not supported."; + return false; + } + + if (CanPlay(can_play_type_handler, content_type, key_system)) { + LOG(INFO) << "Navigator::RequestMediaKeySystemAccess(" << content_type + << ", " << key_system << ") with encryptionScheme \"" + << encryption_scheme << "\" -> supported"; + return true; + } + + LOG(INFO) << "Navigator::RequestMediaKeySystemAccess(" << content_type << ", " + << key_system << ") with encryptionScheme \"" << encryption_scheme + << "\" -> not supported"; + return false; +} + +bool Navigator::CanPlayWithAttributes( + const media::CanPlayTypeHandler& can_play_type_handler, + const std::string& content_type, const std::string& key_system, + const std::string& encryption_scheme) { + DCHECK(key_system_with_attributes_supported_.has_value()); + DCHECK(key_system_with_attributes_supported_.value()); + + auto key_system_with_attributes = + key_system + "; encryptionscheme=\"" + encryption_scheme + '"'; + + if (CanPlay(can_play_type_handler, content_type, + key_system_with_attributes)) { + LOG(INFO) << "Navigator::RequestMediaKeySystemAccess(" << content_type + << ", " << key_system << ") with encryptionScheme \"" + << encryption_scheme << "\" -> supported"; + return true; + } + + LOG(INFO) << "Navigator::RequestMediaKeySystemAccess(" << content_type << ", " + << key_system << ") with encryptionScheme \"" << encryption_scheme + << "\" -> not supported"; + return false; +} + } // namespace dom } // namespace cobalt
diff --git a/src/cobalt/dom/navigator.h b/src/cobalt/dom/navigator.h index 10a417d..1489f78 100644 --- a/src/cobalt/dom/navigator.h +++ b/src/cobalt/dom/navigator.h
@@ -18,6 +18,7 @@ #include <string> #include "base/memory/ref_counted.h" +#include "base/optional.h" #include "cobalt/dom/captions/system_caption_settings.h" #include "cobalt/dom/eme/media_key_system_configuration.h" #include "cobalt/dom/mime_type_array.h" @@ -26,6 +27,7 @@ #include "cobalt/media_session/media_session.h" #include "cobalt/script/promise.h" #include "cobalt/script/script_value_factory.h" +#include "cobalt/script/sequence.h" #include "cobalt/script/wrappable.h" namespace cobalt { @@ -84,6 +86,33 @@ private: ~Navigator() override {} + base::Optional<script::Sequence<MediaKeySystemMediaCapability>> + TryGetSupportedCapabilities( + const media::CanPlayTypeHandler& can_play_type_handler, + const std::string& key_system, + const script::Sequence<MediaKeySystemMediaCapability>& + requested_media_capabilities); + + base::Optional<eme::MediaKeySystemConfiguration> TryGetSupportedConfiguration( + const media::CanPlayTypeHandler& can_play_type_handler, + const std::string& key_system, + const eme::MediaKeySystemConfiguration& candidate_configuration); + + bool CanPlayWithCapability( + const media::CanPlayTypeHandler& can_play_type_handler, + const std::string& key_system, + const MediaKeySystemMediaCapability& media_capability); + + bool CanPlayWithoutAttributes( + const media::CanPlayTypeHandler& can_play_type_handler, + const std::string& content_type, const std::string& key_system, + const std::string& encryption_scheme); + + bool CanPlayWithAttributes( + const media::CanPlayTypeHandler& can_play_type_handler, + const std::string& content_type, const std::string& key_system, + const std::string& encryption_scheme); + std::string user_agent_; std::string language_; scoped_refptr<MimeTypeArray> mime_types_; @@ -93,6 +122,7 @@ scoped_refptr<cobalt::dom::captions::SystemCaptionSettings> system_caption_settings_; script::ScriptValueFactory* script_value_factory_; + base::Optional<bool> key_system_with_attributes_supported_; DISALLOW_COPY_AND_ASSIGN(Navigator); };
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc index d4ecd45..a667e9e 100644 --- a/src/cobalt/dom/window.cc +++ b/src/cobalt/dom/window.cc
@@ -710,7 +710,7 @@ return; } DLOG(INFO) << "Caching splash screen for URL " << location()->url(); - splash_screen_cache_callback_.Run(location()->url(), content); + splash_screen_cache_callback_.Run(content); } const scoped_refptr<OnScreenKeyboard>& Window::on_screen_keyboard() const {
diff --git a/src/cobalt/dom/window.h b/src/cobalt/dom/window.h index a590389..3b3976f 100644 --- a/src/cobalt/dom/window.h +++ b/src/cobalt/dom/window.h
@@ -121,7 +121,7 @@ // close() was called. typedef base::Callback<void(base::TimeDelta)> CloseCallback; typedef UrlRegistry<MediaSource> MediaSourceRegistry; - typedef base::Callback<bool(const GURL&, const std::string&)> CacheCallback; + typedef base::Callback<void(const std::string&)> CacheCallback; enum ClockType { kClockTypeTestRunner,
diff --git a/src/cobalt/extension/media_session.h b/src/cobalt/extension/media_session.h index efb9f17..dccbd42 100644 --- a/src/cobalt/extension/media_session.h +++ b/src/cobalt/extension/media_session.h
@@ -25,13 +25,13 @@ #define kCobaltExtensionMediaSessionName "dev.cobalt.extension.MediaSession" -enum CobaltExtensionPlaybackState { - kCobaltExtensionPlaying = 0, - kCobaltExtensionPaused = 1, - kCobaltExtensionNone = 2 -}; +typedef enum CobaltExtensionMediaSessionPlaybackState { + kCobaltExtensionMediaSessionNone = 0, + kCobaltExtensionMediaSessionPaused = 1, + kCobaltExtensionMediaSessionPlaying = 2 +} CobaltExtensionMediaSessionPlaybackState; -enum CobaltExtensionMediaSessionAction { +typedef enum CobaltExtensionMediaSessionAction { kCobaltExtensionMediaSessionActionPlay, kCobaltExtensionMediaSessionActionPause, kCobaltExtensionMediaSessionActionSeekbackward, @@ -44,7 +44,7 @@ // Not part of spec, but used in Cobalt implementation. kCobaltExtensionMediaSessionActionNumActions, -}; +} CobaltExtensionMediaSessionAction; typedef struct CobaltExtensionMediaImage { // These fields are null-terminated strings copied over from IDL. @@ -63,6 +63,20 @@ size_t artwork_count; } CobaltExtensionMediaMetadata; +typedef struct CobaltExtensionMediaSessionActionDetails { + CobaltExtensionMediaSessionAction action; + + // Seek time/offset are non-negative. Negative value signifies "unset". + double seek_offset; + double seek_time; + + bool fast_seek; +} CobaltExtensionMediaSessionActionDetails; + +typedef void (*CobaltExtensionMediaSessionUpdatePlatformPlaybackStateCallback)( + CobaltExtensionMediaSessionPlaybackState state, void* callback_context); +typedef void (*CobaltExtensionMediaSessionInvokeActionCallback)( + CobaltExtensionMediaSessionActionDetails details, void* callback_context); // This struct and all its members should only be used for piping data to each // platform's implementation of OnMediaSessionStateChanged and they are only @@ -70,11 +84,21 @@ // will be referenced later. typedef struct CobaltExtensionMediaSessionState { SbTimeMonotonic duration; - enum CobaltExtensionPlaybackState actual_playback_state; + CobaltExtensionMediaSessionPlaybackState actual_playback_state; bool available_actions[kCobaltExtensionMediaSessionActionNumActions]; - CobaltExtensionMediaMetadata metadata; + CobaltExtensionMediaMetadata* metadata; double actual_playback_rate; SbTimeMonotonic current_playback_position; + + // Callback to MediaSessionClient::UpdatePlatformPlaybackState for when the + // platform updates state. + CobaltExtensionMediaSessionUpdatePlatformPlaybackStateCallback + update_platform_playback_state_callback; + + // Callback to MediaSessionClient::InvokeAction for when the platform handles + // a new media action. + void* callback_context; + CobaltExtensionMediaSessionInvokeActionCallback invoke_action_callback; } CobaltExtensionMediaSessionState; typedef struct CobaltExtensionMediaSessionApi { @@ -92,8 +116,17 @@ } CobaltExtensionMediaSessionApi; +inline void CobaltExtensionMediaSessionActionDetailsInit( + CobaltExtensionMediaSessionActionDetails* details, + CobaltExtensionMediaSessionAction action) { + details->action = action; + details->seek_offset = -1.0; + details->seek_time = -1.0; + details->fast_seek = false; +} + #ifdef __cplusplus } // extern "C" #endif -#endif // COBALT_EXTENSION_MEDIA_SESSION_H_ \ No newline at end of file +#endif // COBALT_EXTENSION_MEDIA_SESSION_H_
diff --git a/src/cobalt/fetch/embedded_scripts/fetch.js b/src/cobalt/fetch/embedded_scripts/fetch.js index ac5a7a3..ec89191 100644 --- a/src/cobalt/fetch/embedded_scripts/fetch.js +++ b/src/cobalt/fetch/embedded_scripts/fetch.js
@@ -1,22 +1,22 @@ -'use strict';(function(c){function E(a){"string"!==typeof a&&(a=String(a));if(/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(a))throw new g("Invalid character in header field name");return a.toLowerCase()}function Q(a){"string"!==typeof a&&(a=String(a));var b;var d=0;for(b=a.length;d<b;d++){var e=a.charCodeAt(d);if(9!==e&&10!==e&&13!==e&&32!==e)break}for(b=a.length-1;b>d&&(e=a.charCodeAt(b),9===e||10===e||13===e||32===e);b--);a=a.substring(d,b+1);d=0;for(b=a.length;d<b;d++)if(e=a.charCodeAt(d),256<=e||0===e|| -10===e||13===e)throw new g("Invalid character in header field value");return a}function W(a,b){throw new g("Immutable header cannot be modified");}function X(a,b){return!1}function Y(a,b){a=a.toLowerCase();return-1<Z.indexOf(a)||a.startsWith("proxy-")||a.startsWith("sec-")?!0:!1}function aa(a,b){a=a.toLowerCase();return-1<ba.indexOf(a)||"content-type"===a&&(b=b.split(";")[0].toLowerCase(),-1<ca.indexOf(b))?!1:!0}function L(a,b){return-1<da.indexOf(a.toLowerCase())?!0:!1}function h(a){this[l]=new I; -void 0===this[v]&&(this[v]=X);if(void 0!==a){if(null===a||"object"!==typeof a)throw new g("Constructing Headers with invalid parameters");a instanceof h?a.forEach(function(a,d){this.append(d,a)},this):F.isArray(a)?a.forEach(function(a){if(2!==a.length)throw new g("Constructing Headers with invalid parameters");this.append(a[0],a[1])},this):Object.getOwnPropertyNames(a).forEach(function(b){this.append(b,a[b])},this)}}function G(a,b){var d=ea(h.prototype);d[v]=b;h.call(d,a);return d}function M(a){if(a.bodyUsed)return t.reject(new g("Body was already read")); -if(null===a.body)return t.resolve(new u(0));if(fa(a.body))return t.reject(new g("ReadableStream was already locked"));var b=a.body.getReader(),d=[],e=0;return b.read().then(function ha(a){if(a.done){if(0===d.length)a=new u(0);else if(1===d.length)a=new u(d[0].buffer);else{a=new u(e);for(var k=0,c=d.length,f=0;k<c;k++)a.set(d[k],f),f+=d[k].length}return a}return a.value instanceof u?(e+=a.value.length,d.push(a.value),b.read().then(ha)):t.reject(new g("Invalid stream data type"))})}function R(){this._initBody= -function(a){this[N]=!1;this[m]=null===a||void 0===a?null:a instanceof O?a:new O({start:function(b){if(a)if("string"===typeof a)b.enqueue(FetchInternal.encodeToUTF8(a));else if(S.prototype.isPrototypeOf(a))b.enqueue(new u(a.slice(0)));else if(ia(a))b.enqueue(new u(a.buffer.slice(0)));else if(a instanceof Blob)b.enqueue(new u(FetchInternal.blobToArrayBuffer(a)));else throw new g("Unsupported BodyInit type");b.close()}});this[n].get("content-type")||("string"===typeof a?this[n].set("content-type","text/plain;charset=UTF-8"): -a instanceof Blob&&""!==a.type&&this[n].set("content-type",a.type))};P(this,{body:{get:function(){return this[m]}},bodyUsed:{get:function(){return this[N]?!0:this[m]?!!ja(this[m]):!1}}});this.arrayBuffer=function(){return this[z]?t.reject(new DOMException("Aborted","AbortError")):M(this).then(function(a){return a.buffer})};this.text=function(){return this[z]?t.reject(new DOMException("Aborted","AbortError")):M(this).then(function(a){return FetchInternal.decodeFromUTF8(a)})};this.json=function(){return this[z]? -t.reject(new DOMException("Aborted","AbortError")):this.text().then(JSON.parse)};return this}function w(a,b){var d=void 0!==b&&null!==b&&void 0===b.cloneBody;b=b||{};var e=b.body||b.cloneBody,c=b.headers,f=new AbortController;this[A]=f.signal;f=null;if(a instanceof w)this[x]=a.url,this[B]=a.cache,this[C]=a.credentials,void 0===c&&(c=a.headers),this[D]=a.integrity,this[y]=a.method,this[p]=a.mode,d&&"navigate"===this[p]&&(this[p]="same-origin"),this[H]=a.redirect,e||null===a.body||(e=a.body,a[N]=!0), -f=a[A];else{this[x]=String(a);if(!FetchInternal.isUrlValid(this[x],!1))throw new g("Invalid request URL");this[p]="cors";this[C]="same-origin"}if(void 0!==b.window&&null!==b.window)throw new g("Invalid request window");this[B]=b.cache||this[B]||"default";if(-1===ka.indexOf(this[B]))throw new g("Invalid request cache mode");this[C]=b.credentials||this[C]||"same-origin";if(-1===la.indexOf(this[C]))throw new g("Invalid request credentials");void 0!==b.integrity?this[D]=b.integrity:void 0===this[D]&& -(this[D]="");a=(b.method||this[y]||"GET").toUpperCase();if(-1===ma.indexOf(a))throw new g("Invalid request method");this[y]=a;if(b.mode&&-1===na.indexOf(b.mode))throw new g("Invalid request mode");this[p]=b.mode||this[p]||"no-cors";if("no-cors"===this[p]){if(-1===oa.indexOf(this[y]))throw new g("Invalid request method for no-cors");if(""!==this[D])throw new g("Request integrity data is not allowed with no-cors");}if("same-origin"!==this[p]&&"only-if-cached"===this[B])throw new g("Request mode must be same-origin for only-if-cached"); -this[H]=b.redirect||this[H]||"follow";if(-1===pa.indexOf(this[H]))throw new g("Invalid request redirect mode");this[n]="no-cors"===this[p]?G(c,aa):G(c,Y);if(("GET"===this[y]||"HEAD"===this[y])&&e)throw new g("Request body is not allowed for GET or HEAD");"signal"in b&&(f=b.signal);f&&this[A].follow(f);this._initBody(e)}function qa(a,b){var d=G(void 0,b);a.replace(/\r?\n[\t ]+/g," ").split(/\r?\n/).forEach(function(a){var b=a.split(":");if(a=b.shift().trim())b=b.join(":").trim(),d.append(a,b)});return d} -function r(a,b){b||(b={});this[J]="default";this[q]="status"in b?b.status:200;if(200>this[q]||599<this[q])throw new T("Invalid response status");this[U]=200<=this[q]&&300>this[q];if("statusText"in b){var d=b.statusText;for(var e=0,f=d.length,c;e<f;e++)if(c=d.charCodeAt(e),9!==c&&(32>c||255<c||127===c))throw g("Invalid response status text");}else d="OK";this[K]=d;this[n]=G(b.headers,L);this[x]=b.url||"";if(a&&-1<ra.indexOf(this[q]))throw new g("Response body is not allowed with a null body status"); -this[z]=b.is_aborted||!1;this._initBody(a)}if(!c.fetch){var F=c.Array,S=c.ArrayBuffer,ea=c.Object.create,P=c.Object.defineProperties,f=c.Symbol,sa=f.iterator,I=c.Map,T=c.RangeError,g=c.TypeError,u=c.Uint8Array,t=c.Promise,O=c.ReadableStream,V=c.ReadableStreamTee,ja=c.IsReadableStreamDisturbed,fa=c.IsReadableStreamLocked,m=f("body"),N=f("bodyUsed"),B=f("cache"),C=f("credentials"),v=f("guardCallback"),n=f("headers"),D=f("integrity"),l=f("map"),y=f("method"),p=f("mode"),U=f("ok"),H=f("redirect"),q=f("status"), -K=f("statusText"),J=f("type"),x=f("url"),z=f("is_aborted"),A=f("signal"),Z="accept-charset accept-encoding access-control-request-headers access-control-request-method connection content-length cookie cookie2 date dnt expect host keep-alive origin referer te trailer transfer-encoding upgrade via".split(" "),da=["set-cookie","set-cookie2"],ba=["accept","accept-language","content-language"],ca=["application/x-www-form-urlencoded","multipart/form-data","text/plain"],ka="default no-store reload no-cache force-cache only-if-cached".split(" "), -la=["omit","same-origin","include"],ma="DELETE GET HEAD OPTIONS POST PUT".split(" "),oa=["GET","HEAD","POST"],na=["same-origin","no-cors","cors"],pa=["follow","error","manual"],ra=[101,204,205,304],ta=[301,302,303,307,308],ua="[object Int8Array];[object Uint8Array];[object Uint8ClampedArray];[object Int16Array];[object Uint16Array];[object Int32Array];[object Uint32Array];[object Float32Array];[object Float64Array]".split(";"),ia=S.isView||function(a){return a&&-1<ua.indexOf(Object.prototype.toString.call(a))}; -h.prototype.append=function(a,b){if(2!==arguments.length)throw g("Invalid parameters to append");a=E(a);b=Q(b);this[v](a,b)||(this[l].has(a)?this[l].set(a,this[l].get(a)+", "+b):this[l].set(a,b))};h.prototype["delete"]=function(a){if(1!==arguments.length)throw g("Invalid parameters to delete");this[v](a,"invalid")||this[l].delete(E(a))};h.prototype.get=function(a){if(1!==arguments.length)throw g("Invalid parameters to get");a=E(a);var b=this[l].get(a);return void 0!==b?b:null};h.prototype.has=function(a){if(1!== -arguments.length)throw g("Invalid parameters to has");return this[l].has(E(a))};h.prototype.set=function(a,b){if(2!==arguments.length)throw g("Invalid parameters to set");a=E(a);b=Q(b);this[v](a,b)||this[l].set(a,b)};h.prototype.forEach=function(a,b){var d=this;F.from(this[l].entries()).sort().forEach(function(e){a.call(b,e[1],e[0],d)})};h.prototype.keys=function(){return(new I(F.from(this[l].entries()).sort())).keys()};h.prototype.values=function(){return(new I(F.from(this[l].entries()).sort())).values()}; -h.prototype.entries=function(){return(new I(F.from(this[l].entries()).sort())).entries()};h.prototype[sa]=h.prototype.entries;w.prototype.clone=function(){var a=null;null!==this[m]&&(a=V(this[m],!0),this[m]=a[0],a=a[1]);return new w(this,{cloneBody:a,signal:this[A]})};P(w.prototype,{cache:{get:function(){return this[B]}},credentials:{get:function(){return this[C]}},headers:{get:function(){return this[n]}},integrity:{get:function(){return this[D]}},method:{get:function(){return this[y]}},mode:{get:function(){return this[p]}}, -redirect:{get:function(){return this[H]}},url:{get:function(){return this[x]}},signal:{get:function(){return this[A]}}});R.call(w.prototype);R.call(r.prototype);r.prototype.clone=function(){var a=null;null!==this[m]&&(a=V(this[m],!0),this[m]=a[0],a=a[1]);return new r(a,{status:this[q],statusText:this[K],headers:G(this[n],L),url:this[x],is_aborted:this[z]})};P(r.prototype,{headers:{get:function(){return this[n]}},ok:{get:function(){return this[U]}},status:{get:function(){return this[q]}},statusText:{get:function(){return this[K]}}, -type:{get:function(){return this[J]}},url:{get:function(){return this[x]}}});r.error=function(){var a=new r(null);a[n][v]=W;a[J]="error";a[q]=0;a[K]="";return a};r.redirect=function(a,b){if(!FetchInternal.isUrlValid(a,!0))throw new g("Invalid URL for response redirect");void 0===b&&(b=302);if(-1===ta.indexOf(b))throw new T("Invalid status code for response redirect");return new r(null,{status:b,headers:{location:a}})};c.Headers=h;c.Request=w;c.Response=r;c.fetch=function(a,b){return new t(function(d, -e){var c=!1,f=!1,h=new w(a,b),k=new XMLHttpRequest,l=null;if(h.signal.aborted)return e(new DOMException("Aborted","AbortError"));var m=new O({start:function(a){l=a},cancel:function(a){c=!0;k.abort()}}),p=function(){if(!c){c=!0;m.cancel();if(l)try{ReadableStreamDefaultControllerError(l,new DOMException("Aborted","AbortError"))}catch(va){}setTimeout(function(){try{k.abort()}catch(va){}},0)}};k.onload=function(){l.close()};k.onreadystatechange=function(){if(k.readyState===k.HEADERS_RECEIVED){var a={status:k.status, -statusText:k.statusText,headers:qa(k.getAllResponseHeaders()||"",L)};a.url="responseURL"in k?k.responseURL:a.headers.get("X-Request-URL");try{var b=new r(m,a);h[A].addEventListener("abort",function(){b[z]=!0;p();e(new DOMException("Aborted","AbortError"))});b[J]=f?"cors":"basic";d(b)}catch(wa){e(wa)}}};k.onerror=function(){l.error(new g("Network request failed"));e(new g("Network request failed"))};k.ontimeout=function(){l.error(new g("Network request failed"));e(new g("Network request failed"))}; -k.open(h.method,h.url,!0);"include"===h.credentials&&(k.withCredentials=!0);h.headers.forEach(function(a,b){k.setRequestHeader(b,a)});var n=function(a){c||l.enqueue(a)},q=function(a){f=a};null===h.body?k.fetch(n,q,null):M(h).then(function(a){k.fetch(n,q,a)})})};c.fetch.polyfill=!0}})(this); \ No newline at end of file +'use strict';(function(h){function J(a){"string"!==typeof a&&(a=String(a));if(/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(a))throw new e("Invalid character in header field name");return a.toLowerCase()}function X(a){"string"!==typeof a&&(a=String(a));var b;var c=0;for(b=a.length;c<b;c++){var d=a.charCodeAt(c);if(9!==d&&10!==d&&13!==d&&32!==d)break}for(b=a.length-1;b>c&&(d=a.charCodeAt(b),9===d||10===d||13===d||32===d);b--);a=a.substring(c,b+1);c=0;for(b=a.length;c<b;c++)if(d=a.charCodeAt(c),256<=d||0===d|| +10===d||13===d)throw new e("Invalid character in header field value");return a}function fa(a,b){throw new e("Immutable header cannot be modified");}function ha(a,b){return!1}function ia(a,b){a=a.toLowerCase();return-1<ja.indexOf(a)||a.startsWith("proxy-")||a.startsWith("sec-")?!0:!1}function ka(a,b){a=a.toLowerCase();return-1<la.indexOf(a)||"content-type"===a&&(b=b.split(";")[0].toLowerCase(),-1<ma.indexOf(b))?!1:!0}function S(a,b){return-1<na.indexOf(a.toLowerCase())?!0:!1}function n(a){this[p]= +new P;void 0===this[A]&&(this[A]=ha);if(void 0!==a){if(null===a||"object"!==typeof a)throw new e("Constructing Headers with invalid parameters");a instanceof n?a.forEach(function(b,c){this.append(c,b)},this):K.isArray(a)?a.forEach(function(b){if(2!==b.length)throw new e("Constructing Headers with invalid parameters");this.append(b[0],b[1])},this):Object.getOwnPropertyNames(a).forEach(function(b){this.append(b,a[b])},this)}}function L(a,b){var c=oa(n.prototype);c[A]=b;n.call(c,a);return c}function T(a){if(a.bodyUsed)return z.reject(new e("Body was already read")); +if(null===a.body)return z.resolve(new v(0));if(pa(a.body))return z.reject(new e("ReadableStream was already locked"));var b=a.body.getReader(),c=[],d=0;return b.read().then(function q(f){if(f.done){if(0===c.length)f=new v(0);else if(1===c.length)f=new v(c[0].buffer);else{f=new v(d);for(var g=0,w=c.length,M=0;g<w;g++)f.set(c[g],M),M+=c[g].length}return f}return f.value instanceof v?(d+=f.value.length,c.push(f.value),b.read().then(q)):z.reject(new e("Invalid stream data type"))})}function Y(){this._initBody= +function(a){this[U]=!1;this[r]=null===a||void 0===a?null:a instanceof V?a:new V({start:function(b){if(a)if("string"===typeof a)b.enqueue(FetchInternal.encodeToUTF8(a));else if(Z.prototype.isPrototypeOf(a))b.enqueue(new v(a.slice(0)));else if(qa(a)){var c=new v(a.buffer);c=v.from(c.slice(a.byteOffset,a.byteLength+1));b.enqueue(c)}else if(a instanceof Blob)b.enqueue(new v(FetchInternal.blobToArrayBuffer(a)));else throw new e("Unsupported BodyInit type");b.close()}});this[x].get("content-type")||("string"=== +typeof a?this[x].set("content-type","text/plain;charset=UTF-8"):a instanceof Blob&&""!==a.type&&this[x].set("content-type",a.type))};W(this,{body:{get:function(){return this[r]}},bodyUsed:{get:function(){return this[U]?!0:this[r]?!!ra(this[r]):!1}}});this.arrayBuffer=function(){return this[E]?z.reject(new DOMException("Aborted","AbortError")):T(this).then(function(a){return a.buffer})};this.text=function(){return this[E]?z.reject(new DOMException("Aborted","AbortError")):T(this).then(function(a){return FetchInternal.decodeFromUTF8(a)})}; +this.json=function(){return this[E]?z.reject(new DOMException("Aborted","AbortError")):this.text().then(JSON.parse)};return this}function B(a,b){var c=void 0!==b&&null!==b&&void 0===b.cloneBody;b=b||{};var d=b.body||b.cloneBody;""===b.body&&(d="");var l=b.headers,f=new AbortController;this[F]=f.signal;f=null;if(a instanceof B)this[C]=a.url,this[G]=a.cache,this[H]=a.credentials,void 0===l&&(l=a.headers),this[I]=a.integrity,this[D]=a.method,this[t]=a.mode,c&&"navigate"===this[t]&&(this[t]="same-origin"), +this[N]=a.redirect,d||null===a.body||(d=a.body,a[U]=!0),f=a[F];else{this[C]=String(a);if(!FetchInternal.isUrlValid(this[C],!1))throw new e("Invalid request URL");this[t]="cors";this[H]="same-origin"}if(void 0!==b.window&&null!==b.window)throw new e("Invalid request window");this[G]=b.cache||this[G]||"default";if(-1===sa.indexOf(this[G]))throw new e("Invalid request cache mode");this[H]=b.credentials||this[H]||"same-origin";if(-1===ta.indexOf(this[H]))throw new e("Invalid request credentials");void 0!== +b.integrity?this[I]=b.integrity:void 0===this[I]&&(this[I]="");a=(b.method||this[D]||"GET").toUpperCase();if(-1===ua.indexOf(a))throw new e("Invalid request method");this[D]=a;if(b.mode&&-1===va.indexOf(b.mode))throw new e("Invalid request mode");this[t]=b.mode||this[t]||"no-cors";if("no-cors"===this[t]){if(-1===wa.indexOf(this[D]))throw new e("Invalid request method for no-cors");if(""!==this[I])throw new e("Request integrity data is not allowed with no-cors");}if("same-origin"!==this[t]&&"only-if-cached"=== +this[G])throw new e("Request mode must be same-origin for only-if-cached");this[N]=b.redirect||this[N]||"follow";if(-1===xa.indexOf(this[N]))throw new e("Invalid request redirect mode");this[x]="no-cors"===this[t]?L(l,ka):L(l,ia);if(("GET"===this[D]||"HEAD"===this[D])&&d)throw new e("Request body is not allowed for GET or HEAD");"signal"in b&&(f=b.signal);f&&this[F].follow(f);this._initBody(d)}function ya(a,b){var c=L(void 0,b);a.replace(/\r?\n[\t ]+/g," ").split(/\r?\n/).forEach(function(d){var l= +d.split(":");if(d=l.shift().trim())l=l.join(":").trim(),c.append(d,l)});return c}function u(a,b){b||(b={});this[Q]="default";this[y]="status"in b?b.status:200;if(200>this[y]||599<this[y])throw new aa("Invalid response status");this[ba]=200<=this[y]&&300>this[y];if("statusText"in b){var c=b.statusText;for(var d=0,l=c.length,f;d<l;d++)if(f=c.charCodeAt(d),9!==f&&(32>f||255<f||127===f))throw e("Invalid response status text");}else c="OK";this[R]=c;this[x]=L(b.headers,S);this[C]=b.url||"";if(a&&-1<za.indexOf(this[y]))throw new e("Response body is not allowed with a null body status"); +this[E]=b.is_aborted||!1;this._initBody(a)}if(!h.fetch){var K=h.Array,Z=h.ArrayBuffer,oa=h.Object.create,W=h.Object.defineProperties,k=h.Symbol,Aa=k.iterator,P=h.Map,aa=h.RangeError,e=h.TypeError,v=h.Uint8Array,z=h.Promise,V=h.ReadableStream,ca=h.ReadableStreamTee,ra=h.IsReadableStreamDisturbed,pa=h.IsReadableStreamLocked,r=k("body"),U=k("bodyUsed"),G=k("cache"),H=k("credentials"),A=k("guardCallback"),x=k("headers"),I=k("integrity"),p=k("map"),D=k("method"),t=k("mode"),ba=k("ok"),N=k("redirect"), +y=k("status"),R=k("statusText"),Q=k("type"),C=k("url"),E=k("is_aborted"),F=k("signal"),ja="accept-charset accept-encoding access-control-request-headers access-control-request-method connection content-length cookie cookie2 date dnt expect host keep-alive origin referer te trailer transfer-encoding upgrade via".split(" "),na=["set-cookie","set-cookie2"],la=["accept","accept-language","content-language"],ma=["application/x-www-form-urlencoded","multipart/form-data","text/plain"],sa="default no-store reload no-cache force-cache only-if-cached".split(" "), +ta=["omit","same-origin","include"],ua="DELETE GET HEAD OPTIONS POST PUT".split(" "),wa=["GET","HEAD","POST"],va=["same-origin","no-cors","cors"],xa=["follow","error","manual"],za=[101,204,205,304],Ba=[301,302,303,307,308],Ca="[object Int8Array];[object Uint8Array];[object Uint8ClampedArray];[object Int16Array];[object Uint16Array];[object Int32Array];[object Uint32Array];[object Float32Array];[object Float64Array]".split(";"),qa=Z.isView||function(a){return a&&-1<Ca.indexOf(Object.prototype.toString.call(a))}; +n.prototype.append=function(a,b){if(2!==arguments.length)throw e("Invalid parameters to append");a=J(a);b=X(b);this[A](a,b)||(this[p].has(a)?this[p].set(a,this[p].get(a)+", "+b):this[p].set(a,b))};n.prototype["delete"]=function(a){if(1!==arguments.length)throw e("Invalid parameters to delete");this[A](a,"invalid")||this[p].delete(J(a))};n.prototype.get=function(a){if(1!==arguments.length)throw e("Invalid parameters to get");a=J(a);var b=this[p].get(a);return void 0!==b?b:null};n.prototype.has=function(a){if(1!== +arguments.length)throw e("Invalid parameters to has");return this[p].has(J(a))};n.prototype.set=function(a,b){if(2!==arguments.length)throw e("Invalid parameters to set");a=J(a);b=X(b);this[A](a,b)||this[p].set(a,b)};n.prototype.forEach=function(a,b){var c=this;K.from(this[p].entries()).sort().forEach(function(d){a.call(b,d[1],d[0],c)})};n.prototype.keys=function(){return(new P(K.from(this[p].entries()).sort())).keys()};n.prototype.values=function(){return(new P(K.from(this[p].entries()).sort())).values()}; +n.prototype.entries=function(){return(new P(K.from(this[p].entries()).sort())).entries()};n.prototype[Aa]=n.prototype.entries;B.prototype.clone=function(){var a=null;null!==this[r]&&(a=ca(this[r],!0),this[r]=a[0],a=a[1]);return new B(this,{cloneBody:a,signal:this[F]})};W(B.prototype,{cache:{get:function(){return this[G]}},credentials:{get:function(){return this[H]}},headers:{get:function(){return this[x]}},integrity:{get:function(){return this[I]}},method:{get:function(){return this[D]}},mode:{get:function(){return this[t]}}, +redirect:{get:function(){return this[N]}},url:{get:function(){return this[C]}},signal:{get:function(){return this[F]}}});Y.call(B.prototype);Y.call(u.prototype);u.prototype.clone=function(){var a=null;null!==this[r]&&(a=ca(this[r],!0),this[r]=a[0],a=a[1]);return new u(a,{status:this[y],statusText:this[R],headers:L(this[x],S),url:this[C],is_aborted:this[E]})};W(u.prototype,{headers:{get:function(){return this[x]}},ok:{get:function(){return this[ba]}},status:{get:function(){return this[y]}},statusText:{get:function(){return this[R]}}, +type:{get:function(){return this[Q]}},url:{get:function(){return this[C]}}});u.error=function(){var a=new u(null);a[x][A]=fa;a[Q]="error";a[y]=0;a[R]="";return a};u.redirect=function(a,b){if(!FetchInternal.isUrlValid(a,!0))throw new e("Invalid URL for response redirect");void 0===b&&(b=302);if(-1===Ba.indexOf(b))throw new aa("Invalid status code for response redirect");return new u(null,{status:b,headers:{location:a}})};h.Headers=n;h.Request=B;h.Response=u;h.fetch=function(a,b){return new z(function(c, +d){var l=!1,f=!1,q=new B(a,b),g=new XMLHttpRequest,w=null;if(q.signal.aborted)return d(new DOMException("Aborted","AbortError"));var M=new V({start:function(m){w=m},cancel:function(m){l=!0;g.abort()}}),Da=function(){if(!l){l=!0;M.cancel();if(w)try{ReadableStreamDefaultControllerError(w,new DOMException("Aborted","AbortError"))}catch(m){}setTimeout(function(){try{g.abort()}catch(m){}},0)}};g.onload=function(){w.close()};g.onreadystatechange=function(){if(g.readyState===g.HEADERS_RECEIVED){var m={status:g.status, +statusText:g.statusText,headers:ya(g.getAllResponseHeaders()||"",S)};m.url="responseURL"in g?g.responseURL:m.headers.get("X-Request-URL");try{var O=new u(M,m);q[F].addEventListener("abort",function(){O[E]=!0;Da();d(new DOMException("Aborted","AbortError"))});O[Q]=f?"cors":"basic";c(O)}catch(Ea){d(Ea)}}};g.onerror=function(){w.error(new e("Network request failed"));d(new e("Network request failed"))};g.ontimeout=function(){w.error(new e("Network request failed"));d(new e("Network request failed"))}; +g.open(q.method,q.url,!0);"include"===q.credentials&&(g.withCredentials=!0);q.headers.forEach(function(m,O){g.setRequestHeader(O,m)});var da=function(m){l||w.enqueue(m)},ea=function(m){f=m};null===q.body?g.fetch(da,ea,null):T(q).then(function(m){g.fetch(da,ea,m)})})};h.fetch.polyfill=!0}})(this); \ No newline at end of file
diff --git a/src/cobalt/fetch/fetch.js b/src/cobalt/fetch/fetch.js index b5de929..8c8162b 100644 --- a/src/cobalt/fetch/fetch.js +++ b/src/cobalt/fetch/fetch.js
@@ -434,7 +434,11 @@ } else if (ArrayBuffer.prototype.isPrototypeOf(data)) { controller.enqueue(new Uint8Array(data.slice(0))) } else if (isArrayBufferView(data)) { - controller.enqueue(new Uint8Array(data.buffer.slice(0))) + // View as bytes + const asBytes = new Uint8Array(data.buffer); + // slice and copy + var byteSlice = Uint8Array.from(asBytes.slice(data.byteOffset, data.byteLength + 1)); + controller.enqueue(byteSlice); } else if (data instanceof Blob) { controller.enqueue(new Uint8Array(FetchInternal.blobToArrayBuffer(data))) } else { @@ -529,6 +533,7 @@ init.cloneBody === undefined init = init || {} var body = init.body || init.cloneBody + if(init.body === '') body = ''; var headersInit = init.headers // AbortSignal cannot be constructed directly, so create a temporary
diff --git a/src/cobalt/h5vcc/h5vcc_updater.cc b/src/cobalt/h5vcc/h5vcc_updater.cc index 4b7a171..bebd3b0 100644 --- a/src/cobalt/h5vcc/h5vcc_updater.cc +++ b/src/cobalt/h5vcc/h5vcc_updater.cc
@@ -33,7 +33,7 @@ if (updater_module_->GetUpdaterChannel().compare(channel) != 0 && updater_module_->IsChannelValid(channel)) { updater_module_->SetUpdaterChannel(channel); - updater_module_->MarkChannelChanged(); + updater_module_->CompareAndSwapChannelChanged(0, 1); updater_module_->RunUpdateCheck(); } }
diff --git a/src/cobalt/layout/paragraph.cc b/src/cobalt/layout/paragraph.cc index 55ccd1e..a18aecb 100644 --- a/src/cobalt/layout/paragraph.cc +++ b/src/cobalt/layout/paragraph.cc
@@ -125,17 +125,22 @@ return start_position; } -bool Paragraph::FindBreakPosition(const scoped_refptr<dom::FontList>& used_font, - int32 start_position, int32 end_position, - LayoutUnit available_width, - bool should_collapse_trailing_white_space, - bool allow_overflow, - Paragraph::BreakPolicy break_policy, - int32* break_position, - LayoutUnit* break_width) { +bool Paragraph::FindBreakPosition( + BaseDirection direction, bool should_attempt_to_wrap, + const scoped_refptr<dom::FontList>& used_font, int32 start_position, + int32 end_position, LayoutUnit available_width, + bool should_collapse_trailing_white_space, bool allow_overflow, + Paragraph::BreakPolicy break_policy, int32* break_position, + LayoutUnit* break_width) { DCHECK(is_closed_); - *break_position = start_position; + DCHECK(direction == base_direction_); + if (AreInlineAndScriptDirectionsTheSame(direction, start_position) || + should_attempt_to_wrap) { + *break_position = start_position; + } else { + *break_position = end_position; + } *break_width = LayoutUnit(); // If overflow isn't allowed and there is no available width, then there is @@ -165,9 +170,10 @@ // |break_width| will be updated with the position of the last available // break position. FindIteratorBreakPosition( - used_font, line_break_iterator_, start_position, end_position, - available_width, should_collapse_trailing_white_space, - allow_normal_overflow, break_position, break_width); + direction, should_attempt_to_wrap, used_font, line_break_iterator_, + start_position, end_position, available_width, + should_collapse_trailing_white_space, allow_normal_overflow, + break_position, break_width); } // If break word is the break policy, attempt to break unbreakable "words" at @@ -177,20 +183,39 @@ if (break_policy == kBreakPolicyBreakWord) { // Only continue allowing overflow if the break position has not moved from // start, meaning that no normal break positions were found. - allow_overflow = allow_overflow && (*break_position == start_position); + if (AreInlineAndScriptDirectionsTheSame(direction, start_position) || + should_attempt_to_wrap) { + allow_overflow = allow_overflow && (*break_position == start_position); + } else { + allow_overflow = allow_overflow && (*break_position == end_position); + } // Find the last available break-word break position. |break_position| and // |break_width| will be updated with the position of the last available // break position. The search begins at the location of the last normal // break position that fit within the available width. - FindIteratorBreakPosition( - used_font, character_break_iterator_, *break_position, end_position, - available_width, false, allow_overflow, break_position, break_width); + if (AreInlineAndScriptDirectionsTheSame(direction, start_position) || + should_attempt_to_wrap) { + FindIteratorBreakPosition(direction, should_attempt_to_wrap, used_font, + character_break_iterator_, *break_position, + end_position, available_width, false, + allow_overflow, break_position, break_width); + } else { + FindIteratorBreakPosition(direction, should_attempt_to_wrap, used_font, + character_break_iterator_, start_position, + *break_position, available_width, false, + allow_overflow, break_position, break_width); + } } // No usable break position was found if the break position has not moved // from the start position. - return *break_position > start_position; + if (AreInlineAndScriptDirectionsTheSame(direction, start_position) || + should_attempt_to_wrap) { + return *break_position > start_position; + } else { + return *break_position < end_position; + } } int32 Paragraph::GetNextBreakPosition(int32 position, @@ -268,6 +293,12 @@ return (GetBidiLevel(position) % 2) == 1; } +bool Paragraph::AreInlineAndScriptDirectionsTheSame(BaseDirection direction, + int32 position) const { + return ((direction == kLeftToRightBaseDirection && !IsRTL(position)) || + (direction == kRightToLeftBaseDirection && IsRTL(position))); +} + bool Paragraph::IsCollapsibleWhiteSpace(int32 position) const { // Only check for the space character. Other collapsible white space // characters will have already been converted into the space characters and @@ -338,6 +369,7 @@ } void Paragraph::FindIteratorBreakPosition( + BaseDirection direction, bool should_attempt_to_wrap, const scoped_refptr<dom::FontList>& used_font, icu::BreakIterator* const break_iterator, int32 start_position, int32 end_position, LayoutUnit available_width, @@ -347,19 +379,37 @@ // position. Continue until TryIncludeSegmentWithinAvailableWidth() returns // false, indicating that no more segments can be included. break_iterator->setText(unicode_text_); - for (int32 segment_end = break_iterator->following(start_position); - segment_end != icu::BreakIterator::DONE && segment_end < end_position; - segment_end = break_iterator->next()) { - if (!TryIncludeSegmentWithinAvailableWidth( - used_font, *break_position, segment_end, available_width, - should_collapse_trailing_white_space, &allow_overflow, - break_position, break_width)) { - break; + if (AreInlineAndScriptDirectionsTheSame(direction, start_position) || + should_attempt_to_wrap) { + for (int32 segment_end = break_iterator->following(start_position); + segment_end != icu::BreakIterator::DONE && segment_end < end_position; + segment_end = break_iterator->next()) { + if (!TryIncludeSegmentWithinAvailableWidth( + direction, should_attempt_to_wrap, used_font, *break_position, + segment_end, available_width, + should_collapse_trailing_white_space, &allow_overflow, + break_position, break_width)) { + break; + } + } + } else { + for (int32 segment_begin = break_iterator->preceding(end_position); + segment_begin != icu::BreakIterator::DONE && + segment_begin > start_position; + segment_begin = break_iterator->previous()) { + if (!TryIncludeSegmentWithinAvailableWidth( + direction, should_attempt_to_wrap, used_font, segment_begin, + *break_position, available_width, + should_collapse_trailing_white_space, &allow_overflow, + break_position, break_width)) { + break; + } } } } bool Paragraph::TryIncludeSegmentWithinAvailableWidth( + BaseDirection direction, bool should_attempt_to_wrap, const scoped_refptr<dom::FontList>& used_font, int32 segment_start, int32 segment_end, LayoutUnit available_width, bool should_collapse_trailing_white_space, bool* allow_overflow, @@ -388,7 +438,12 @@ return false; } - *break_position = segment_end; + if (AreInlineAndScriptDirectionsTheSame(direction, segment_start) || + should_attempt_to_wrap) { + *break_position = segment_end; + } else { + *break_position = segment_start; + } *break_width += segment_width; if (*allow_overflow) {
diff --git a/src/cobalt/layout/paragraph.h b/src/cobalt/layout/paragraph.h index 3feb5d8..d64233c 100644 --- a/src/cobalt/layout/paragraph.h +++ b/src/cobalt/layout/paragraph.h
@@ -111,7 +111,8 @@ // substring coming before |break_position|. // // Returns false if no usable break position was found. - bool FindBreakPosition(const scoped_refptr<dom::FontList>& used_font, + bool FindBreakPosition(BaseDirection direction, bool should_attempt_to_wrap, + const scoped_refptr<dom::FontList>& used_font, int32 start_position, int32 end_position, LayoutUnit available_width, bool should_collapse_trailing_white_space, @@ -136,6 +137,8 @@ int GetBidiLevel(int32 position) const; bool IsRTL(int32 position) const; + bool AreInlineAndScriptDirectionsTheSame(BaseDirection direction, + int32 position) const; bool IsCollapsibleWhiteSpace(int32 position) const; bool GetNextRunPosition(int32 position, int32* next_run_position) const; int32 GetTextEndPosition() const; @@ -174,7 +177,9 @@ // that first overflowing segment will be included. The parameter // |break_width| indicates the width of the portion of the substring coming // before |break_position|. - void FindIteratorBreakPosition(const scoped_refptr<dom::FontList>& used_font, + void FindIteratorBreakPosition(BaseDirection direction, + bool should_attempt_to_wrap, + const scoped_refptr<dom::FontList>& used_font, icu::BreakIterator* const break_iterator, int32 start_position, int32 end_position, LayoutUnit available_width, @@ -197,6 +202,7 @@ // of false does not guarantee that the segment was not included, but simply // that no additional segments can be included. bool TryIncludeSegmentWithinAvailableWidth( + BaseDirection direction, bool should_attempt_to_wrap, const scoped_refptr<dom::FontList>& used_font, int32 start_position, int32 end_position, LayoutUnit available_width, bool should_collapse_trailing_white_space, bool* allow_overflow,
diff --git a/src/cobalt/layout/text_box.cc b/src/cobalt/layout/text_box.cc index 4507080b..f1bd926 100644 --- a/src/cobalt/layout/text_box.cc +++ b/src/cobalt/layout/text_box.cc
@@ -42,7 +42,9 @@ paragraph_(paragraph), text_start_position_(text_start_position), text_end_position_(text_end_position), + truncated_text_start_position_(text_start_position), truncated_text_end_position_(text_end_position), + previous_truncated_text_start_position_(text_start_position), previous_truncated_text_end_position_(text_end_position), truncated_text_offset_from_left_(0), used_font_(used_style_provider->GetUsedFontList( @@ -237,12 +239,16 @@ } void TextBox::DoPreEllipsisPlacementProcessing() { + previous_truncated_text_start_position_ = truncated_text_start_position_; previous_truncated_text_end_position_ = truncated_text_end_position_; + truncated_text_start_position_ = text_start_position_; truncated_text_end_position_ = text_end_position_; } void TextBox::DoPostEllipsisPlacementProcessing() { - if (previous_truncated_text_end_position_ != truncated_text_end_position_) { + if (previous_truncated_text_start_position_ != + truncated_text_start_position_ || + previous_truncated_text_end_position_ != truncated_text_end_position_) { InvalidateRenderTreeNodesOfBoxAndAncestors(); } } @@ -397,7 +403,7 @@ // color is animated, in which case it could become non-transparent. if (used_color.a() > 0.0f || is_color_animated || text_shadow != cssom::KeywordValue::GetNone()) { - int32 text_start_position = GetNonCollapsedTextStartPosition(); + int32 text_start_position = GetVisibleTextStartPosition(); int32 text_length = GetVisibleTextLength(); scoped_refptr<render_tree::GlyphBuffer> glyph_buffer = @@ -481,7 +487,12 @@ // If the ellipsis has already been placed, then the text is fully truncated // by the ellipsis. if (*is_placed) { - truncated_text_end_position_ = text_start_position_; + if (paragraph_->AreInlineAndScriptDirectionsTheSame(base_direction, + text_start_position_)) { + truncated_text_end_position_ = text_start_position_; + } else { + truncated_text_start_position_ = text_end_position_; + } return; } @@ -510,8 +521,8 @@ // text box. Otherwise, it can only appear after the first character // (https://www.w3.org/TR/css3-ui/#propdef-text-overflow). if (paragraph_->FindBreakPosition( - used_font_, start_position, end_position, desired_content_offset, - false, !(*is_placement_requirement_met), + base_direction, false, used_font_, start_position, end_position, + desired_content_offset, false, !(*is_placement_requirement_met), Paragraph::kBreakPolicyBreakWord, &found_position, &found_offset)) { // A usable break position was found. Calculate the placed offset using the // the break position's distance from the content box's start edge. In the @@ -525,7 +536,12 @@ } else { *placed_offset = content_box_start_offset + found_offset; } - truncated_text_end_position_ = found_position; + if (paragraph_->AreInlineAndScriptDirectionsTheSame(base_direction, + start_position)) { + truncated_text_end_position_ = found_position; + } else { + truncated_text_start_position_ = found_position; + } // An acceptable break position was not found. If the placement requirement // was already met prior to this box, then the ellipsis doesn't require a // character from this box to appear prior to its position, so simply place @@ -533,7 +549,12 @@ } else if (is_placement_requirement_met) { *placed_offset = GetMarginBoxStartEdgeOffsetFromContainingBlock(base_direction); - truncated_text_end_position_ = text_start_position_; + if (paragraph_->AreInlineAndScriptDirectionsTheSame(base_direction, + start_position)) { + truncated_text_end_position_ = text_start_position_; + } else { + truncated_text_start_position_ = text_end_position_; + } // The placement requirement has not already been met. Given that an // acceptable break position was not found within the text, the ellipsis can // only be placed at the end edge of the box. @@ -603,7 +624,8 @@ // fits within the available width. Overflow is never allowed. LayoutUnit wrap_width; if (!paragraph_->FindBreakPosition( - used_font_, start_position, text_end_position_, available_width, + paragraph_->base_direction(), true, used_font_, start_position, + text_end_position_, available_width, should_collapse_trailing_white_space, false, break_policy, &wrap_position, &wrap_width)) { // If no break position is found, but the line existence is already @@ -720,19 +742,24 @@ Paragraph::kVisualTextOrder); } +int32 TextBox::GetVisibleTextStartPosition() const { + return std::max(GetNonCollapsedTextStartPosition(), + truncated_text_start_position_); +} + int32 TextBox::GetVisibleTextEndPosition() const { return std::min(GetNonCollapsedTextEndPosition(), truncated_text_end_position_); } int32 TextBox::GetVisibleTextLength() const { - return GetVisibleTextEndPosition() - GetNonCollapsedTextStartPosition(); + return GetVisibleTextEndPosition() - GetVisibleTextStartPosition(); } bool TextBox::HasVisibleText() const { return GetVisibleTextLength() > 0; } std::string TextBox::GetVisibleText() const { - return paragraph_->RetrieveUtf8SubString(GetNonCollapsedTextStartPosition(), + return paragraph_->RetrieveUtf8SubString(GetVisibleTextStartPosition(), GetVisibleTextEndPosition(), Paragraph::kVisualTextOrder); }
diff --git a/src/cobalt/layout/text_box.h b/src/cobalt/layout/text_box.h index c2edcc6..855a0a2 100644 --- a/src/cobalt/layout/text_box.h +++ b/src/cobalt/layout/text_box.h
@@ -133,6 +133,7 @@ int32 GetNonCollapsibleTextLength() const; std::string GetNonCollapsibleText() const; + int32 GetVisibleTextStartPosition() const; int32 GetVisibleTextEndPosition() const; int32 GetVisibleTextLength() const; bool HasVisibleText() const; @@ -145,7 +146,7 @@ const scoped_refptr<Paragraph> paragraph_; // The position within the paragraph where the text contained in this box // begins. - const int32 text_start_position_; + int32 text_start_position_; // The position within the paragraph where the text contained in this box // ends. int32 text_end_position_; @@ -154,11 +155,13 @@ // "Implementations must hide characters and atomic inline-level elements at // the applicable edge(s) of the line as necessary to fit the ellipsis." // https://www.w3.org/TR/css3-ui/#propdef-text-overflow + int32 truncated_text_start_position_; int32 truncated_text_end_position_; - // Tracking of the previous value of |truncated_text_end_position_|, which + // Tracking of the previous value of the truncated text position, which // allows for determination of whether or not the value changed during // ellipsis placement. When this occurs, the cached render tree nodes of this // box and its ancestors are invalidated. + int32 previous_truncated_text_start_position_; int32 previous_truncated_text_end_position_; // The horizontal offset to apply to rendered text as a result of an ellipsis // truncating the text. This value can be non-zero when the text box is in a
diff --git a/src/cobalt/layout/topmost_event_target.cc b/src/cobalt/layout/topmost_event_target.cc index 6316a6b..df2cd6a 100644 --- a/src/cobalt/layout/topmost_event_target.cc +++ b/src/cobalt/layout/topmost_event_target.cc
@@ -130,18 +130,45 @@ } namespace { +// Return the nearest common ancestor of previous_element and target_element +scoped_refptr<dom::Element> GetNearestCommonAncestor( + scoped_refptr<dom::HTMLElement> previous_element, + scoped_refptr<dom::HTMLElement> target_element) { + scoped_refptr<dom::Element> nearest_common_ancestor; + if (previous_element == target_element) { + nearest_common_ancestor = target_element; + } else { + if (previous_element && target_element) { + // Find the nearest common ancestor, if there is any. + dom::Document* previous_document = previous_element->node_document(); + // The elements only have a common ancestor if they are both in the same + // document. + if (previous_document && + previous_document == target_element->node_document()) { + // The nearest ancestor of the target element that is already + // designated is the nearest common ancestor of it and the previous + // element. + nearest_common_ancestor = target_element; + while (nearest_common_ancestor && + nearest_common_ancestor->AsHTMLElement() && + !nearest_common_ancestor->AsHTMLElement()->IsDesignated()) { + nearest_common_ancestor = nearest_common_ancestor->parent_element(); + } + } + } + } + return nearest_common_ancestor; +} + void SendStateChangeLeaveEvents( bool is_pointer_event, scoped_refptr<dom::HTMLElement> previous_element, scoped_refptr<dom::HTMLElement> target_element, + scoped_refptr<dom::Element> nearest_common_ancestor, dom::PointerEventInit* event_init) { // Send enter/leave/over/out (status change) events when needed. if (previous_element != target_element) { const scoped_refptr<dom::Window>& view = event_init->view(); - // The enter/leave status change events apply to all ancestors up to the - // nearest common ancestor between the previous and current element. - scoped_refptr<dom::Element> nearest_common_ancestor; - // Send out and leave events. if (previous_element) { // LottiePlayer elements may change playback state. @@ -149,24 +176,9 @@ previous_element->AsLottiePlayer()->OnUnHover(); } - event_init->set_related_target(target_element); - // Find the nearest common ancestor, if there is any. dom::Document* previous_document = previous_element->node_document(); - if (previous_document) { - if (target_element && - previous_document == target_element->node_document()) { - // The nearest ancestor of the current element that is already - // designated is the nearest common ancestor of it and the previous - // element. - nearest_common_ancestor = target_element; - while (nearest_common_ancestor && - nearest_common_ancestor->AsHTMLElement() && - !nearest_common_ancestor->AsHTMLElement()->IsDesignated()) { - nearest_common_ancestor = nearest_common_ancestor->parent_element(); - } - } - } + event_init->set_related_target(target_element); if (is_pointer_event) { previous_element->DispatchEvent(new dom::PointerEvent( base::Tokens::pointerout(), view, *event_init)); @@ -209,15 +221,12 @@ void SendStateChangeEnterEvents( bool is_pointer_event, scoped_refptr<dom::HTMLElement> previous_element, scoped_refptr<dom::HTMLElement> target_element, + scoped_refptr<dom::Element> nearest_common_ancestor, dom::PointerEventInit* event_init) { // Send enter/leave/over/out (status change) events when needed. if (previous_element != target_element) { const scoped_refptr<dom::Window>& view = event_init->view(); - // The enter/leave status change events apply to all ancestors up to the - // nearest common ancestor between the previous and current element. - scoped_refptr<dom::Element> nearest_common_ancestor; - // Send over and enter events. if (target_element) { // LottiePlayer elements may change playback state. @@ -399,8 +408,14 @@ scoped_refptr<dom::HTMLElement> previous_html_element( previous_html_element_weak_); + // The enter/leave status change events apply to all ancestors up to the + // nearest common ancestor between the previous and current element. + scoped_refptr<dom::Element> nearest_common_ancestor( + GetNearestCommonAncestor(previous_html_element, target_element)); + SendStateChangeLeaveEvents(pointer_event, previous_html_element, - target_element, &event_init); + target_element, nearest_common_ancestor, + &event_init); if (target_element) { target_element->DispatchEvent(event); @@ -424,26 +439,41 @@ } } - if (target_element && !is_touchpad_event) { - // Send the click event if needed, which is not prevented by canceling the - // pointerdown event. - // https://www.w3.org/TR/uievents/#event-type-click - // https://www.w3.org/TR/pointerevents/#compatibility-mapping-with-mouse-events - if (event_init.button() == 0 && - ((mouse_event->type() == base::Tokens::pointerup()) || - (mouse_event->type() == base::Tokens::mouseup()))) { + if (event_init.button() == 0 && + ((mouse_event->type() == base::Tokens::pointerup()) || + (mouse_event->type() == base::Tokens::mouseup()))) { + // This is an 'up' event for the last pressed button indicating that no + // more buttons are pressed. + if (target_element && !is_touchpad_event) { + // Send the click event if needed, which is not prevented by canceling + // the pointerdown event. + // https://www.w3.org/TR/uievents/#event-type-click + // https://www.w3.org/TR/pointerevents/#compatibility-mapping-with-mouse-events target_element->DispatchEvent( new dom::MouseEvent(base::Tokens::click(), view, event_init)); } + if (target_element && (pointer_event->pointer_type() != "mouse")) { + // If it's not a mouse event, then releasing the last button means + // that there is no longer an indicated element. + dom::Document* document = target_element->node_document(); + if (document) { + document->SetIndicatedElement(NULL); + target_element = NULL; + } + } } SendStateChangeEnterEvents(pointer_event, previous_html_element, - target_element, &event_init); + target_element, nearest_common_ancestor, + &event_init); if (target_element) { - dom::Document* document = target_element->node_document(); - if (document) { - document->SetIndicatedElement(target_element); + // Touchpad input never indicates document elements. + if (!is_touchpad_event) { + dom::Document* document = target_element->node_document(); + if (document) { + document->SetIndicatedElement(target_element); + } } previous_html_element_weak_ = base::AsWeakPtr(target_element.get()); } else {
diff --git a/src/cobalt/layout_tests/layout_tests.cc b/src/cobalt/layout_tests/layout_tests.cc index 4cd46c1..17804c8 100644 --- a/src/cobalt/layout_tests/layout_tests.cc +++ b/src/cobalt/layout_tests/layout_tests.cc
@@ -207,7 +207,7 @@ renderer::RenderTreePixelTester::Options pixel_tester_options; if (renderer::RenderTreePixelTester::IsReferencePlatform()) { // Use stricter tolerances on reference platforms. - pixel_tester_options.gaussian_blur_sigma = 3.0f; + pixel_tester_options.gaussian_blur_sigma = 3.5f; } RunTest(GetParam(), graphics_context_, pixel_tester_options); }
diff --git a/src/cobalt/layout_tests/testdata/bidi/bidi-paragraphs-should-maintain-proper-ordering-when-split-across-multiple-lines-expected.png b/src/cobalt/layout_tests/testdata/bidi/bidi-paragraphs-should-maintain-proper-ordering-when-split-across-multiple-lines-expected.png index d0f9074..7e86a49 100644 --- a/src/cobalt/layout_tests/testdata/bidi/bidi-paragraphs-should-maintain-proper-ordering-when-split-across-multiple-lines-expected.png +++ b/src/cobalt/layout_tests/testdata/bidi/bidi-paragraphs-should-maintain-proper-ordering-when-split-across-multiple-lines-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/bidi/bidi-paragraphs-should-maintain-proper-ordering-when-split-across-multiple-lines.html b/src/cobalt/layout_tests/testdata/bidi/bidi-paragraphs-should-maintain-proper-ordering-when-split-across-multiple-lines.html index 71a614f..463fedd 100644 --- a/src/cobalt/layout_tests/testdata/bidi/bidi-paragraphs-should-maintain-proper-ordering-when-split-across-multiple-lines.html +++ b/src/cobalt/layout_tests/testdata/bidi/bidi-paragraphs-should-maintain-proper-ordering-when-split-across-multiple-lines.html
@@ -30,8 +30,12 @@ لتد2ل3تت4دل5ت6د ط1لتدلنش 123456789 745 ط1لت 987 لتد 654</span> </div> + <div class="containing-block" dir="rtl"> + <span>12لتدل3ت dدلت4دلتد5ل6تد يabطا32ل Single Word + 1234 ط1لتدلنش ab12دلتد34cd ط1aلتد2ل 3تت489 + 12 ل5ت6745 ط1لتدلنش ط1لaتدلتدتد ط11246 ط1abcd + لتد2ل3تت4دل5ت6د ط1لتدلنش 123456789 745 ط1لت + 987 لتد 654</span> + </div> </body> </html> - -</body> -</html> \ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-system-fallback-if-no-matching-family-is-found-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-system-fallback-if-no-matching-family-is-found-expected.png index 291576a..bf339a6 100644 --- a/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-system-fallback-if-no-matching-family-is-found-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-system-fallback-if-no-matching-family-is-found-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly-expected.png index 4b3d234..e509aaa 100644 --- a/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly.html b/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly.html index 22e2cab..e1e8f5b 100644 --- a/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly.html +++ b/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly.html
@@ -29,7 +29,7 @@ <span>🙈🙉🙊👨👩🏃🐌</span> <span>🐜💐🌲🍇🥝🍄🍔</span> <span>🍟🍞🥞🌮🍣🍡🍨</span> - <span class="bold-span">🌎🌚</span> + <span class="bold-span">🌎🌚🥰</span> </div> </body> </html>
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-clip-when-it-overflows-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-clip-when-it-overflows-expected.png index 27b72da..0bbe59c 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-clip-when-it-overflows-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-clip-when-it-overflows-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-ellipsize-each-line-that-overflows-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-ellipsize-each-line-that-overflows-expected.png index 164d112..2e89634 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-ellipsize-each-line-that-overflows-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-ellipsize-each-line-that-overflows-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-ellipsize-overflowing-first-word-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-ellipsize-overflowing-first-word-expected.png index 59aa7b9..4db6e7b 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-ellipsize-overflowing-first-word-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-ellipsize-overflowing-first-word-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-handle-transform-functions-via-matrix-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-handle-transform-functions-via-matrix-expected.png index b311cd1..21d31da 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-handle-transform-functions-via-matrix-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-handle-transform-functions-via-matrix-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-handle-transform-functions-via-rotation-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-handle-transform-functions-via-rotation-expected.png index 4cfa868..85a1acb 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-handle-transform-functions-via-rotation-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-handle-transform-functions-via-rotation-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-not-ellipsize-first-character-on-line-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-not-ellipsize-first-character-on-line-expected.png index 27b72da..0bbe59c 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-not-ellipsize-first-character-on-line-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-not-ellipsize-first-character-on-line-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-properly-position-ellipsis-in-spans-with-margins-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-properly-position-ellipsis-in-spans-with-margins-expected.png index a88d55a..f71519f 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-properly-position-ellipsis-in-spans-with-margins-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-properly-position-ellipsis-in-spans-with-margins-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-retain-background-color-of-ellipsized-span-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-retain-background-color-of-ellipsized-span-expected.png index ae53279..ac84ae0 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-retain-background-color-of-ellipsized-span-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-retain-background-color-of-ellipsized-span-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-use-style-of-containing-block-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-use-style-of-containing-block-expected.png index 5d56a8b..e059ac1 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-use-style-of-containing-block-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-ellipsis-should-use-style-of-containing-block-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-shaped-text-should-accurately-calculate-width-before-ellipsis-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-shaped-text-should-accurately-calculate-width-before-ellipsis-expected.png index 7b2d801..8b20b2a 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-shaped-text-should-accurately-calculate-width-before-ellipsis-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-shaped-text-should-accurately-calculate-width-before-ellipsis-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-text-overflow-ellipsis-should-display-ellipsis-on-overflow-when-overflow-is-hidden-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-text-overflow-ellipsis-should-display-ellipsis-on-overflow-when-overflow-is-hidden-expected.png index bf2da54..7fecf85 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-text-overflow-ellipsis-should-display-ellipsis-on-overflow-when-overflow-is-hidden-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-text-overflow-ellipsis-should-display-ellipsis-on-overflow-when-overflow-is-hidden-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-ui/5-2-text-overflow-ellipsis-should-not-be-inherited-expected.png b/src/cobalt/layout_tests/testdata/css3-ui/5-2-text-overflow-ellipsis-should-not-be-inherited-expected.png index bb3987f..a264063 100644 --- a/src/cobalt/layout_tests/testdata/css3-ui/5-2-text-overflow-ellipsis-should-not-be-inherited-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-ui/5-2-text-overflow-ellipsis-should-not-be-inherited-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/web-platform-tests/fetch/web_platform_tests.txt b/src/cobalt/layout_tests/testdata/web-platform-tests/fetch/web_platform_tests.txt index 5c11ed1..72ab7d8 100644 --- a/src/cobalt/layout_tests/testdata/web-platform-tests/fetch/web_platform_tests.txt +++ b/src/cobalt/layout_tests/testdata/web-platform-tests/fetch/web_platform_tests.txt
@@ -97,12 +97,8 @@ api/request/request-cache-only-if-cached.html,DISABLE api/request/request-cache-reload.html,DISABLE api/request/request-clone.sub.html,PASS -# Fails because Body only supports text, json, and arrayBuffer. See the -# corresponding tests for Response which have been customized to test only -# those types. -api/request/request-consume.html,DISABLE -# Fails because blob and formData are not supported. -api/request/request-consume-empty.html,DISABLE +api/request/request-consume.html,PASS +api/request/request-consume-empty.html,PASS # Disabled due to failing test fixture api/request/request-disturbed.html,DISABLE api/request/request-error.html,PASS
diff --git a/src/cobalt/layout_tests/web_platform_test_parser.cc b/src/cobalt/layout_tests/web_platform_test_parser.cc index 864148b..0e1b721 100644 --- a/src/cobalt/layout_tests/web_platform_test_parser.cc +++ b/src/cobalt/layout_tests/web_platform_test_parser.cc
@@ -126,7 +126,6 @@ << "\"" << top_level << "\""; return std::vector<WebPlatformTestInfo>(); } - DLOG(INFO) << "[Temporary debugging] javascript engine for parser exiting"; } base::FilePath test_dir(GetTestInputRootDirectory()
diff --git a/src/cobalt/media/base/shell_audio_bus.cc b/src/cobalt/media/base/audio_bus.cc similarity index 87% rename from src/cobalt/media/base/shell_audio_bus.cc rename to src/cobalt/media/base/audio_bus.cc index 5140d01..ea63e7a 100644 --- a/src/cobalt/media/base/shell_audio_bus.cc +++ b/src/cobalt/media/base/audio_bus.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #include <algorithm> #include <limits> @@ -24,20 +24,17 @@ namespace { -typedef ShellAudioBus::StorageType StorageType; -typedef ShellAudioBus::SampleType SampleType; +typedef AudioBus::StorageType StorageType; +typedef AudioBus::SampleType SampleType; const float kFloat32ToInt16Factor = 32768.f; -inline void ConvertSample(ShellAudioBus::SampleType src_type, - const uint8* src_ptr, - ShellAudioBus::SampleType dest_type, - uint8* dest_ptr) { +inline void ConvertSample(AudioBus::SampleType src_type, const uint8* src_ptr, + AudioBus::SampleType dest_type, uint8* dest_ptr) { if (src_type == dest_type) { - SbMemoryCopy( - dest_ptr, src_ptr, - src_type == ShellAudioBus::kInt16 ? sizeof(int16) : sizeof(float)); - } else if (src_type == ShellAudioBus::kFloat32) { + SbMemoryCopy(dest_ptr, src_ptr, + src_type == AudioBus::kInt16 ? sizeof(int16) : sizeof(float)); + } else if (src_type == AudioBus::kFloat32) { float sample_in_float = *reinterpret_cast<const float*>(src_ptr); int32 sample_in_int32 = static_cast<int32>(sample_in_float * kFloat32ToInt16Factor); @@ -78,8 +75,8 @@ } // namespace -ShellAudioBus::ShellAudioBus(size_t channels, size_t frames, - SampleType sample_type, StorageType storage_type) +AudioBus::AudioBus(size_t channels, size_t frames, SampleType sample_type, + StorageType storage_type) : channels_(channels), frames_(frames), sample_type_(sample_type), @@ -106,7 +103,7 @@ } } -ShellAudioBus::ShellAudioBus(size_t frames, const std::vector<float*>& samples) +AudioBus::AudioBus(size_t frames, const std::vector<float*>& samples) : channels_(samples.size()), frames_(frames), sample_type_(kFloat32), @@ -119,7 +116,7 @@ } } -ShellAudioBus::ShellAudioBus(size_t channels, size_t frames, float* samples) +AudioBus::AudioBus(size_t channels, size_t frames, float* samples) : channels_(channels), frames_(frames), sample_type_(kFloat32), @@ -129,7 +126,7 @@ channel_data_.push_back(reinterpret_cast<uint8*>(samples)); } -ShellAudioBus::ShellAudioBus(size_t frames, const std::vector<int16*>& samples) +AudioBus::AudioBus(size_t frames, const std::vector<int16*>& samples) : channels_(samples.size()), frames_(frames), sample_type_(kInt16), @@ -142,7 +139,7 @@ } } -ShellAudioBus::ShellAudioBus(size_t channels, size_t frames, int16* samples) +AudioBus::AudioBus(size_t channels, size_t frames, int16* samples) : channels_(channels), frames_(frames), sample_type_(kInt16), @@ -152,7 +149,7 @@ channel_data_.push_back(reinterpret_cast<uint8*>(samples)); } -size_t ShellAudioBus::GetSampleSizeInBytes() const { +size_t AudioBus::GetSampleSizeInBytes() const { if (sample_type_ == kInt16) { return sizeof(int16); } @@ -160,29 +157,29 @@ return sizeof(float); } -const uint8* ShellAudioBus::interleaved_data() const { +const uint8* AudioBus::interleaved_data() const { DCHECK_EQ(storage_type_, kInterleaved); return channel_data_[0]; } -const uint8* ShellAudioBus::planar_data(size_t channel) const { +const uint8* AudioBus::planar_data(size_t channel) const { DCHECK_LT(channel, channels_); DCHECK_EQ(storage_type_, kPlanar); return channel_data_[channel]; } -uint8* ShellAudioBus::interleaved_data() { +uint8* AudioBus::interleaved_data() { DCHECK_EQ(storage_type_, kInterleaved); return channel_data_[0]; } -uint8* ShellAudioBus::planar_data(size_t channel) { +uint8* AudioBus::planar_data(size_t channel) { DCHECK_LT(channel, channels_); DCHECK_EQ(storage_type_, kPlanar); return channel_data_[channel]; } -void ShellAudioBus::ZeroFrames(size_t start_frame, size_t end_frame) { +void AudioBus::ZeroFrames(size_t start_frame, size_t end_frame) { DCHECK_LE(start_frame, end_frame); DCHECK_LE(end_frame, frames_); end_frame = std::min(end_frame, frames_); @@ -201,7 +198,7 @@ } } -void ShellAudioBus::Assign(const ShellAudioBus& source) { +void AudioBus::Assign(const AudioBus& source) { DCHECK_EQ(channels_, source.channels_); if (channels_ != source.channels_) { ZeroAllFrames(); @@ -232,8 +229,8 @@ } } -void ShellAudioBus::Assign(const ShellAudioBus& source, - const std::vector<float>& matrix) { +void AudioBus::Assign(const AudioBus& source, + const std::vector<float>& matrix) { DCHECK_EQ(channels() * source.channels(), matrix.size()); DCHECK_EQ(sample_type_, kFloat32); DCHECK_EQ(source.sample_type_, kFloat32); @@ -258,7 +255,7 @@ } template <StorageType SourceStorageType, StorageType DestStorageType> -void ShellAudioBus::MixFloatSamples(const ShellAudioBus& source) { +void AudioBus::MixFloatSamples(const AudioBus& source) { const size_t frames = std::min(frames_, source.frames_); if (SourceStorageType == DestStorageType) { @@ -284,7 +281,7 @@ } template <StorageType SourceStorageType, StorageType DestStorageType> -void ShellAudioBus::MixInt16Samples(const ShellAudioBus& source) { +void AudioBus::MixInt16Samples(const AudioBus& source) { const size_t frames = std::min(frames_, source.frames_); if (SourceStorageType == DestStorageType) { @@ -318,7 +315,7 @@ } } -void ShellAudioBus::Mix(const ShellAudioBus& source) { +void AudioBus::Mix(const AudioBus& source) { DCHECK_EQ(channels_, source.channels_); DCHECK_EQ(sample_type_, source.sample_type_); @@ -359,8 +356,7 @@ } } -void ShellAudioBus::Mix(const ShellAudioBus& source, - const std::vector<float>& matrix) { +void AudioBus::Mix(const AudioBus& source, const std::vector<float>& matrix) { DCHECK_EQ(channels() * source.channels(), matrix.size()); DCHECK_EQ(sample_type_, source.sample_type_); @@ -411,7 +407,7 @@ } } -uint8* ShellAudioBus::GetSamplePtr(size_t channel, size_t frame) { +uint8* AudioBus::GetSamplePtr(size_t channel, size_t frame) { DCHECK_LT(channel, channels_); DCHECK_LT(frame, frames_); @@ -423,7 +419,7 @@ } } -const uint8* ShellAudioBus::GetSamplePtr(size_t channel, size_t frame) const { +const uint8* AudioBus::GetSamplePtr(size_t channel, size_t frame) const { DCHECK_LT(channel, channels_); DCHECK_LT(frame, frames_);
diff --git a/src/cobalt/media/base/shell_audio_bus.h b/src/cobalt/media/base/audio_bus.h similarity index 85% rename from src/cobalt/media/base/shell_audio_bus.h rename to src/cobalt/media/base/audio_bus.h index cdd4668..2b4c369 100644 --- a/src/cobalt/media/base/shell_audio_bus.h +++ b/src/cobalt/media/base/audio_bus.h
@@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef COBALT_MEDIA_BASE_SHELL_AUDIO_BUS_H_ -#define COBALT_MEDIA_BASE_SHELL_AUDIO_BUS_H_ +#ifndef COBALT_MEDIA_BASE_AUDIO_BUS_H_ +#define COBALT_MEDIA_BASE_AUDIO_BUS_H_ #include <memory> #include <vector> @@ -37,11 +37,11 @@ // second of such audio contains 48000 frames (96000 samples). // Note: This class doesn't do endianness conversions. It assumes that all data // is in the correct endianness. -class COBALT_EXPORT ShellAudioBus { +class COBALT_EXPORT AudioBus { public: // Guaranteed alignment of each channel's data; use 64-byte alignment so it // satisfies all our current platforms. Note that this is only used for - // buffers that are allocated and owned by the ShellAudioBus. We don't + // buffers that are allocated and owned by the AudioBus. We don't // enforce alignment for the buffers passed in and extra caution should be // taken if they are used as hardware buffer. static const size_t kChannelAlignmentInBytes = 64; @@ -50,12 +50,12 @@ enum StorageType { kInterleaved, kPlanar }; - ShellAudioBus(size_t channels, size_t frames, SampleType sample_type, - StorageType storage_type); - ShellAudioBus(size_t frames, const std::vector<float*>& samples); - ShellAudioBus(size_t channels, size_t frames, float* samples); - ShellAudioBus(size_t frames, const std::vector<int16*>& samples); - ShellAudioBus(size_t channels, size_t frames, int16* samples); + AudioBus(size_t channels, size_t frames, SampleType sample_type, + StorageType storage_type); + AudioBus(size_t frames, const std::vector<float*>& samples); + AudioBus(size_t channels, size_t frames, float* samples); + AudioBus(size_t frames, const std::vector<int16*>& samples); + AudioBus(size_t channels, size_t frames, int16* samples); size_t channels() const { return channels_; } size_t frames() const { return frames_; } @@ -84,7 +84,7 @@ // conversion between different sample types and storage types. When source // has less frames than the destination object, it will only copy these frames // and will not fill the rest frames in our buffer with 0. - void Assign(const ShellAudioBus& source); + void Assign(const AudioBus& source); // The same as the above function except that this function also does mixing. // |matrix| is a |dest.channels()| row * |source.channels()| column matrix in @@ -96,14 +96,14 @@ // + source.sample[source.channels() - 1][frame] * // matrix[channels() * source.channels() + source.channels() - 1]; // Note: Both objects must have storage type of kFloat32. - void Assign(const ShellAudioBus& source, const std::vector<float>& matrix); + void Assign(const AudioBus& source, const std::vector<float>& matrix); // The following functions are the same as the Assign() functions except that // they add the calculated samples to the target samples instead of replacing // the target samples with the calculated samples. // Note: Both objects must have storage type of kFloat32. - void Mix(const ShellAudioBus& source); - void Mix(const ShellAudioBus& source, const std::vector<float>& matrix); + void Mix(const AudioBus& source); + void Mix(const AudioBus& source, const std::vector<float>& matrix); public: // The .*ForTypes? functions below are optimized versions that assume what @@ -134,10 +134,10 @@ } template <StorageType SourceStorageType, StorageType DestStorageType> - void MixFloatSamples(const ShellAudioBus& source); + void MixFloatSamples(const AudioBus& source); template <StorageType SourceStorageType, StorageType DestStorageType> - void MixInt16Samples(const ShellAudioBus& source); + void MixInt16Samples(const AudioBus& source); private: void SetFloat32Sample(size_t channel, size_t frame, float sample) { @@ -160,10 +160,10 @@ SampleType sample_type_; StorageType storage_type_; - DISALLOW_COPY_AND_ASSIGN(ShellAudioBus); + DISALLOW_COPY_AND_ASSIGN(AudioBus); }; } // namespace media } // namespace cobalt -#endif // COBALT_MEDIA_BASE_SHELL_AUDIO_BUS_H_ +#endif // COBALT_MEDIA_BASE_AUDIO_BUS_H_
diff --git a/src/cobalt/media/base/pipeline.h b/src/cobalt/media/base/pipeline.h index f0d37fc..c2bbcfc 100644 --- a/src/cobalt/media/base/pipeline.h +++ b/src/cobalt/media/base/pipeline.h
@@ -92,7 +92,9 @@ virtual ~Pipeline() {} virtual void Suspend() {} - virtual void Resume() {} + // TODO: This is temporary for supporting background media playback. + // Need to be removed with media refactor. + virtual void Resume(PipelineWindow window) {} // Build a pipeline to using the given filter collection to construct a filter // chain, executing |seek_cb| when the initial seek/preroll has completed.
diff --git a/src/cobalt/media/base/sbplayer_pipeline.cc b/src/cobalt/media/base/sbplayer_pipeline.cc index 4f4f9d1..68abc49 100644 --- a/src/cobalt/media/base/sbplayer_pipeline.cc +++ b/src/cobalt/media/base/sbplayer_pipeline.cc
@@ -90,7 +90,10 @@ ~SbPlayerPipeline() override; void Suspend() override; - void Resume() override; + // TODO: This is temporary for supporting background media playback. + // Need to be removed with media refactor. + void Resume(PipelineWindow window) override; + void Start(Demuxer* demuxer, const SetDrmSystemReadyCB& set_drm_system_ready_cb, const PipelineStatusCB& ended_cb, const ErrorCB& error_cb, @@ -175,7 +178,7 @@ void CallSeekCB(PipelineStatus status); void SuspendTask(base::WaitableEvent* done_event); - void ResumeTask(base::WaitableEvent* done_event); + void ResumeTask(PipelineWindow window, base::WaitableEvent* done_event); // Store the media time retrieved by GetMediaTime so we can cache it as an // estimate and avoid calling SbPlayerGetInfo too frequently. @@ -331,7 +334,7 @@ waitable_event.Wait(); } -void SbPlayerPipeline::Resume() { +void SbPlayerPipeline::Resume(PipelineWindow window) { DCHECK(!task_runner_->BelongsToCurrentThread()); base::WaitableEvent waitable_event( @@ -339,7 +342,8 @@ base::WaitableEvent::InitialState::NOT_SIGNALED); task_runner_->PostTask(FROM_HERE, base::Bind(&SbPlayerPipeline::ResumeTask, - base::Unretained(this), &waitable_event)); + base::Unretained(this), + window, &waitable_event)); waitable_event.Wait(); } @@ -1314,7 +1318,8 @@ done_event->Signal(); } -void SbPlayerPipeline::ResumeTask(base::WaitableEvent* done_event) { +void SbPlayerPipeline::ResumeTask(PipelineWindow window, + base::WaitableEvent* done_event) { DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(done_event); DCHECK(suspended_); @@ -1324,8 +1329,10 @@ return; } + window_ = window; + if (player_) { - player_->Resume(); + player_->Resume(window); } suspended_ = false;
diff --git a/src/cobalt/media/base/starboard_player.cc b/src/cobalt/media/base/starboard_player.cc index d23cdab..d7eeb2e 100644 --- a/src/cobalt/media/base/starboard_player.cc +++ b/src/cobalt/media/base/starboard_player.cc
@@ -140,7 +140,7 @@ #if SB_HAS(PLAYER_WITH_URL) , is_url_based_(false) -#endif // SB_HAS(PLAYER_WITH_URL) +#endif // SB_HAS(PLAYER_WITH_URL { DCHECK(!get_decode_target_graphics_context_provider_func_.is_null()); DCHECK(audio_config.IsValidConfig() || video_config.IsValidConfig()); @@ -450,9 +450,11 @@ player_ = kSbPlayerInvalid; } -void StarboardPlayer::Resume() { +void StarboardPlayer::Resume(SbWindow window) { DCHECK(task_runner_->BelongsToCurrentThread()); + window_ = window; + // Check if the player is already resumed. if (state_ != kSuspended) { DCHECK(SbPlayerIsValid(player_)); @@ -540,16 +542,22 @@ TRACE_EVENT0("cobalt::media", "StarboardPlayer::CreatePlayer"); DCHECK(task_runner_->BelongsToCurrentThread()); +bool is_visible = SbWindowIsValid(window_); #if SB_API_VERSION >= 11 SbMediaAudioCodec audio_codec = audio_sample_info_.codec; - SbMediaVideoCodec video_codec = video_sample_info_.codec; + SbMediaVideoCodec video_codec = kSbMediaVideoCodecNone; + // TODO: This is temporary for supporting background media playback. + // Need to be removed with media refactor. + if (is_visible) { + video_codec = video_sample_info_.codec; + } #else // SB_API_VERSION >= 11 SbMediaAudioCodec audio_codec = kSbMediaAudioCodecNone; if (audio_config_.IsValidConfig()) { audio_codec = MediaAudioCodecToSbMediaAudioCodec(audio_config_.codec()); } SbMediaVideoCodec video_codec = kSbMediaVideoCodecNone; - if (video_config_.IsValidConfig()) { + if (video_config_.IsValidConfig() && is_visible) { video_codec = MediaVideoCodecToSbMediaVideoCodec(video_config_.codec()); } #endif // SB_API_VERSION >= 11 @@ -562,6 +570,11 @@ creation_param.drm_system = drm_system_; creation_param.audio_sample_info = audio_sample_info_; creation_param.video_sample_info = video_sample_info_; + // TODO: This is temporary for supporting background media playback. + // Need to be removed with media refactor. + if (!is_visible) { + creation_param.video_sample_info.codec = kSbMediaVideoCodecNone; + } creation_param.output_mode = output_mode_; DCHECK_EQ(SbPlayerGetPreferredOutputMode(&creation_param), output_mode_); player_ = SbPlayerCreate( @@ -573,6 +586,11 @@ #else // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT) DCHECK(SbPlayerOutputModeSupported(output_mode_, video_codec, drm_system_)); + // TODO: This is temporary for supporting background media playback. + // Need to be removed with media refactor. + if (!is_visible) { + DCHECK(audio_codec != kSbMediaAudioCodecNone); + } player_ = SbPlayerCreate( window_, video_codec, audio_codec, drm_system_, has_audio ? &audio_sample_info_ : NULL,
diff --git a/src/cobalt/media/base/starboard_player.h b/src/cobalt/media/base/starboard_player.h index 2b00770..b4c1581 100644 --- a/src/cobalt/media/base/starboard_player.h +++ b/src/cobalt/media/base/starboard_player.h
@@ -114,7 +114,9 @@ #endif // SB_HAS(PLAYER_WITH_URL) void Suspend(); - void Resume(); + // TODO: This is temporary for supporting background media playback. + // Need to be removed with media refactor. + void Resume(SbWindow window); SbDecodeTarget GetCurrentSbDecodeTarget(); SbPlayerOutputMode GetSbPlayerOutputMode(); @@ -213,7 +215,7 @@ const GetDecodeTargetGraphicsContextProviderFunc get_decode_target_graphics_context_provider_func_; scoped_refptr<CallbackHelper> callback_helper_; - const SbWindow window_; + SbWindow window_; SbDrmSystem drm_system_ = kSbDrmSystemInvalid; Host* const host_; // Consider merge |SbPlayerSetBoundsHelper| into CallbackHelper.
diff --git a/src/cobalt/media/can_play_type_handler.h b/src/cobalt/media/can_play_type_handler.h index 40d1ea6..00b94f1 100644 --- a/src/cobalt/media/can_play_type_handler.h +++ b/src/cobalt/media/can_play_type_handler.h
@@ -25,9 +25,10 @@ class CanPlayTypeHandler { public: virtual ~CanPlayTypeHandler() {} - virtual SbMediaSupportType CanPlayType(const std::string& mime_type, - const std::string& key_system, - bool is_progressive) const = 0; + virtual SbMediaSupportType CanPlayProgressive( + const std::string& mime_type) const = 0; + virtual SbMediaSupportType CanPlayAdaptive( + const std::string& mime_type, const std::string& key_system) const = 0; virtual void SetDisabledMediaCodecs(const std::string& codecs) = 0; protected:
diff --git a/src/cobalt/media/fetcher_buffered_data_source.cc b/src/cobalt/media/fetcher_buffered_data_source.cc index 2409eb8..9eb25be 100644 --- a/src/cobalt/media/fetcher_buffered_data_source.cc +++ b/src/cobalt/media/fetcher_buffered_data_source.cc
@@ -407,7 +407,7 @@ read_cb.Run(static_cast<int>(bytes_peeked)); // If we have a large buffer size, it could be ideal if we can keep sending // small requests when the read offset is far from the beginning of the - // buffer. However as the ShellDemuxer will cache many frames and the + // buffer. However as the ProgressiveDemuxer will cache many frames and the // buffer we are using is usually small, we will just avoid sending requests // here to make code simple. return;
diff --git a/src/cobalt/media/filters/source_buffer_stream.cc b/src/cobalt/media/filters/source_buffer_stream.cc index c4208ba..0d30352 100644 --- a/src/cobalt/media/filters/source_buffer_stream.cc +++ b/src/cobalt/media/filters/source_buffer_stream.cc
@@ -736,7 +736,7 @@ size_t bytes_to_free = 0; - int garbage_collection_duration_threshold_in_seconds = + int64_t garbage_collection_duration_threshold_in_seconds = SbMediaGetBufferGarbageCollectionDurationThreshold() / kSbTimeSecond; // Check if we're under or at the memory/duration limit. const auto kGcDurationThresholdInMilliseconds =
diff --git a/src/cobalt/media/media.gyp b/src/cobalt/media/media.gyp index bc1e422..4b31fc0 100644 --- a/src/cobalt/media/media.gyp +++ b/src/cobalt/media/media.gyp
@@ -29,6 +29,8 @@ 'media_module.cc', 'media_module.h', + 'base/audio_bus.cc', + 'base/audio_bus.h', 'base/audio_codecs.cc', 'base/audio_codecs.h', 'base/audio_decoder_config.cc', @@ -90,10 +92,6 @@ 'base/sbplayer_pipeline.cc', 'base/sbplayer_set_bounds_helper.cc', 'base/sbplayer_set_bounds_helper.h', - 'base/shell_audio_bus.cc', - 'base/shell_audio_bus.h', - 'base/shell_data_source_reader.cc', - 'base/shell_data_source_reader.h', 'base/starboard_player.cc', 'base/starboard_player.h', 'base/starboard_utils.cc', @@ -125,20 +123,6 @@ 'filters/h264_to_annex_b_bitstream_converter.h', 'filters/h265_parser.cc', 'filters/h265_parser.h', - 'filters/shell_au.cc', - 'filters/shell_au.h', - 'filters/shell_avc_parser.cc', - 'filters/shell_avc_parser.h', - 'filters/shell_demuxer.cc', - 'filters/shell_demuxer.h', - 'filters/shell_mp4_map.cc', - 'filters/shell_mp4_map.h', - 'filters/shell_mp4_parser.cc', - 'filters/shell_mp4_parser.h', - 'filters/shell_parser.cc', - 'filters/shell_parser.h', - 'filters/shell_rbsp_stream.cc', - 'filters/shell_rbsp_stream.h', 'filters/source_buffer_range.cc', 'filters/source_buffer_range.h', 'filters/source_buffer_state.cc', @@ -216,6 +200,22 @@ 'player/web_media_player_impl.h', 'player/web_media_player_proxy.cc', 'player/web_media_player_proxy.h', + 'progressive/avc_access_unit.cc', + 'progressive/avc_access_unit.h', + 'progressive/avc_parser.cc', + 'progressive/avc_parser.h', + 'progressive/data_source_reader.cc', + 'progressive/data_source_reader.h', + 'progressive/mp4_map.cc', + 'progressive/mp4_map.h', + 'progressive/mp4_parser.cc', + 'progressive/mp4_parser.h', + 'progressive/progressive_demuxer.cc', + 'progressive/progressive_demuxer.h', + 'progressive/progressive_parser.cc', + 'progressive/progressive_parser.h', + 'progressive/rbsp_stream.cc', + 'progressive/rbsp_stream.h', ], 'direct_dependent_settings': { 'include_dirs': [ @@ -240,9 +240,9 @@ '<(DEPTH)/testing/gtest.gyp:gtest', ], 'sources': [ - 'base/mock_shell_data_source_reader.h', - 'filters/shell_mp4_map_unittest.cc', - 'filters/shell_rbsp_stream_unittest.cc', + 'progressive/mock_data_source_reader.h', + 'progressive/mp4_map_unittest.cc', + 'progressive/rbsp_stream_unittest.cc', ], 'includes': [ '<(DEPTH)/cobalt/test/test.gypi' ], },
diff --git a/src/cobalt/media/media_module.cc b/src/cobalt/media/media_module.cc index e476a6f..9938d41 100644 --- a/src/cobalt/media/media_module.cc +++ b/src/cobalt/media/media_module.cc
@@ -48,37 +48,27 @@ << "\" from console/command line."; } - SbMediaSupportType CanPlayType(const std::string& mime_type, - const std::string& key_system, - bool is_progressive) const override { - if (is_progressive) { - // |mime_type| is something like: - // video/mp4 - // video/webm - // video/mp4; codecs="avc1.4d401e" - // video/webm; codecs="vp9" - // We do a rough pre-filter to ensure that only video/mp4 is supported as - // progressive. - if (SbStringFindString(mime_type.c_str(), "video/mp4") == 0 && - SbStringFindString(mime_type.c_str(), "application/x-mpegURL") == 0) { - return kSbMediaSupportTypeNotSupported; - } + SbMediaSupportType CanPlayProgressive( + const std::string& mime_type) const override { + // |mime_type| is something like: + // video/mp4 + // video/webm + // video/mp4; codecs="avc1.4d401e" + // video/webm; codecs="vp9" + // We do a rough pre-filter to ensure that only video/mp4 is supported as + // progressive. + if (SbStringFindString(mime_type.c_str(), "video/mp4") == 0 && + SbStringFindString(mime_type.c_str(), "application/x-mpegURL") == 0) { + return kSbMediaSupportTypeNotSupported; } - if (!disabled_media_codecs_.empty()) { - auto mime_codecs = ExtractCodecs(mime_type); - for (auto& disabled_codec : disabled_media_codecs_) { - for (auto& mime_codec : mime_codecs) { - if (mime_codec.find(disabled_codec) != std::string::npos) { - LOG(INFO) << "Codec (" << mime_codec - << ") is disabled via console/command line."; - return kSbMediaSupportTypeNotSupported; - } - } - } - } - SbMediaSupportType type = - SbMediaCanPlayMimeAndKeySystem(mime_type.c_str(), key_system.c_str()); - return type; + + return CanPlayType(mime_type, ""); + } + + SbMediaSupportType CanPlayAdaptive( + const std::string& mime_type, + const std::string& key_system) const override { + return CanPlayType(mime_type, key_system); } private: @@ -107,6 +97,25 @@ return codecs; } + SbMediaSupportType CanPlayType(const std::string& mime_type, + const std::string& key_system) const { + if (!disabled_media_codecs_.empty()) { + auto mime_codecs = ExtractCodecs(mime_type); + for (auto& disabled_codec : disabled_media_codecs_) { + for (auto& mime_codec : mime_codecs) { + if (mime_codec.find(disabled_codec) != std::string::npos) { + LOG(INFO) << "Codec (" << mime_codec + << ") is disabled via console/command line."; + return kSbMediaSupportTypeNotSupported; + } + } + } + } + SbMediaSupportType type = + SbMediaCanPlayMimeAndKeySystem(mime_type.c_str(), key_system.c_str()); + return type; + } + // List of disabled media codecs that will be treated as unsupported. std::vector<std::string> disabled_media_codecs_; }; @@ -120,6 +129,7 @@ if (system_window_) { window = system_window_->GetSbWindow(); } + return std::unique_ptr<WebMediaPlayer>(new media::WebMediaPlayerImpl( window, base::Bind(&MediaModule::GetSbDecodeTargetGraphicsContextProvider, @@ -149,11 +159,16 @@ resource_provider_ = resource_provider; + SbWindow window = kSbWindowInvalid; + if (system_window_) { + window = system_window_->GetSbWindow(); + } + for (Players::iterator iter = players_.begin(); iter != players_.end(); ++iter) { DCHECK(!iter->second); if (!iter->second) { - iter->first->Resume(); + iter->first->Resume(window); } }
diff --git a/src/cobalt/media/player/web_media_player.h b/src/cobalt/media/player/web_media_player.h index 86c4827..ea66d09 100644 --- a/src/cobalt/media/player/web_media_player.h +++ b/src/cobalt/media/player/web_media_player.h
@@ -115,7 +115,9 @@ // Suspend/Resume virtual void Suspend() = 0; - virtual void Resume() = 0; + // TODO: This is temporary for supporting background media playback. + // Need to be removed with media refactor. + virtual void Resume(SbWindow window) = 0; // True if the loaded media has a playable video/audio track. virtual bool HasVideo() const = 0;
diff --git a/src/cobalt/media/player/web_media_player_impl.cc b/src/cobalt/media/player/web_media_player_impl.cc index 6f18dc7..7638848 100644 --- a/src/cobalt/media/player/web_media_player_impl.cc +++ b/src/cobalt/media/player/web_media_player_impl.cc
@@ -24,8 +24,8 @@ #include "cobalt/media/base/limits.h" #include "cobalt/media/base/media_log.h" #include "cobalt/media/filters/chunk_demuxer.h" -#include "cobalt/media/filters/shell_demuxer.h" #include "cobalt/media/player/web_media_player_proxy.h" +#include "cobalt/media/progressive/progressive_demuxer.h" #include "starboard/double.h" #include "starboard/types.h" @@ -292,8 +292,8 @@ is_local_source_ = !url.SchemeIs("http") && !url.SchemeIs("https"); progressive_demuxer_.reset( - new ShellDemuxer(pipeline_thread_.task_runner(), buffer_allocator_, - proxy_->data_source(), media_log_)); + new ProgressiveDemuxer(pipeline_thread_.task_runner(), buffer_allocator_, + proxy_->data_source(), media_log_)); state_.is_progressive = true; StartPipeline(progressive_demuxer_.get()); @@ -532,7 +532,9 @@ void WebMediaPlayerImpl::Suspend() { pipeline_->Suspend(); } -void WebMediaPlayerImpl::Resume() { pipeline_->Resume(); } +void WebMediaPlayerImpl::Resume(PipelineWindow window) { + pipeline_->Resume(window); +} bool WebMediaPlayerImpl::DidLoadingProgress() const { DCHECK_EQ(main_loop_, base::MessageLoop::current());
diff --git a/src/cobalt/media/player/web_media_player_impl.h b/src/cobalt/media/player/web_media_player_impl.h index a1a51be..c77d8b3 100644 --- a/src/cobalt/media/player/web_media_player_impl.h +++ b/src/cobalt/media/player/web_media_player_impl.h
@@ -140,7 +140,9 @@ // Suspend/Resume void Suspend() override; - void Resume() override; + // TODO: This is temporary for supporting background media playback. + // Need to be removed with media refactor. + void Resume(PipelineWindow window) override; // True if the loaded media has a playable video/audio track. bool HasVideo() const override;
diff --git a/src/cobalt/media/filters/shell_au.cc b/src/cobalt/media/progressive/avc_access_unit.cc similarity index 74% rename from src/cobalt/media/filters/shell_au.cc rename to src/cobalt/media/progressive/avc_access_unit.cc index fadfadb..25ad24e 100644 --- a/src/cobalt/media/filters/shell_au.cc +++ b/src/cobalt/media/progressive/avc_access_unit.cc
@@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "cobalt/media/filters/shell_au.h" +#include "cobalt/media/progressive/avc_access_unit.h" #include <algorithm> #include "cobalt/media/base/decoder_buffer.h" #include "cobalt/media/base/endian_util.h" #include "cobalt/media/base/timestamp_constants.h" -#include "cobalt/media/filters/shell_parser.h" +#include "cobalt/media/progressive/progressive_parser.h" namespace cobalt { namespace media { @@ -27,7 +27,7 @@ namespace { bool ReadBytes(uint64 offset, size_t size, uint8* buffer, - ShellDataSourceReader* reader) { + DataSourceReader* reader) { if (reader->BlockingRead(offset, size, buffer) != size) { DLOG(ERROR) << "unable to download AU"; return false; @@ -36,7 +36,7 @@ } bool ReadBytes(uint64 offset, size_t size, DecoderBuffer* decoder_buffer, - uint64 decoder_buffer_offset, ShellDataSourceReader* reader) { + uint64 decoder_buffer_offset, DataSourceReader* reader) { size_t buffer_index = 0; auto& allocations = decoder_buffer->allocations(); while (size > 0) { @@ -67,17 +67,17 @@ return true; } -// ==== ShellEndOfStreamAU ================================================== +// ==== EndOfStreamAU ================================================== -class ShellEndOfStreamAU : public ShellAU { +class EndOfStreamAU : public AvcAccessUnit { public: - ShellEndOfStreamAU(Type type, TimeDelta timestamp) + EndOfStreamAU(Type type, TimeDelta timestamp) : type_(type), timestamp_(timestamp), duration_(kInfiniteDuration) {} private: bool IsEndOfStream() const override { return true; } bool IsValid() const override { return true; } - bool Read(ShellDataSourceReader* reader, DecoderBuffer* buffer) override { + bool Read(DataSourceReader* reader, DecoderBuffer* buffer) override { NOTREACHED(); return false; } @@ -102,20 +102,19 @@ TimeDelta duration_; }; -// ==== ShellAudioAU ======================================================= +// ==== AudioAU ======================================================= -class ShellAudioAU : public ShellAU { +class AudioAU : public AvcAccessUnit { public: - ShellAudioAU(uint64 offset, size_t size, size_t prepend_size, - bool is_keyframe, TimeDelta timestamp, TimeDelta duration, - ShellParser* parser); + AudioAU(uint64 offset, size_t size, size_t prepend_size, bool is_keyframe, + TimeDelta timestamp, TimeDelta duration, ProgressiveParser* parser); private: bool IsEndOfStream() const override { return false; } bool IsValid() const override { return offset_ != 0 && size_ != 0 && timestamp_ != kNoTimestamp; } - bool Read(ShellDataSourceReader* reader, DecoderBuffer* buffer) override; + bool Read(DataSourceReader* reader, DecoderBuffer* buffer) override; Type GetType() const override { return DemuxerStream::AUDIO; } bool IsKeyframe() const override { return is_keyframe_; } bool AddPrepend() const override { return true; } @@ -132,12 +131,12 @@ bool is_keyframe_; TimeDelta timestamp_; TimeDelta duration_; - ShellParser* parser_; + ProgressiveParser* parser_; }; -ShellAudioAU::ShellAudioAU(uint64 offset, size_t size, size_t prepend_size, - bool is_keyframe, TimeDelta timestamp, - TimeDelta duration, ShellParser* parser) +AudioAU::AudioAU(uint64 offset, size_t size, size_t prepend_size, + bool is_keyframe, TimeDelta timestamp, TimeDelta duration, + ProgressiveParser* parser) : offset_(offset), size_(size), prepend_size_(prepend_size), @@ -146,7 +145,7 @@ duration_(duration), parser_(parser) {} -bool ShellAudioAU::Read(ShellDataSourceReader* reader, DecoderBuffer* buffer) { +bool AudioAU::Read(DataSourceReader* reader, DecoderBuffer* buffer) { DCHECK_LE(size_ + prepend_size_, buffer->data_size()); if (!ReadBytes(offset_, size_, buffer, prepend_size_, reader)) return false; @@ -158,20 +157,20 @@ return true; } -// ==== ShellVideoAU ======================================================= +// ==== VideoAU ======================================================= -class ShellVideoAU : public ShellAU { +class VideoAU : public AvcAccessUnit { public: - ShellVideoAU(uint64 offset, size_t size, size_t prepend_size, - uint8 length_of_nalu_size, bool is_keyframe, TimeDelta timestamp, - TimeDelta duration, ShellParser* parser); + VideoAU(uint64 offset, size_t size, size_t prepend_size, + uint8 length_of_nalu_size, bool is_keyframe, TimeDelta timestamp, + TimeDelta duration, ProgressiveParser* parser); private: bool IsEndOfStream() const override { return false; } bool IsValid() const override { return offset_ != 0 && size_ != 0 && timestamp_ != kNoTimestamp; } - bool Read(ShellDataSourceReader* reader, DecoderBuffer* buffer) override; + bool Read(DataSourceReader* reader, DecoderBuffer* buffer) override; Type GetType() const override { return DemuxerStream::VIDEO; } bool IsKeyframe() const override { return is_keyframe_; } bool AddPrepend() const override { return is_keyframe_; } @@ -193,13 +192,13 @@ bool is_keyframe_; TimeDelta timestamp_; TimeDelta duration_; - ShellParser* parser_; + ProgressiveParser* parser_; }; -ShellVideoAU::ShellVideoAU(uint64 offset, size_t size, size_t prepend_size, - uint8 length_of_nalu_size, bool is_keyframe, - TimeDelta timestamp, TimeDelta duration, - ShellParser* parser) +VideoAU::VideoAU(uint64 offset, size_t size, size_t prepend_size, + uint8 length_of_nalu_size, bool is_keyframe, + TimeDelta timestamp, TimeDelta duration, + ProgressiveParser* parser) : offset_(offset), size_(size), prepend_size_(prepend_size), @@ -212,7 +211,7 @@ CHECK_NE(length_of_nalu_size_, 3); } -bool ShellVideoAU::Read(ShellDataSourceReader* reader, DecoderBuffer* buffer) { +bool VideoAU::Read(DataSourceReader* reader, DecoderBuffer* buffer) { size_t au_left = size_; // bytes left in the AU uint64 au_offset = offset_; // offset to read in the reader size_t buf_left = buffer->data_size(); // bytes left in the buffer @@ -280,33 +279,34 @@ } // namespace -// ==== ShellAU ================================================================ +// ==== AvcAccessUnit +// ================================================================ -ShellAU::ShellAU() {} +AvcAccessUnit::AvcAccessUnit() {} -ShellAU::~ShellAU() {} +AvcAccessUnit::~AvcAccessUnit() {} // static -scoped_refptr<ShellAU> ShellAU::CreateEndOfStreamAU(DemuxerStream::Type type, - TimeDelta timestamp) { - return new ShellEndOfStreamAU(type, timestamp); +scoped_refptr<AvcAccessUnit> AvcAccessUnit::CreateEndOfStreamAU( + DemuxerStream::Type type, TimeDelta timestamp) { + return new EndOfStreamAU(type, timestamp); } // static -scoped_refptr<ShellAU> ShellAU::CreateAudioAU( +scoped_refptr<AvcAccessUnit> AvcAccessUnit::CreateAudioAU( uint64 offset, size_t size, size_t prepend_size, bool is_keyframe, - TimeDelta timestamp, TimeDelta duration, ShellParser* parser) { - return new ShellAudioAU(offset, size, prepend_size, is_keyframe, timestamp, - duration, parser); + TimeDelta timestamp, TimeDelta duration, ProgressiveParser* parser) { + return new AudioAU(offset, size, prepend_size, is_keyframe, timestamp, + duration, parser); } // static -scoped_refptr<ShellAU> ShellAU::CreateVideoAU( +scoped_refptr<AvcAccessUnit> AvcAccessUnit::CreateVideoAU( uint64 offset, size_t size, size_t prepend_size, uint8 length_of_nalu_size, bool is_keyframe, TimeDelta timestamp, TimeDelta duration, - ShellParser* parser) { - return new ShellVideoAU(offset, size, prepend_size, length_of_nalu_size, - is_keyframe, timestamp, duration, parser); + ProgressiveParser* parser) { + return new VideoAU(offset, size, prepend_size, length_of_nalu_size, + is_keyframe, timestamp, duration, parser); } } // namespace media
diff --git a/src/cobalt/media/filters/shell_au.h b/src/cobalt/media/progressive/avc_access_unit.h similarity index 63% rename from src/cobalt/media/filters/shell_au.h rename to src/cobalt/media/progressive/avc_access_unit.h index d6254e4..7c283e9 100644 --- a/src/cobalt/media/filters/shell_au.h +++ b/src/cobalt/media/progressive/avc_access_unit.h
@@ -12,44 +12,44 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef COBALT_MEDIA_FILTERS_SHELL_AU_H_ -#define COBALT_MEDIA_FILTERS_SHELL_AU_H_ +#ifndef COBALT_MEDIA_PROGRESSIVE_ACCESS_UNIT_H_ +#define COBALT_MEDIA_PROGRESSIVE_ACCESS_UNIT_H_ #include "base/memory/ref_counted.h" #include "cobalt/media/base/demuxer_stream.h" -#include "cobalt/media/base/shell_data_source_reader.h" +#include "cobalt/media/progressive/data_source_reader.h" namespace cobalt { namespace media { -class ShellParser; +class ProgressiveParser; static const int kAnnexBStartCodeSize = 4; static const uint8_t kAnnexBStartCode[] = {0, 0, 0, 1}; -// The basic unit of currency between ShellDemuxer and ShellParser, the ShellAU -// defines all needed information for a given AccessUnit (Frame) of encoded -// media data. -class ShellAU : public base::RefCountedThreadSafe<ShellAU> { +// The basic unit of currency between ProgressiveDemuxer and ProgressiveParser, +// the AvcAccessUnit defines all needed information for a given AvcAccessUnit +// (Frame) of encoded media data. +class AvcAccessUnit : public base::RefCountedThreadSafe<AvcAccessUnit> { public: typedef base::TimeDelta TimeDelta; typedef DemuxerStream::Type Type; - static scoped_refptr<ShellAU> CreateEndOfStreamAU(Type type, - TimeDelta timestamp); - static scoped_refptr<ShellAU> CreateAudioAU( + static scoped_refptr<AvcAccessUnit> CreateEndOfStreamAU(Type type, + TimeDelta timestamp); + static scoped_refptr<AvcAccessUnit> CreateAudioAU( uint64 offset, size_t size, size_t prepend_size, bool is_keyframe, - TimeDelta timestamp, TimeDelta duration, ShellParser* parser); - static scoped_refptr<ShellAU> CreateVideoAU( + TimeDelta timestamp, TimeDelta duration, ProgressiveParser* parser); + static scoped_refptr<AvcAccessUnit> CreateVideoAU( uint64 offset, size_t size, size_t prepend_size, uint8 length_of_nalu_size, bool is_keyframe, TimeDelta timestamp, - TimeDelta duration, ShellParser* parser); + TimeDelta duration, ProgressiveParser* parser); virtual bool IsEndOfStream() const = 0; virtual bool IsValid() const = 0; // Read an AU from reader to buffer and also do all the necessary operations // like prepending head to make it ready to decode. - virtual bool Read(ShellDataSourceReader* reader, DecoderBuffer* buffer) = 0; + virtual bool Read(DataSourceReader* reader, DecoderBuffer* buffer) = 0; virtual Type GetType() const = 0; virtual bool IsKeyframe() const = 0; virtual bool AddPrepend() const = 0; @@ -63,13 +63,13 @@ virtual void SetTimestamp(TimeDelta timestamp) = 0; protected: - friend class base::RefCountedThreadSafe<ShellAU>; + friend class base::RefCountedThreadSafe<AvcAccessUnit>; - ShellAU(); - virtual ~ShellAU(); + AvcAccessUnit(); + virtual ~AvcAccessUnit(); }; } // namespace media } // namespace cobalt -#endif // COBALT_MEDIA_FILTERS_SHELL_AU_H_ +#endif // COBALT_MEDIA_PROGRESSIVE_ACCESS_UNIT_H_
diff --git a/src/cobalt/media/filters/shell_avc_parser.cc b/src/cobalt/media/progressive/avc_parser.cc similarity index 92% rename from src/cobalt/media/filters/shell_avc_parser.cc rename to src/cobalt/media/progressive/avc_parser.cc index baca931..e08141a 100644 --- a/src/cobalt/media/filters/shell_avc_parser.cc +++ b/src/cobalt/media/progressive/avc_parser.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "cobalt/media/filters/shell_avc_parser.h" +#include "cobalt/media/progressive/avc_parser.h" #include <limits> #include <vector> @@ -23,9 +23,9 @@ #include "cobalt/media/base/endian_util.h" #include "cobalt/media/base/media_util.h" #include "cobalt/media/base/video_types.h" -#include "cobalt/media/filters/shell_au.h" -#include "cobalt/media/filters/shell_rbsp_stream.h" #include "cobalt/media/formats/mp4/aac.h" +#include "cobalt/media/progressive/avc_access_unit.h" +#include "cobalt/media/progressive/rbsp_stream.h" #include "starboard/memory.h" namespace cobalt { @@ -36,19 +36,19 @@ // lower five bits of first byte in SPS should be 7 static const uint8 kSPSNALType = 7; -ShellAVCParser::ShellAVCParser(scoped_refptr<ShellDataSourceReader> reader, - const scoped_refptr<MediaLog>& media_log) - : ShellParser(reader), +AVCParser::AVCParser(scoped_refptr<DataSourceReader> reader, + const scoped_refptr<MediaLog>& media_log) + : ProgressiveParser(reader), media_log_(media_log), nal_header_size_(0), video_prepend_size_(0) { DCHECK(media_log); } -ShellAVCParser::~ShellAVCParser() {} +AVCParser::~AVCParser() {} -bool ShellAVCParser::Prepend(scoped_refptr<ShellAU> au, - scoped_refptr<DecoderBuffer> buffer) { +bool AVCParser::Prepend(scoped_refptr<AvcAccessUnit> au, + scoped_refptr<DecoderBuffer> buffer) { // sanity-check inputs if (!au || !buffer) { NOTREACHED() << "bad input to Prepend()"; @@ -93,8 +93,7 @@ return true; } -bool ShellAVCParser::DownloadAndParseAVCConfigRecord(uint64 offset, - uint32 size) { +bool AVCParser::DownloadAndParseAVCConfigRecord(uint64 offset, uint32 size) { if (size == 0) { return false; } @@ -109,8 +108,8 @@ } // static -bool ShellAVCParser::ParseSPS(const uint8* sps, size_t sps_size, - ShellSPSRecord* record_out) { +bool AVCParser::ParseSPS(const uint8* sps, size_t sps_size, + SPSRecord* record_out) { DCHECK(sps) << "no sps provided"; DCHECK(record_out) << "no output structure provided"; // first byte is NAL type id, check that it is SPS @@ -119,7 +118,7 @@ return false; } // convert SPS NALU to RBSP stream - ShellRBSPStream sps_rbsp(sps + 1, sps_size - 1); + RBSPStream sps_rbsp(sps + 1, sps_size - 1); uint8 profile_idc = 0; if (!sps_rbsp.ReadByte(&profile_idc)) { DLOG(ERROR) << "failure reading profile_idc from sps RBSP"; @@ -294,7 +293,7 @@ return true; } -bool ShellAVCParser::ParseAVCConfigRecord(uint8* buffer, uint32 size) { +bool AVCParser::ParseAVCConfigRecord(uint8* buffer, uint32 size) { if (size < kAVCConfigMinSize) { DLOG(ERROR) << base::StringPrintf("AVC config record bad size: %d", size); return false; @@ -392,7 +391,7 @@ } } // now we parse the valid SPS we extracted from byte stream earlier. - ShellSPSRecord sps_record; + SPSRecord sps_record; if (!ParseSPS(buffer + usable_sps_offset, usable_sps_size, &sps_record)) { DLOG(WARNING) << "error parsing SPS"; return false; @@ -409,8 +408,8 @@ buffer + usable_pps_offset, usable_pps_size); } -bool ShellAVCParser::BuildAnnexBPrepend(uint8* sps, uint32 sps_size, uint8* pps, - uint32 pps_size) { +bool AVCParser::BuildAnnexBPrepend(uint8* sps, uint32 sps_size, uint8* pps, + uint32 pps_size) { // We will need to attach the sps and pps (if provided) to each keyframe // video packet, with the AnnexB start code in front of each. Start with // sps size and start code @@ -445,7 +444,7 @@ return true; } -void ShellAVCParser::ParseAudioSpecificConfig(uint8 b0, uint8 b1) { +void AVCParser::ParseAudioSpecificConfig(uint8 b0, uint8 b1) { media::mp4::AAC aac; std::vector<uint8> aac_config(2); @@ -472,8 +471,8 @@ Unencrypted(), base::TimeDelta(), 0); } -size_t ShellAVCParser::CalculatePrependSize(DemuxerStream::Type type, - bool is_keyframe) { +size_t AVCParser::CalculatePrependSize(DemuxerStream::Type type, + bool is_keyframe) { size_t prepend_size = 0; if (type == DemuxerStream::VIDEO) { bool needs_prepend = is_keyframe;
diff --git a/src/cobalt/media/filters/shell_avc_parser.h b/src/cobalt/media/progressive/avc_parser.h similarity index 77% rename from src/cobalt/media/filters/shell_avc_parser.h rename to src/cobalt/media/progressive/avc_parser.h index 758a7a2..e383bdf 100644 --- a/src/cobalt/media/filters/shell_avc_parser.h +++ b/src/cobalt/media/progressive/avc_parser.h
@@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef COBALT_MEDIA_FILTERS_SHELL_AVC_PARSER_H_ -#define COBALT_MEDIA_FILTERS_SHELL_AVC_PARSER_H_ +#ifndef COBALT_MEDIA_PROGRESSIVE_AVC_PARSER_H_ +#define COBALT_MEDIA_PROGRESSIVE_AVC_PARSER_H_ #include <vector> #include "cobalt/media/base/media_log.h" -#include "cobalt/media/filters/shell_parser.h" +#include "cobalt/media/progressive/progressive_parser.h" namespace cobalt { namespace media { @@ -29,27 +29,27 @@ static const int kAnnexBPrependMaxSize = 1024; // while not an actual parser, provides shared functionality to both the -// mp4 and flv parsers which derive from it. Implements part of ShellParser -// while leaving the rest for its children. -class ShellAVCParser : public ShellParser { +// mp4 and flv parsers which derive from it. Implements part of +// ProgressiveParser while leaving the rest for its children. +class AVCParser : public ProgressiveParser { public: - explicit ShellAVCParser(scoped_refptr<ShellDataSourceReader> reader, - const scoped_refptr<MediaLog>& media_log); - virtual ~ShellAVCParser(); + explicit AVCParser(scoped_refptr<DataSourceReader> reader, + const scoped_refptr<MediaLog>& media_log); + virtual ~AVCParser(); - struct ShellSPSRecord { + struct SPSRecord { math::Size coded_size; math::Rect visible_rect; math::Size natural_size; uint32 num_ref_frames; }; static bool ParseSPS(const uint8* sps, size_t sps_size, - ShellSPSRecord* record_out); + SPSRecord* record_out); // GetNextAU we must pass on to FLV or MP4 children. - virtual scoped_refptr<ShellAU> GetNextAU(DemuxerStream::Type type) = 0; + virtual scoped_refptr<AvcAccessUnit> GetNextAU(DemuxerStream::Type type) = 0; // Prepends are common to all AVC/AAC containers so we can do this one here. - bool Prepend(scoped_refptr<ShellAU> au, + bool Prepend(scoped_refptr<AvcAccessUnit> au, scoped_refptr<DecoderBuffer> buffer) override; protected: @@ -77,4 +77,4 @@ } // namespace media } // namespace cobalt -#endif // COBALT_MEDIA_FILTERS_SHELL_AVC_PARSER_H_ +#endif // COBALT_MEDIA_PROGRESSIVE_AVC_PARSER_H_
diff --git a/src/cobalt/media/base/shell_data_source_reader.cc b/src/cobalt/media/progressive/data_source_reader.cc similarity index 81% rename from src/cobalt/media/base/shell_data_source_reader.cc rename to src/cobalt/media/progressive/data_source_reader.cc index 2c7c38f..fd4ff71 100644 --- a/src/cobalt/media/base/shell_data_source_reader.cc +++ b/src/cobalt/media/progressive/data_source_reader.cc
@@ -12,16 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "cobalt/media/base/shell_data_source_reader.h" +#include "cobalt/media/progressive/data_source_reader.h" #include "starboard/types.h" namespace cobalt { namespace media { -const int ShellDataSourceReader::kReadError = DataSource::kReadError; +const int DataSourceReader::kReadError = DataSource::kReadError; -ShellDataSourceReader::ShellDataSourceReader() +DataSourceReader::DataSourceReader() : data_source_(NULL), blocking_read_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC, base::WaitableEvent::InitialState::NOT_SIGNALED), @@ -29,15 +29,15 @@ read_has_failed_(false), last_bytes_read_(0) {} -ShellDataSourceReader::~ShellDataSourceReader() {} +DataSourceReader::~DataSourceReader() {} -void ShellDataSourceReader::SetDataSource(DataSource* data_source) { +void DataSourceReader::SetDataSource(DataSource* data_source) { DCHECK(data_source); data_source_ = data_source; } // currently only single-threaded reads supported -int ShellDataSourceReader::BlockingRead(int64 position, int size, uint8* data) { +int DataSourceReader::BlockingRead(int64 position, int size, uint8* data) { // read failures are unrecoverable, all subsequent reads will also fail if (read_has_failed_) { return kReadError; @@ -57,7 +57,7 @@ } data_source_->Read( position, size, data, - base::Bind(&ShellDataSourceReader::BlockingReadCompleted, this)); + base::Bind(&DataSourceReader::BlockingReadCompleted, this)); } // wait for callback on read completion @@ -91,7 +91,7 @@ return total_bytes_read; } -void ShellDataSourceReader::Stop() { +void DataSourceReader::Stop() { if (data_source_) { data_source_->Stop(); @@ -100,13 +100,13 @@ } } -void ShellDataSourceReader::BlockingReadCompleted(int bytes_read) { +void DataSourceReader::BlockingReadCompleted(int bytes_read) { last_bytes_read_ = bytes_read; // wake up blocked thread blocking_read_event_.Signal(); } -int64 ShellDataSourceReader::FileSize() { +int64 DataSourceReader::FileSize() { if (file_size_ == -1) { base::AutoLock auto_lock(lock_); if (data_source_ && !data_source_->GetSize(&file_size_)) {
diff --git a/src/cobalt/media/base/shell_data_source_reader.h b/src/cobalt/media/progressive/data_source_reader.h similarity index 85% rename from src/cobalt/media/base/shell_data_source_reader.h rename to src/cobalt/media/progressive/data_source_reader.h index 2049a9d..c773083 100644 --- a/src/cobalt/media/base/shell_data_source_reader.h +++ b/src/cobalt/media/progressive/data_source_reader.h
@@ -12,9 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef COBALT_MEDIA_BASE_SHELL_DATA_SOURCE_READER_H_ -#define COBALT_MEDIA_BASE_SHELL_DATA_SOURCE_READER_H_ - +#ifndef COBALT_MEDIA_PROGRESSIVE_DATA_SOURCE_READER_H_ +#define COBALT_MEDIA_PROGRESSIVE_DATA_SOURCE_READER_H_ #include "base/bind.h" #include "base/callback.h" #include "base/memory/ref_counted.h" @@ -32,12 +31,11 @@ // object is also the sole owner of a pointer to DataSource. If we want to add // asynchronous reading to this object it will need its own thread and a // callback queue. -class ShellDataSourceReader - : public base::RefCountedThreadSafe<ShellDataSourceReader> { +class DataSourceReader : public base::RefCountedThreadSafe<DataSourceReader> { public: static const int kReadError; - ShellDataSourceReader(); + DataSourceReader(); virtual void SetDataSource(DataSource* data_source); // Block the calling thread's message loop until read is complete. @@ -53,8 +51,8 @@ virtual void Stop(); protected: - friend class base::RefCountedThreadSafe<ShellDataSourceReader>; - virtual ~ShellDataSourceReader(); + friend class base::RefCountedThreadSafe<DataSourceReader>; + virtual ~DataSourceReader(); // blocking read callback virtual void BlockingReadCompleted(int bytes_read); @@ -69,4 +67,4 @@ } // namespace media } // namespace cobalt -#endif // COBALT_MEDIA_BASE_SHELL_DATA_SOURCE_READER_H_ +#endif // COBALT_MEDIA_PROGRESSIVE_DATA_SOURCE_READER_H_
diff --git a/src/cobalt/media/sandbox/shell_demuxer_fuzzer.cc b/src/cobalt/media/progressive/demuxer_fuzzer.cc similarity index 78% rename from src/cobalt/media/sandbox/shell_demuxer_fuzzer.cc rename to src/cobalt/media/progressive/demuxer_fuzzer.cc index 74d1e7e..ebd2766 100644 --- a/src/cobalt/media/sandbox/shell_demuxer_fuzzer.cc +++ b/src/cobalt/media/progressive/demuxer_fuzzer.cc
@@ -25,7 +25,7 @@ #include "cobalt/media/sandbox/media_sandbox.h" #include "media/base/bind_to_loop.h" #include "media/base/pipeline_status.h" -#include "media/filters/shell_demuxer.h" +#include "media/progressive/progressive_demuxer.h" namespace cobalt { namespace media { @@ -39,19 +39,20 @@ using ::media::DemuxerHost; using ::media::DemuxerStream; using ::media::PipelineStatus; -using ::media::ShellDemuxer; +using ::media::ProgressiveDemuxer; -class ShellDemuxerFuzzer : DemuxerHost { +class DemuxerFuzzer : DemuxerHost { public: - explicit ShellDemuxerFuzzer(const std::vector<uint8>& content) + explicit DemuxerFuzzer(const std::vector<uint8>& content) : error_occurred_(false), eos_count_(0), stopped_(false) { - demuxer_ = new ShellDemuxer(base::MessageLoop::current()->task_runner(), - new InMemoryDataSource(content)); + demuxer_ = + new ProgressiveDemuxer(base::MessageLoop::current()->task_runner(), + new InMemoryDataSource(content)); } void Fuzz() { demuxer_->Initialize( - this, Bind(&ShellDemuxerFuzzer::InitializeCB, base::Unretained(this))); + this, Bind(&DemuxerFuzzer::InitializeCB, base::Unretained(this))); // Check if there is any error or if both of the audio and video streams // have reached eos. @@ -59,7 +60,7 @@ base::RunLoop().RunUntilIdle(); } - demuxer_->Stop(Bind(&ShellDemuxerFuzzer::StopCB, base::Unretained(this))); + demuxer_->Stop(Bind(&DemuxerFuzzer::StopCB, base::Unretained(this))); while (!stopped_) { base::RunLoop().RunUntilIdle(); @@ -101,10 +102,10 @@ error_occurred_ = true; return; } - audio_stream->Read(BindToCurrentLoop(Bind( - &ShellDemuxerFuzzer::ReadCB, base::Unretained(this), audio_stream))); - video_stream->Read(BindToCurrentLoop(Bind( - &ShellDemuxerFuzzer::ReadCB, base::Unretained(this), video_stream))); + audio_stream->Read(BindToCurrentLoop( + Bind(&DemuxerFuzzer::ReadCB, base::Unretained(this), audio_stream))); + video_stream->Read(BindToCurrentLoop( + Bind(&DemuxerFuzzer::ReadCB, base::Unretained(this), video_stream))); } void StopCB() { stopped_ = true; } @@ -122,18 +123,18 @@ } DCHECK(!error_occurred_); stream->Read(BindToCurrentLoop( - Bind(&ShellDemuxerFuzzer::ReadCB, base::Unretained(this), stream))); + Bind(&DemuxerFuzzer::ReadCB, base::Unretained(this), stream))); } bool error_occurred_; int eos_count_; bool stopped_; - scoped_refptr<ShellDemuxer> demuxer_; + scoped_refptr<ProgressiveDemuxer> demuxer_; }; -class ShellDemuxerFuzzerApp : public FuzzerApp { +class DemuxerFuzzerApp : public FuzzerApp { public: - explicit ShellDemuxerFuzzerApp(MediaSandbox* media_sandbox) + explicit DemuxerFuzzerApp(MediaSandbox* media_sandbox) : media_sandbox_(media_sandbox) {} std::vector<uint8> ParseFileContent( @@ -149,7 +150,7 @@ void Fuzz(const std::string& file_name, const std::vector<uint8>& fuzzing_content) override { - ShellDemuxerFuzzer demuxer_fuzzer(fuzzing_content); + DemuxerFuzzer demuxer_fuzzer(fuzzing_content); demuxer_fuzzer.Fuzz(); } @@ -159,9 +160,8 @@ int SandboxMain(int argc, char** argv) { MediaSandbox media_sandbox( - argc, argv, - base::FilePath(FILE_PATH_LITERAL("shell_demuxer_fuzzer.json"))); - ShellDemuxerFuzzerApp fuzzer_app(&media_sandbox); + argc, argv, base::FilePath(FILE_PATH_LITERAL("demuxer_fuzzer.json"))); + DemuxerFuzzerApp fuzzer_app(&media_sandbox); if (fuzzer_app.Init(argc, argv)) { fuzzer_app.RunFuzzingLoop();
diff --git a/src/cobalt/media/base/mock_shell_data_source_reader.h b/src/cobalt/media/progressive/mock_data_source_reader.h similarity index 71% rename from src/cobalt/media/base/mock_shell_data_source_reader.h rename to src/cobalt/media/progressive/mock_data_source_reader.h index 08935b2..cf3ddab 100644 --- a/src/cobalt/media/base/mock_shell_data_source_reader.h +++ b/src/cobalt/media/progressive/mock_data_source_reader.h
@@ -14,20 +14,20 @@ * limitations under the License. */ -#ifndef COBALT_MEDIA_BASE_MOCK_SHELL_DATA_SOURCE_READER_H_ -#define COBALT_MEDIA_BASE_MOCK_SHELL_DATA_SOURCE_READER_H_ +#ifndef COBALT_MEDIA_PROGRESSIVE_MOCK_DATA_SOURCE_READER_H_ +#define COBALT_MEDIA_PROGRESSIVE_MOCK_DATA_SOURCE_READER_H_ -#include "media/base/shell_data_source_reader.h" +#include "media/progressive/data_source_reader.h" #include "testing/gmock/include/gmock/gmock.h" namespace cobalt { namespace media { -class MockShellDataSourceReader : public ShellDataSourceReader { +class MockDataSourceReader : public DataSourceReader { public: - MockShellDataSourceReader() {} + MockDataSourceReader() {} - // ShellDataSourceReader implementation + // DataSourceReader implementation MOCK_METHOD1(SetDataSource, void(DataSource*)); MOCK_METHOD3(BlockingRead, int(int64, int, uint8*)); MOCK_METHOD0(FileSize, int64()); @@ -37,4 +37,4 @@ } // namespace media } // namespace cobalt -#endif // COBALT_MEDIA_BASE_MOCK_SHELL_DATA_SOURCE_READER_H_ +#endif // COBALT_MEDIA_PROGRESSIVE_MOCK_DATA_SOURCE_READER_H_
diff --git a/src/cobalt/media/filters/shell_mp4_map.cc b/src/cobalt/media/progressive/mp4_map.cc similarity index 92% rename from src/cobalt/media/filters/shell_mp4_map.cc rename to src/cobalt/media/progressive/mp4_map.cc index 3a5189e..3a65467 100644 --- a/src/cobalt/media/filters/shell_mp4_map.cc +++ b/src/cobalt/media/progressive/mp4_map.cc
@@ -12,23 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "cobalt/media/filters/shell_mp4_map.h" +#include "cobalt/media/progressive/mp4_map.h" #include <algorithm> #include "base/strings/stringprintf.h" #include "cobalt/media/base/endian_util.h" -#include "cobalt/media/filters/shell_mp4_parser.h" +#include "cobalt/media/progressive/mp4_parser.h" namespace cobalt { namespace media { // ==== TableCache ============================================================= -ShellMP4Map::TableCache::TableCache(uint64 table_offset, uint32 entry_count, - uint32 entry_size, - uint32 cache_size_entries, - scoped_refptr<ShellDataSourceReader> reader) +MP4Map::TableCache::TableCache(uint64 table_offset, uint32 entry_count, + uint32 entry_size, uint32 cache_size_entries, + scoped_refptr<DataSourceReader> reader) : entry_size_(entry_size), entry_count_(entry_count), cache_size_entries_(cache_size_entries), @@ -37,7 +36,7 @@ cache_first_entry_number_(-1), cache_entry_count_(0) {} -uint8* ShellMP4Map::TableCache::GetBytesAtEntry(uint32 entry_number) { +uint8* MP4Map::TableCache::GetBytesAtEntry(uint32 entry_number) { // don't fetch the unfetchable if (entry_number >= entry_count_) { return NULL; @@ -77,7 +76,7 @@ return &cache_[0] + (cache_offset * entry_size_); } -bool ShellMP4Map::TableCache::ReadU32Entry(uint32 entry_number, uint32* entry) { +bool MP4Map::TableCache::ReadU32Entry(uint32 entry_number, uint32* entry) { if (uint8* data = GetBytesAtEntry(entry_number)) { *entry = endian_util::load_uint32_big_endian(data); return true; @@ -86,8 +85,8 @@ return false; } -bool ShellMP4Map::TableCache::ReadU32PairEntry(uint32 entry_number, - uint32* first, uint32* second) { +bool MP4Map::TableCache::ReadU32PairEntry(uint32 entry_number, uint32* first, + uint32* second) { if (uint8* data = GetBytesAtEntry(entry_number)) { if (first) *first = endian_util::load_uint32_big_endian(data); if (second) *second = endian_util::load_uint32_big_endian(data + 4); @@ -97,8 +96,8 @@ return false; } -bool ShellMP4Map::TableCache::ReadU32EntryIntoU64(uint32 entry_number, - uint64* entry) { +bool MP4Map::TableCache::ReadU32EntryIntoU64(uint32 entry_number, + uint64* entry) { if (uint8* data = GetBytesAtEntry(entry_number)) { *entry = endian_util::load_uint32_big_endian(data); return true; @@ -107,7 +106,7 @@ return false; } -bool ShellMP4Map::TableCache::ReadU64Entry(uint32 entry_number, uint64* entry) { +bool MP4Map::TableCache::ReadU64Entry(uint32 entry_number, uint64* entry) { if (uint8* data = GetBytesAtEntry(entry_number)) { *entry = endian_util::load_uint64_big_endian(data); return true; @@ -116,7 +115,7 @@ return false; } -// ==== ShellMP4Map ============================================================ +// ==== MP4Map ============================================================ // atom | name | size | description, (*) means optional table // -----+-----------------------+------+---------------------------------------- @@ -128,7 +127,7 @@ // stts | time-to-sample | 8 | run-length sample number to duration // stsz | sample size | 4 | per-sample list of sample sizes -ShellMP4Map::ShellMP4Map(scoped_refptr<ShellDataSourceReader> reader) +MP4Map::MP4Map(scoped_refptr<DataSourceReader> reader) : reader_(reader), current_chunk_sample_(0), next_chunk_sample_(0), @@ -155,14 +154,14 @@ stts_table_index_(0), stsz_default_size_(0) {} -bool ShellMP4Map::IsComplete() { +bool MP4Map::IsComplete() { // all required table pointers must be valid for map to function return (co64_ || stco_) && stsc_ && stts_ && (stsz_ || stsz_default_size_); } // The sample size is a lookup in the stsz table, which is indexed per sample // number. -bool ShellMP4Map::GetSize(uint32 sample_number, uint32* size_out) { +bool MP4Map::GetSize(uint32 sample_number, uint32* size_out) { DCHECK(size_out); DCHECK(stsz_ || stsz_default_size_); @@ -184,7 +183,7 @@ // then use the stsz to sum samples to the byte offset with that chunk. The sum // of the chunk offset and the byte offset within the chunk is the offset of // the sample. -bool ShellMP4Map::GetOffset(uint32 sample_number, uint64* offset_out) { +bool MP4Map::GetOffset(uint32 sample_number, uint64* offset_out) { DCHECK(offset_out); DCHECK(stsc_); DCHECK(stco_ || co64_); @@ -255,7 +254,7 @@ // durations to find the dts of that sample number. We then integrate sample // numbers through the ctts to find the composition time offset, which we add to // the dts to return the pts. -bool ShellMP4Map::GetTimestamp(uint32 sample_number, uint64* timestamp_out) { +bool MP4Map::GetTimestamp(uint32 sample_number, uint64* timestamp_out) { DCHECK(timestamp_out); if (sample_number > highest_valid_sample_number_) { return false; @@ -280,7 +279,7 @@ } // Sum through the stts to find the duration of the given sample_number. -bool ShellMP4Map::GetDuration(uint32 sample_number, uint32* duration_out) { +bool MP4Map::GetDuration(uint32 sample_number, uint32* duration_out) { DCHECK(duration_out); if (sample_number > highest_valid_sample_number_) { return false; @@ -295,7 +294,7 @@ return true; } -bool ShellMP4Map::GetIsKeyframe(uint32 sample_number, bool* is_keyframe_out) { +bool MP4Map::GetIsKeyframe(uint32 sample_number, bool* is_keyframe_out) { DCHECK(is_keyframe_out); if (sample_number > highest_valid_sample_number_) { return false; @@ -336,14 +335,14 @@ return true; } -bool ShellMP4Map::IsEOS(uint32 sample_number) { +bool MP4Map::IsEOS(uint32 sample_number) { return (sample_number > highest_valid_sample_number_); } // First look up the sample number for the provided timestamp by integrating // timestamps through the stts. Then do a binary search on the stss to find the // keyframe nearest that sample number. -bool ShellMP4Map::GetKeyframe(uint64 timestamp, uint32* sample_out) { +bool MP4Map::GetKeyframe(uint64 timestamp, uint32* sample_out) { DCHECK(sample_out); // Advance stts to the provided timestamp range if (!stts_AdvanceToTime(timestamp)) { @@ -375,8 +374,8 @@ // Set up map state and load first part of table, or entire table if it is small // enough, for each of the supporated atoms. -bool ShellMP4Map::SetAtom(uint32 four_cc, uint64 offset, uint64 size, - uint32 cache_size_entries, const uint8* atom) { +bool MP4Map::SetAtom(uint32 four_cc, uint64 offset, uint64 size, + uint32 cache_size_entries, const uint8* atom) { // All map atoms are variable-length tables starting with 4 bytes of // version/flag info followed by a uint32 indicating the number of items in // table. The stsz atom bucks tradition by putting an optional default value @@ -463,7 +462,7 @@ return atom_init; } -bool ShellMP4Map::co64_Init() { +bool MP4Map::co64_Init() { DCHECK(co64_); // load offset of first chunk into current_chunk_offset_ if (co64_->GetEntryCount() > 0) { @@ -482,7 +481,7 @@ // uint32 sample count // uint32 composition offset in ticks // -bool ShellMP4Map::ctts_Init() { +bool MP4Map::ctts_Init() { DCHECK(ctts_); // get cache segment vector to reserve table entries in advance int cache_segments = @@ -506,7 +505,7 @@ // To find the composition offset of a given sample number we must integrate // through the ctts to find the range of samples containing sample_number. Note // that the ctts is an optional table. -bool ShellMP4Map::ctts_AdvanceToSample(uint32 sample_number) { +bool MP4Map::ctts_AdvanceToSample(uint32 sample_number) { // ctts table is optional, so treat not having one as non-fatal if (!ctts_) { return true; @@ -573,8 +572,8 @@ return true; } -bool ShellMP4Map::ctts_SlipCacheToSample(uint32 sample_number, - int starting_cache_index) { +bool MP4Map::ctts_SlipCacheToSample(uint32 sample_number, + int starting_cache_index) { DCHECK_LT(starting_cache_index, ctts_samples_.size()); int cache_index = starting_cache_index; for (; cache_index + 1 < ctts_samples_.size(); cache_index++) { @@ -593,7 +592,7 @@ return true; } -bool ShellMP4Map::stco_Init() { +bool MP4Map::stco_Init() { DCHECK(stco_); // load offset of first chunk into current_chunk_offset_ if (stco_->GetEntryCount() > 0) { @@ -610,7 +609,7 @@ // uint32 first chunk number with this sample count // uint32 samples-per-chunk // uint32 sample description id (unused) -bool ShellMP4Map::stsc_Init() { +bool MP4Map::stsc_Init() { DCHECK(stsc_); // set up vector to correct final size int cache_segments = @@ -660,7 +659,7 @@ // to be consumed incrementally and with minimal memory consumption we calculate // this integration step only when needed, and save results for each cached // piece of the table, to avoid having to recalculate needed data. -bool ShellMP4Map::stsc_AdvanceToSample(uint32 sample_number) { +bool MP4Map::stsc_AdvanceToSample(uint32 sample_number) { DCHECK(stsc_); // sample_number could be before first chunk, meaning that we are seeking // backwards and have left the current chunk. Find the closest part of the @@ -736,8 +735,8 @@ return true; } -bool ShellMP4Map::stsc_SlipCacheToSample(uint32 sample_number, - int starting_cache_index) { +bool MP4Map::stsc_SlipCacheToSample(uint32 sample_number, + int starting_cache_index) { DCHECK_LT(starting_cache_index, stsc_sample_sums_.size()); // look through old sample sums for the first entry that exceeds sample // sample_number, we want the entry right before that @@ -776,7 +775,7 @@ } // stss is a list of sample numbers that are keyframes. -bool ShellMP4Map::stss_Init() { +bool MP4Map::stss_Init() { int cache_segments = (stss_->GetEntryCount() / stss_->GetCacheSizeEntries()) + 1; stss_keyframes_.reserve(cache_segments); @@ -800,7 +799,7 @@ } // advance by one table entry through stss, updating cache if necessary -bool ShellMP4Map::stss_AdvanceStep() { +bool MP4Map::stss_AdvanceStep() { DCHECK(stss_); stss_last_keyframe_ = stss_next_keyframe_; stss_table_index_++; @@ -823,7 +822,7 @@ return true; } -bool ShellMP4Map::stss_FindNearestKeyframe(uint32 sample_number) { +bool MP4Map::stss_FindNearestKeyframe(uint32 sample_number) { DCHECK(stss_); // it is assumed that there's at least one cache entry created by // stss_Init(); @@ -955,7 +954,7 @@ // The stts table has the following per-entry layout: // uint32 sample count - number of sequential samples with this duration // uint32 sample duration - duration in ticks of this sample range -bool ShellMP4Map::stts_Init() { +bool MP4Map::stts_Init() { int cache_segments = (stts_->GetEntryCount() / stts_->GetCacheSizeEntries()) + 1; stts_samples_.reserve(cache_segments); @@ -982,7 +981,7 @@ return true; } -bool ShellMP4Map::stts_AdvanceToSample(uint32 sample_number) { +bool MP4Map::stts_AdvanceToSample(uint32 sample_number) { DCHECK(stts_); // sample_number could be before our current sample range, in which case // we skip to the nearest table entry before sample_number and integrate @@ -1015,8 +1014,8 @@ // Move our integration steps to a previously saved entry in the cache tables. // Searches linearly through the vector of old cached values, so can accept a // starting index to do the search from. -bool ShellMP4Map::stts_SlipCacheToSample(uint32 sample_number, - int starting_cache_index) { +bool MP4Map::stts_SlipCacheToSample(uint32 sample_number, + int starting_cache_index) { DCHECK_LT(starting_cache_index, stts_samples_.size()); int cache_index = starting_cache_index; for (; cache_index + 1 < stts_samples_.size(); cache_index++) { @@ -1039,7 +1038,7 @@ return true; } -bool ShellMP4Map::stts_AdvanceToTime(uint64 timestamp) { +bool MP4Map::stts_AdvanceToTime(uint64 timestamp) { DCHECK(stts_); if (timestamp < stts_first_sample_time_) { @@ -1067,7 +1066,7 @@ return true; } -bool ShellMP4Map::stts_IntegrateStep() { +bool MP4Map::stts_IntegrateStep() { // advance time to next sample range uint32 range_size = stts_next_first_sample_ - stts_first_sample_; stts_first_sample_time_ += (range_size * stts_sample_duration_); @@ -1111,8 +1110,7 @@ return true; } -bool ShellMP4Map::stts_SlipCacheToTime(uint64 timestamp, - int starting_cache_index) { +bool MP4Map::stts_SlipCacheToTime(uint64 timestamp, int starting_cache_index) { DCHECK_LT(starting_cache_index, stts_timestamps_.size()); int cache_index = starting_cache_index; for (; cache_index + 1 < stts_timestamps_.size(); cache_index++) { @@ -1135,7 +1133,7 @@ return true; } -bool ShellMP4Map::stsz_Init() { return stsz_->GetBytesAtEntry(0) != NULL; } +bool MP4Map::stsz_Init() { return stsz_->GetBytesAtEntry(0) != NULL; } } // namespace media } // namespace cobalt
diff --git a/src/cobalt/media/filters/shell_mp4_map.h b/src/cobalt/media/progressive/mp4_map.h similarity index 93% rename from src/cobalt/media/filters/shell_mp4_map.h rename to src/cobalt/media/progressive/mp4_map.h index 88e1319..93bc08f 100644 --- a/src/cobalt/media/filters/shell_mp4_map.h +++ b/src/cobalt/media/progressive/mp4_map.h
@@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef COBALT_MEDIA_FILTERS_SHELL_MP4_MAP_H_ -#define COBALT_MEDIA_FILTERS_SHELL_MP4_MAP_H_ +#ifndef COBALT_MEDIA_PROGRESSIVE_MP4_MAP_H_ +#define COBALT_MEDIA_PROGRESSIVE_MP4_MAP_H_ #include <vector> #include "base/callback.h" #include "base/memory/ref_counted.h" -#include "cobalt/media/base/shell_data_source_reader.h" +#include "cobalt/media/progressive/data_source_reader.h" namespace cobalt { namespace media { @@ -37,9 +37,9 @@ // them to provide byte offsets, sizes, and timestamps of a mp4 atom. The // caching design benefits from, but does not require, sequential access // in sample numbers. -class ShellMP4Map : public base::RefCountedThreadSafe<ShellMP4Map> { +class MP4Map : public base::RefCountedThreadSafe<MP4Map> { public: - explicit ShellMP4Map(scoped_refptr<ShellDataSourceReader> reader); + explicit MP4Map(scoped_refptr<DataSourceReader> reader); bool IsComplete(); @@ -117,7 +117,7 @@ uint32 entry_count, // number of entries in table uint32 entry_size, // size in bytes of each entry in table uint32 cache_size_entries, // number of entries to cache in mem - scoped_refptr<ShellDataSourceReader> reader); // reader to use + scoped_refptr<DataSourceReader> reader); // reader to use // The following Read* functions all read values in big endian. bool ReadU32Entry(uint32 entry_number, uint32* entry); @@ -138,7 +138,7 @@ uint32 entry_count_; // size of table in entries uint32 cache_size_entries_; // max number of entries to fit in memory uint64 table_offset_; // offset of table in stream - scoped_refptr<ShellDataSourceReader> reader_; // means to read more table + scoped_refptr<DataSourceReader> reader_; // means to read more table // current cache state std::vector<uint8> cache_; // the cached part of the table @@ -146,7 +146,7 @@ uint32 cache_entry_count_; // number of valid entries in cache }; - scoped_refptr<ShellDataSourceReader> reader_; + scoped_refptr<DataSourceReader> reader_; // current integration state for GetOffset(), we save the sum of sample sizes // within the current chunk. @@ -211,4 +211,4 @@ } // namespace media } // namespace cobalt -#endif // COBALT_MEDIA_FILTERS_SHELL_MP4_MAP_H_ +#endif // COBALT_MEDIA_PROGRESSIVE_MP4_MAP_H_
diff --git a/src/cobalt/media/filters/shell_mp4_map_unittest.cc b/src/cobalt/media/progressive/mp4_map_unittest.cc similarity index 95% rename from src/cobalt/media/filters/shell_mp4_map_unittest.cc rename to src/cobalt/media/progressive/mp4_map_unittest.cc index 1fa0a73..347b7bb 100644 --- a/src/cobalt/media/filters/shell_mp4_map_unittest.cc +++ b/src/cobalt/media/progressive/mp4_map_unittest.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "cobalt/media/filters/shell_mp4_map.h" +#include "cobalt/media/progressive/mp4_map.h" #include <stdlib.h> // for rand and srand @@ -23,8 +23,8 @@ #include <vector> #include "cobalt/media/base/endian_util.h" -#include "cobalt/media/base/mock_shell_data_source_reader.h" -#include "cobalt/media/filters/shell_mp4_parser.h" +#include "cobalt/media/progressive/mock_data_source_reader.h" +#include "cobalt/media/progressive/mp4_parser.h" #include "starboard/memory.h" #include "starboard/types.h" #include "testing/gmock/include/gmock/gmock.h" @@ -48,8 +48,8 @@ using cobalt::media::kEntrySize_stss; using cobalt::media::kEntrySize_stsz; using cobalt::media::kEntrySize_stts; -using cobalt::media::MockShellDataSourceReader; -using cobalt::media::ShellMP4Map; +using cobalt::media::MockDataSourceReader; +using cobalt::media::MP4Map; using ::testing::_; using ::testing::AllOf; @@ -403,16 +403,16 @@ } }; -class ShellMP4MapTest : public testing::Test { +class MP4MapTest : public testing::Test { protected: - ShellMP4MapTest() { + MP4MapTest() { // make a new mock reader - reader_ = new ::testing::NiceMock<MockShellDataSourceReader>(); + reader_ = new ::testing::NiceMock<MockDataSourceReader>(); // make a new map with a mock reader. - map_ = new ShellMP4Map(reader_); + map_ = new MP4Map(reader_); } - virtual ~ShellMP4MapTest() { + virtual ~MP4MapTest() { DCHECK(map_->HasOneRef()); map_ = NULL; @@ -421,7 +421,7 @@ reader_ = NULL; } - void ResetMap() { map_ = new ShellMP4Map(reader_); } + void ResetMap() { map_ = new MP4Map(reader_); } void CreateTestSampleTable(unsigned int seed, int num_of_samples, int min_sample_size, int max_sample_size, @@ -454,21 +454,21 @@ } // ==== Test Fixture Members - scoped_refptr<ShellMP4Map> map_; - scoped_refptr<MockShellDataSourceReader> reader_; + scoped_refptr<MP4Map> map_; + scoped_refptr<MockDataSourceReader> reader_; std::unique_ptr<SampleTable> sample_table_; }; // ==== SetAtom() Tests ======================================================== /* -TEST_F(ShellMP4MapTest, SetAtomWithZeroDefaultSize) { +TEST_F(MP4MapTest, SetAtomWithZeroDefaultSize) { // SetAtom() should fail with a zero default size on an stsc. NOTIMPLEMENTED(); } */ // ==== GetSize() Tests ======================================================== -TEST_F(ShellMP4MapTest, GetSizeWithDefaultSize) { +TEST_F(MP4MapTest, GetSizeWithDefaultSize) { CreateTestSampleTable(100, 1000, 0xb0df00d, 0xb0df00d, 5, 10, 5, 10, 10, 20, 10, 20); sample_table_->ClearReadStatistics(); @@ -490,7 +490,7 @@ ASSERT_EQ(sample_table_->read_count(), 0); } -TEST_F(ShellMP4MapTest, GetSizeIterationWithHugeCache) { +TEST_F(MP4MapTest, GetSizeIterationWithHugeCache) { for (int max_sample_size = 10; max_sample_size < 20; ++max_sample_size) { CreateTestSampleTable(200 + max_sample_size, 1000, 10, max_sample_size, 5, 10, 5, 10, 10, 20, 10, 20); @@ -517,7 +517,7 @@ } } -TEST_F(ShellMP4MapTest, GetSizeIterationTinyCache) { +TEST_F(MP4MapTest, GetSizeIterationTinyCache) { for (int max_sample_size = 10; max_sample_size < 20; ++max_sample_size) { CreateTestSampleTable(300 + max_sample_size, 1000, 10, max_sample_size, 5, 10, 5, 10, 10, 20, 10, 20); @@ -543,7 +543,7 @@ } } -TEST_F(ShellMP4MapTest, GetSizeRandomAccess) { +TEST_F(MP4MapTest, GetSizeRandomAccess) { CreateTestSampleTable(101, 2000, 20, 24, 5, 10, 5, 10, 10, 20, 10, 20); for (int i = 24; i < 27; ++i) { ResetMap(); @@ -593,7 +593,7 @@ // ==== GetOffset() Tests ====================================================== -TEST_F(ShellMP4MapTest, GetOffsetIterationHugeCache) { +TEST_F(MP4MapTest, GetOffsetIterationHugeCache) { for (int coindex = 0; coindex < 2; ++coindex) { CreateTestSampleTable(102 + coindex, 1000, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); @@ -617,7 +617,7 @@ } } -TEST_F(ShellMP4MapTest, GetOffsetIterationTinyCache) { +TEST_F(MP4MapTest, GetOffsetIterationTinyCache) { for (int coindex = 0; coindex < 2; ++coindex) { CreateTestSampleTable(103, 30, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); for (int i = 1; i < 12; ++i) { @@ -644,7 +644,7 @@ // Random access within cache should just result in correct re-integration // through the stsc. -TEST_F(ShellMP4MapTest, GetOffsetRandomAccessHugeCache) { +TEST_F(MP4MapTest, GetOffsetRandomAccessHugeCache) { for (int coindex = 0; coindex < 2; ++coindex) { CreateTestSampleTable(104, 300, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); @@ -664,7 +664,7 @@ // Random access across cache boundaries should not break computation of // offsets. -TEST_F(ShellMP4MapTest, GetOffsetRandomAccessTinyCache) { +TEST_F(MP4MapTest, GetOffsetRandomAccessTinyCache) { for (int coindex = 0; coindex < 2; ++coindex) { CreateTestSampleTable(105, 300, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); @@ -718,7 +718,7 @@ } } -TEST_F(ShellMP4MapTest, GetOffsetRandomAccessWithDefaultSize) { +TEST_F(MP4MapTest, GetOffsetRandomAccessWithDefaultSize) { for (int coindex = 0; coindex < 2; ++coindex) { CreateTestSampleTable(106, 300, 20, 20, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); @@ -755,7 +755,7 @@ // ==== GetDuration() Tests ==================================================== -TEST_F(ShellMP4MapTest, GetDurationIteration) { +TEST_F(MP4MapTest, GetDurationIteration) { CreateTestSampleTable(107, 60, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); SetTestTable(kAtomType_stts, 2); @@ -773,7 +773,7 @@ map_->GetDuration(sample_table_->sample_count(), &failed_duration)); } -TEST_F(ShellMP4MapTest, GetDurationRandomAccess) { +TEST_F(MP4MapTest, GetDurationRandomAccess) { CreateTestSampleTable(108, 60, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); SetTestTable(kAtomType_stts, 3); @@ -810,7 +810,7 @@ // ==== GetTimestamp() Tests =================================================== -TEST_F(ShellMP4MapTest, GetTimestampIterationNoCompositionTime) { +TEST_F(MP4MapTest, GetTimestampIterationNoCompositionTime) { CreateTestSampleTable(109, 60, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); SetTestTable(kAtomType_stts, 7); @@ -828,7 +828,7 @@ map_->GetTimestamp(sample_table_->sample_count(), &failed_timestamp)); } -TEST_F(ShellMP4MapTest, GetTimestampRandomAccessNoCompositionTime) { +TEST_F(MP4MapTest, GetTimestampRandomAccessNoCompositionTime) { CreateTestSampleTable(110, 60, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); SetTestTable(kAtomType_stts, 10); @@ -858,7 +858,7 @@ } } -TEST_F(ShellMP4MapTest, GetTimestampIteration) { +TEST_F(MP4MapTest, GetTimestampIteration) { CreateTestSampleTable(111, 300, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); for (int i = 1; i < 20; ++i) { ResetMap(); @@ -879,7 +879,7 @@ } } -TEST_F(ShellMP4MapTest, GetTimestampRandomAccess) { +TEST_F(MP4MapTest, GetTimestampRandomAccess) { CreateTestSampleTable(112, 300, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); for (int i = 1; i < 20; ++i) { ResetMap(); @@ -904,7 +904,7 @@ // ==== GetIsKeyframe() Tests ================================================== // the map should consider every valid sample number a keyframe without an stss -TEST_F(ShellMP4MapTest, GetIsKeyframeNoKeyframeTable) { +TEST_F(MP4MapTest, GetIsKeyframeNoKeyframeTable) { ResetMap(); bool is_keyframe_out = false; ASSERT_TRUE(map_->GetIsKeyframe(100, &is_keyframe_out)); @@ -921,7 +921,7 @@ } } -TEST_F(ShellMP4MapTest, GetIsKeyframeIteration) { +TEST_F(MP4MapTest, GetIsKeyframeIteration) { CreateTestSampleTable(113, 1000, 0xb0df00d, 0xb0df00d, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); @@ -936,7 +936,7 @@ } } -TEST_F(ShellMP4MapTest, GetIsKeyframeRandomAccess) { +TEST_F(MP4MapTest, GetIsKeyframeRandomAccess) { CreateTestSampleTable(114, 1000, 0xb0df00d, 0xb0df00d, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); @@ -1005,7 +1005,7 @@ // every frame should be returned as a keyframe. This tests if our computation // of timestamps => sample numbers is equivalent to sample numbers => timestamps -TEST_F(ShellMP4MapTest, GetKeyframeNoKeyframeTableIteration) { +TEST_F(MP4MapTest, GetKeyframeNoKeyframeTableIteration) { CreateTestSampleTable(115, 30, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); SetTestTable(kAtomType_stts, 7); @@ -1022,7 +1022,7 @@ } } -TEST_F(ShellMP4MapTest, GetKeyframeNoKeyframeTableRandomAccess) { +TEST_F(MP4MapTest, GetKeyframeNoKeyframeTableRandomAccess) { CreateTestSampleTable(116, 30, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); SetTestTable(kAtomType_stts, 5); @@ -1056,7 +1056,7 @@ } // GetKeyframe is not normally called iteratively, so we test random access -TEST_F(ShellMP4MapTest, GetKeyframe) { +TEST_F(MP4MapTest, GetKeyframe) { CreateTestSampleTable(117, 60, 20, 25, 5, 10, 5, 10, 10, 20, 10, 20); ResetMap(); SetTestTable(kAtomType_stss, 3);
diff --git a/src/cobalt/media/filters/shell_mp4_parser.cc b/src/cobalt/media/progressive/mp4_parser.cc similarity index 91% rename from src/cobalt/media/filters/shell_mp4_parser.cc rename to src/cobalt/media/progressive/mp4_parser.cc index 7d9efb1..957395d 100644 --- a/src/cobalt/media/filters/shell_mp4_parser.cc +++ b/src/cobalt/media/progressive/mp4_parser.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "cobalt/media/filters/shell_mp4_parser.h" +#include "cobalt/media/progressive/mp4_parser.h" #include <inttypes.h> #include <limits> @@ -67,10 +67,10 @@ static const int kMapTableAtomCacheEntries_ctts = 51543 / kEntrySize_ctts; // static -PipelineStatus ShellMP4Parser::Construct( - scoped_refptr<ShellDataSourceReader> reader, - const uint8* construction_header, scoped_refptr<ShellParser>* parser, - const scoped_refptr<MediaLog>& media_log) { +PipelineStatus MP4Parser::Construct(scoped_refptr<DataSourceReader> reader, + const uint8* construction_header, + scoped_refptr<ProgressiveParser>* parser, + const scoped_refptr<MediaLog>& media_log) { DCHECK(parser); DCHECK(media_log); *parser = NULL; @@ -90,28 +90,28 @@ } // construct new mp4 parser - *parser = new ShellMP4Parser(reader, ftyp_atom_size, media_log); + *parser = new MP4Parser(reader, ftyp_atom_size, media_log); return PIPELINE_OK; } -ShellMP4Parser::ShellMP4Parser(scoped_refptr<ShellDataSourceReader> reader, - uint32 ftyp_atom_size, - const scoped_refptr<MediaLog>& media_log) - : ShellAVCParser(reader, media_log), +MP4Parser::MP4Parser(scoped_refptr<DataSourceReader> reader, + uint32 ftyp_atom_size, + const scoped_refptr<MediaLog>& media_log) + : AVCParser(reader, media_log), atom_offset_(ftyp_atom_size), // start at next atom, skipping over ftyp current_trak_is_video_(false), current_trak_is_audio_(false), current_trak_time_scale_(0), video_time_scale_hz_(0), audio_time_scale_hz_(0), - audio_map_(new ShellMP4Map(reader)), - video_map_(new ShellMP4Map(reader)), + audio_map_(new MP4Map(reader)), + video_map_(new MP4Map(reader)), audio_sample_(0), video_sample_(0), first_audio_hole_ticks_(0), first_audio_hole_(base::TimeDelta::FromSeconds(0)) {} -ShellMP4Parser::~ShellMP4Parser() {} +MP4Parser::~MP4Parser() {} // For MP4 we traverse the file's atom structure attempting to find the audio // and video configuration information and the locations in the file of the @@ -119,7 +119,7 @@ // NALUs in the file. As some of the stbl subatoms can be quite large we cache // a fixed maximum quantity of each stbl subatom and update the cache only on // miss. -bool ShellMP4Parser::ParseConfig() { +bool MP4Parser::ParseConfig() { while (!IsConfigComplete() || !audio_map_->IsComplete() || !video_map_->IsComplete()) { if (!ParseNextAtom()) { @@ -129,7 +129,7 @@ return true; } -scoped_refptr<ShellAU> ShellMP4Parser::GetNextAU(DemuxerStream::Type type) { +scoped_refptr<AvcAccessUnit> MP4Parser::GetNextAU(DemuxerStream::Type type) { uint32 size = 0; uint32 duration_ticks = 0; uint64 timestamp_ticks = 0; @@ -148,8 +148,8 @@ !audio_map_->GetTimestamp(audio_sample_, ×tamp_ticks)) { // determine if EOS or error if (audio_map_->IsEOS(audio_sample_)) { - return ShellAU::CreateEndOfStreamAU(DemuxerStream::AUDIO, - audio_track_duration_); + return AvcAccessUnit::CreateEndOfStreamAU(DemuxerStream::AUDIO, + audio_track_duration_); } else { DLOG(ERROR) << "parsed bad audio AU"; return NULL; @@ -195,8 +195,8 @@ !video_map_->GetTimestamp(video_sample_, ×tamp_ticks) || !video_map_->GetIsKeyframe(video_sample_, &is_keyframe)) { if (video_map_->IsEOS(video_sample_)) { - return ShellAU::CreateEndOfStreamAU(DemuxerStream::VIDEO, - video_track_duration_); + return AvcAccessUnit::CreateEndOfStreamAU(DemuxerStream::VIDEO, + video_track_duration_); } else { DLOG(ERROR) << "parsed bad video AU"; return NULL; @@ -219,13 +219,14 @@ size_t prepend_size = CalculatePrependSize(type, is_keyframe); if (type == DemuxerStream::AUDIO) - return ShellAU::CreateAudioAU(offset, size, prepend_size, is_keyframe, - timestamp, duration, this); - return ShellAU::CreateVideoAU(offset, size, prepend_size, nal_header_size_, - is_keyframe, timestamp, duration, this); + return AvcAccessUnit::CreateAudioAU(offset, size, prepend_size, is_keyframe, + timestamp, duration, this); + return AvcAccessUnit::CreateVideoAU(offset, size, prepend_size, + nal_header_size_, is_keyframe, timestamp, + duration, this); } -bool ShellMP4Parser::SeekTo(base::TimeDelta timestamp) { +bool MP4Parser::SeekTo(base::TimeDelta timestamp) { if (audio_time_scale_hz_ == 0 || video_time_scale_hz_ == 0) { DLOG_IF(ERROR, audio_time_scale_hz_ == 0) << "|audio_time_scale_hz_| cannot be 0."; @@ -272,7 +273,7 @@ // fourCC code | ASCII | four-byte ASCII code we treat as uint32 // extended size | uint64 | optional size field, only here if atom size is 1 // <--- rest of atom body starts here -bool ShellMP4Parser::ParseNextAtom() { +bool MP4Parser::ParseNextAtom() { uint8 atom[kAtomDownload]; int bytes_read = reader_->BlockingRead(atom_offset_, kAtomDownload, atom); if (bytes_read < kAtomDownload) { @@ -461,7 +462,7 @@ return atom_parse_success; } -bool ShellMP4Parser::ParseMP4_esds(uint64 atom_data_size) { +bool MP4Parser::ParseMP4_esds(uint64 atom_data_size) { if (atom_data_size < kFullBoxHeaderAndFlagSize) { DLOG(WARNING) << base::StringPrintf( "esds box should at least be %d bytes but now it is %" PRId64 " bytes", @@ -501,7 +502,7 @@ return false; } -bool ShellMP4Parser::ParseMP4_hdlr(uint64 atom_data_size, uint8* hdlr) { +bool MP4Parser::ParseMP4_hdlr(uint64 atom_data_size, uint8* hdlr) { // ensure we're downloading enough of the hdlr to parse DCHECK_LE(kDesiredBytes_hdlr + 16, kAtomDownload); // sanity-check for minimum size @@ -534,7 +535,7 @@ return true; } -bool ShellMP4Parser::ParseMP4_mdhd(uint64 atom_data_size, uint8* mdhd) { +bool MP4Parser::ParseMP4_mdhd(uint64 atom_data_size, uint8* mdhd) { DCHECK_LE(kDesiredBytes_mdhd + 16, kAtomDownload); if (atom_data_size < kDesiredBytes_mdhd) { DLOG(WARNING) << base::StringPrintf("bad size %" PRId64 " on mdhd", @@ -577,7 +578,7 @@ return true; } -bool ShellMP4Parser::ParseMP4_mp4a(uint64 atom_data_size, uint8* mp4a) { +bool MP4Parser::ParseMP4_mp4a(uint64 atom_data_size, uint8* mp4a) { DCHECK_LE(kDesiredBytes_mp4a + 16, kAtomDownload); // we only need the first two bytes of the header, which details the version // number of this atom, which tells us the size of the rest of the header, @@ -619,7 +620,7 @@ // 12 | time scale | 4 // 16 | duration: | 4 // -bool ShellMP4Parser::ParseMP4_mvhd(uint64 atom_data_size, uint8* mvhd) { +bool MP4Parser::ParseMP4_mvhd(uint64 atom_data_size, uint8* mvhd) { DCHECK_LE(kDesiredBytes_mvhd + 16, kAtomDownload); // it should be at least long enough for us to extract the parts we want if (atom_data_size < kDesiredBytes_mvhd) { @@ -641,8 +642,7 @@ return true; } -base::TimeDelta ShellMP4Parser::TicksToTime(uint64 ticks, - uint32 time_scale_hz) { +base::TimeDelta MP4Parser::TicksToTime(uint64 ticks, uint32 time_scale_hz) { DCHECK_NE(time_scale_hz, 0); if (time_scale_hz == 0) { @@ -652,7 +652,7 @@ time_scale_hz); } -uint64 ShellMP4Parser::TimeToTicks(base::TimeDelta time, uint32 time_scale_hz) { +uint64 MP4Parser::TimeToTicks(base::TimeDelta time, uint32 time_scale_hz) { DCHECK_NE(time_scale_hz, 0); if (time_scale_hz == 0) {
diff --git a/src/cobalt/media/filters/shell_mp4_parser.h b/src/cobalt/media/progressive/mp4_parser.h similarity index 82% rename from src/cobalt/media/filters/shell_mp4_parser.h rename to src/cobalt/media/progressive/mp4_parser.h index 6a16b9f..6d0d617 100644 --- a/src/cobalt/media/filters/shell_mp4_parser.h +++ b/src/cobalt/media/progressive/mp4_parser.h
@@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef COBALT_MEDIA_FILTERS_SHELL_MP4_PARSER_H_ -#define COBALT_MEDIA_FILTERS_SHELL_MP4_PARSER_H_ +#ifndef COBALT_MEDIA_PROGRESSIVE_MP4_PARSER_H_ +#define COBALT_MEDIA_PROGRESSIVE_MP4_PARSER_H_ #include "cobalt/media/base/media_log.h" -#include "cobalt/media/filters/shell_avc_parser.h" -#include "cobalt/media/filters/shell_mp4_map.h" +#include "cobalt/media/progressive/avc_parser.h" +#include "cobalt/media/progressive/mp4_map.h" namespace cobalt { namespace media { @@ -27,7 +27,7 @@ // second download (typically), but no larger. This is currently set at 16 // bytes for the 8 byte header + optional 8 byte size extension plus 20 bytes // for the needed values within an mvhd header. We leave this is the header so -// that ShellMP4Map can re-use, +// that MP4Map can re-use, static const int kAtomDownload = 36; // mp4 atom fourCC codes as big-endian unsigned ints @@ -59,24 +59,23 @@ static const uint32 kAtomType_vmhd = 0x766d6864; // skip whole atom // TODO: mp4v!! -class ShellMP4Parser : public ShellAVCParser { +class MP4Parser : public AVCParser { public: // Attempts to make sense of the provided bytes of the top of a file as an // flv, and if it does make sense returns PIPELINE_OK and |*parser| contains a - // ShellMP4Parser initialized with some basic state. If it doesn't make sense + // MP4Parser initialized with some basic state. If it doesn't make sense // this returns an error status and |*parser| contains NULL. - static PipelineStatus Construct(scoped_refptr<ShellDataSourceReader> reader, + static PipelineStatus Construct(scoped_refptr<DataSourceReader> reader, const uint8* construction_header, - scoped_refptr<ShellParser>* parser, + scoped_refptr<ProgressiveParser>* parser, const scoped_refptr<MediaLog>& media_log); - ShellMP4Parser(scoped_refptr<ShellDataSourceReader> reader, - uint32 ftyp_atom_size, - const scoped_refptr<MediaLog>& media_log); - ~ShellMP4Parser() override; + MP4Parser(scoped_refptr<DataSourceReader> reader, uint32 ftyp_atom_size, + const scoped_refptr<MediaLog>& media_log); + ~MP4Parser() override; - // === ShellParser implementation + // === ProgressiveParser implementation bool ParseConfig() override; - scoped_refptr<ShellAU> GetNextAU(DemuxerStream::Type type) override; + scoped_refptr<AvcAccessUnit> GetNextAU(DemuxerStream::Type type) override; bool SeekTo(base::TimeDelta timestamp) override; private: @@ -99,8 +98,8 @@ uint32 audio_time_scale_hz_; base::TimeDelta audio_track_duration_; base::TimeDelta video_track_duration_; - scoped_refptr<ShellMP4Map> audio_map_; - scoped_refptr<ShellMP4Map> video_map_; + scoped_refptr<MP4Map> audio_map_; + scoped_refptr<MP4Map> video_map_; uint32 audio_sample_; uint32 video_sample_; // for keeping buffers continuous across time scales @@ -111,4 +110,4 @@ } // namespace media } // namespace cobalt -#endif // COBALT_MEDIA_FILTERS_SHELL_MP4_PARSER_H_ +#endif // COBALT_MEDIA_PROGRESSIVE_MP4_PARSER_H_
diff --git a/src/cobalt/media/filters/shell_demuxer.cc b/src/cobalt/media/progressive/progressive_demuxer.cc similarity index 77% rename from src/cobalt/media/filters/shell_demuxer.cc rename to src/cobalt/media/progressive/progressive_demuxer.cc index 3d0a8cf..a396825 100644 --- a/src/cobalt/media/filters/shell_demuxer.cc +++ b/src/cobalt/media/progressive/progressive_demuxer.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "cobalt/media/filters/shell_demuxer.h" +#include "cobalt/media/progressive/progressive_demuxer.h" #include <inttypes.h> @@ -33,14 +33,16 @@ namespace cobalt { namespace media { -ShellDemuxerStream::ShellDemuxerStream(ShellDemuxer* demuxer, Type type) +ProgressiveDemuxerStream::ProgressiveDemuxerStream(ProgressiveDemuxer* demuxer, + Type type) : demuxer_(demuxer), type_(type) { - TRACE_EVENT0("media_stack", "ShellDemuxerStream::ShellDemuxerStream()"); + TRACE_EVENT0("media_stack", + "ProgressiveDemuxerStream::ProgressiveDemuxerStream()"); DCHECK(demuxer_); } -void ShellDemuxerStream::Read(const ReadCB& read_cb) { - TRACE_EVENT0("media_stack", "ShellDemuxerStream::Read()"); +void ProgressiveDemuxerStream::Read(const ReadCB& read_cb) { + TRACE_EVENT0("media_stack", "ProgressiveDemuxerStream::Read()"); DCHECK(!read_cb.is_null()); base::AutoLock auto_lock(lock_); @@ -48,7 +50,7 @@ // Don't accept any additional reads if we've been told to stop. // The demuxer_ may have been destroyed in the pipleine thread. if (stopped_) { - TRACE_EVENT0("media_stack", "ShellDemuxerStream::Read() EOS sent."); + TRACE_EVENT0("media_stack", "ProgressiveDemuxerStream::Read() EOS sent."); read_cb.Run(DemuxerStream::kOk, scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer())); return; @@ -61,7 +63,7 @@ // Send the oldest buffer back. scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front(); if (buffer->end_of_stream()) { - TRACE_EVENT0("media_stack", "ShellDemuxerStream::Read() EOS sent."); + TRACE_EVENT0("media_stack", "ProgressiveDemuxerStream::Read() EOS sent."); } else { // Do not pop EOS buffers, so that subsequent read requests also get EOS total_buffer_size_ -= buffer->data_size(); @@ -70,31 +72,33 @@ } read_cb.Run(DemuxerStream::kOk, buffer); } else { - TRACE_EVENT0("media_stack", "ShellDemuxerStream::Read() request queued."); + TRACE_EVENT0("media_stack", + "ProgressiveDemuxerStream::Read() request queued."); read_queue_.push_back(read_cb); } } -AudioDecoderConfig ShellDemuxerStream::audio_decoder_config() { +AudioDecoderConfig ProgressiveDemuxerStream::audio_decoder_config() { return demuxer_->AudioConfig(); } -VideoDecoderConfig ShellDemuxerStream::video_decoder_config() { +VideoDecoderConfig ProgressiveDemuxerStream::video_decoder_config() { return demuxer_->VideoConfig(); } -Ranges<base::TimeDelta> ShellDemuxerStream::GetBufferedRanges() { +Ranges<base::TimeDelta> ProgressiveDemuxerStream::GetBufferedRanges() { base::AutoLock auto_lock(lock_); return buffered_ranges_; } -DemuxerStream::Type ShellDemuxerStream::type() const { return type_; } +DemuxerStream::Type ProgressiveDemuxerStream::type() const { return type_; } -void ShellDemuxerStream::EnableBitstreamConverter() { NOTIMPLEMENTED(); } +void ProgressiveDemuxerStream::EnableBitstreamConverter() { NOTIMPLEMENTED(); } -void ShellDemuxerStream::EnqueueBuffer(scoped_refptr<DecoderBuffer> buffer) { +void ProgressiveDemuxerStream::EnqueueBuffer( + scoped_refptr<DecoderBuffer> buffer) { TRACE_EVENT1( - "media_stack", "ShellDemuxerStream::EnqueueBuffer()", "timestamp", + "media_stack", "ProgressiveDemuxerStream::EnqueueBuffer()", "timestamp", buffer->end_of_stream() ? -1 : buffer->timestamp().InMicroseconds()); base::AutoLock auto_lock(lock_); if (stopped_) { @@ -107,7 +111,7 @@ if (buffer->end_of_stream()) { TRACE_EVENT0("media_stack", - "ShellDemuxerStream::EnqueueBuffer() EOS received."); + "ProgressiveDemuxerStream::EnqueueBuffer() EOS received."); } else if (buffer->timestamp() != kNoTimestamp) { if (last_buffer_timestamp_ != kNoTimestamp && last_buffer_timestamp_ < buffer->timestamp()) { @@ -135,23 +139,23 @@ } } -base::TimeDelta ShellDemuxerStream::GetLastBufferTimestamp() const { +base::TimeDelta ProgressiveDemuxerStream::GetLastBufferTimestamp() const { base::AutoLock auto_lock(lock_); return last_buffer_timestamp_; } -size_t ShellDemuxerStream::GetTotalBufferSize() const { +size_t ProgressiveDemuxerStream::GetTotalBufferSize() const { base::AutoLock auto_lock(lock_); return total_buffer_size_; } -size_t ShellDemuxerStream::GetTotalBufferCount() const { +size_t ProgressiveDemuxerStream::GetTotalBufferCount() const { base::AutoLock auto_lock(lock_); return total_buffer_count_; } -void ShellDemuxerStream::FlushBuffers() { - TRACE_EVENT0("media_stack", "ShellDemuxerStream::FlushBuffers()"); +void ProgressiveDemuxerStream::FlushBuffers() { + TRACE_EVENT0("media_stack", "ProgressiveDemuxerStream::FlushBuffers()"); base::AutoLock auto_lock(lock_); // TODO: Investigate if the following warning is valid. DLOG_IF(WARNING, !read_queue_.empty()) << "Read requests should be empty"; @@ -161,8 +165,8 @@ last_buffer_timestamp_ = kNoTimestamp; } -void ShellDemuxerStream::Stop() { - TRACE_EVENT0("media_stack", "ShellDemuxerStream::Stop()"); +void ProgressiveDemuxerStream::Stop() { + TRACE_EVENT0("media_stack", "ProgressiveDemuxerStream::Stop()"); DCHECK(demuxer_->MessageLoopBelongsToCurrentThread()); base::AutoLock auto_lock(lock_); buffer_queue_.clear(); @@ -172,7 +176,7 @@ // fulfill any pending callbacks with EOS buffers set to end timestamp for (ReadQueue::iterator it = read_queue_.begin(); it != read_queue_.end(); ++it) { - TRACE_EVENT0("media_stack", "ShellDemuxerStream::Stop() EOS sent."); + TRACE_EVENT0("media_stack", "ProgressiveDemuxerStream::Stop() EOS sent."); it->Run(DemuxerStream::kOk, scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer())); } @@ -181,16 +185,16 @@ } // -// ShellDemuxer +// ProgressiveDemuxer // -ShellDemuxer::ShellDemuxer( +ProgressiveDemuxer::ProgressiveDemuxer( const scoped_refptr<base::SingleThreadTaskRunner>& message_loop, DecoderBuffer::Allocator* buffer_allocator, DataSource* data_source, const scoped_refptr<MediaLog>& media_log) : message_loop_(message_loop), buffer_allocator_(buffer_allocator), host_(NULL), - blocking_thread_("ShellDemuxerBlk"), + blocking_thread_("ProgDemuxerBlk"), data_source_(data_source), media_log_(media_log), stopped_(false), @@ -201,20 +205,20 @@ DCHECK(buffer_allocator_); DCHECK(data_source_); DCHECK(media_log_); - reader_ = new ShellDataSourceReader(); + reader_ = new DataSourceReader(); reader_->SetDataSource(data_source_); } -ShellDemuxer::~ShellDemuxer() { +ProgressiveDemuxer::~ProgressiveDemuxer() { // Explicitly stop |blocking_thread_| to ensure that it stops before the // destructiing of any other members. blocking_thread_.Stop(); } -void ShellDemuxer::Initialize(DemuxerHost* host, - const PipelineStatusCB& status_cb, - bool enable_text_tracks) { - TRACE_EVENT0("media_stack", "ShellDemuxer::Initialize()"); +void ProgressiveDemuxer::Initialize(DemuxerHost* host, + const PipelineStatusCB& status_cb, + bool enable_text_tracks) { + TRACE_EVENT0("media_stack", "ProgressiveDemuxer::Initialize()"); DCHECK(!enable_text_tracks); DCHECK(MessageLoopBelongsToCurrentThread()); DCHECK(reader_); @@ -226,9 +230,9 @@ // create audio and video demuxer stream objects audio_demuxer_stream_.reset( - new ShellDemuxerStream(this, DemuxerStream::AUDIO)); + new ProgressiveDemuxerStream(this, DemuxerStream::AUDIO)); video_demuxer_stream_.reset( - new ShellDemuxerStream(this, DemuxerStream::VIDEO)); + new ProgressiveDemuxerStream(this, DemuxerStream::VIDEO)); // start the blocking thread and have it download and parse the media config if (!blocking_thread_.Start()) { @@ -237,16 +241,18 @@ } blocking_thread_.task_runner()->PostTask( - FROM_HERE, base::Bind(&ShellDemuxer::ParseConfigBlocking, + FROM_HERE, base::Bind(&ProgressiveDemuxer::ParseConfigBlocking, base::Unretained(this), status_cb)); } -void ShellDemuxer::ParseConfigBlocking(const PipelineStatusCB& status_cb) { +void ProgressiveDemuxer::ParseConfigBlocking( + const PipelineStatusCB& status_cb) { DCHECK(blocking_thread_.task_runner()->BelongsToCurrentThread()); DCHECK(!parser_); // construct stream parser with error callback - PipelineStatus status = ShellParser::Construct(reader_, &parser_, media_log_); + PipelineStatus status = + ProgressiveParser::Construct(reader_, &parser_, media_log_); // if we can't construct a parser for this stream it's a fatal error, return // false so ParseConfigDone will notify the caller to Initialize() via // status_cb. @@ -286,8 +292,8 @@ ParseConfigDone(status_cb, PIPELINE_OK); } -void ShellDemuxer::ParseConfigDone(const PipelineStatusCB& status_cb, - PipelineStatus status) { +void ProgressiveDemuxer::ParseConfigDone(const PipelineStatusCB& status_cb, + PipelineStatus status) { DCHECK(blocking_thread_.task_runner()->BelongsToCurrentThread()); if (HasStopCalled()) { @@ -306,18 +312,18 @@ status_cb.Run(PIPELINE_OK); } -void ShellDemuxer::Request(DemuxerStream::Type type) { +void ProgressiveDemuxer::Request(DemuxerStream::Type type) { if (!blocking_thread_.task_runner()->BelongsToCurrentThread()) { blocking_thread_.task_runner()->PostTask( FROM_HERE, - base::Bind(&ShellDemuxer::Request, base::Unretained(this), type)); + base::Bind(&ProgressiveDemuxer::Request, base::Unretained(this), type)); return; } DCHECK(!requested_au_) << "overlapping requests not supported!"; flushing_ = false; // Ask parser for next AU - scoped_refptr<ShellAU> au = parser_->GetNextAU(type); + scoped_refptr<AvcAccessUnit> au = parser_->GetNextAU(type); // fatal parsing error returns NULL or malformed AU if (!au || !au->IsValid()) { if (!HasStopCalled()) { @@ -332,12 +338,12 @@ const char* ALLOW_UNUSED_TYPE event_type = type == DemuxerStream::AUDIO ? "audio" : "video"; - TRACE_EVENT2("media_stack", "ShellDemuxer::RequestTask()", "type", event_type, - "timestamp", au->GetTimestamp().InMicroseconds()); + TRACE_EVENT2("media_stack", "ProgressiveDemuxer::RequestTask()", "type", + event_type, "timestamp", au->GetTimestamp().InMicroseconds()); // don't issue allocation requests for EOS AUs if (au->IsEndOfStream()) { - TRACE_EVENT0("media_stack", "ShellDemuxer::RequestTask() EOS sent"); + TRACE_EVENT0("media_stack", "ProgressiveDemuxer::RequestTask() EOS sent"); // enqueue EOS buffer with correct stream scoped_refptr<DecoderBuffer> eos_buffer = DecoderBuffer::CreateEOSBuffer(); if (type == DemuxerStream::AUDIO) { @@ -357,7 +363,7 @@ AllocateBuffer(); } -void ShellDemuxer::AllocateBuffer() { +void ProgressiveDemuxer::AllocateBuffer() { DCHECK(requested_au_); if (HasStopCalled()) { @@ -385,7 +391,8 @@ const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(100); blocking_thread_.message_loop()->task_runner()->PostDelayedTask( FROM_HERE, - base::Bind(&ShellDemuxer::AllocateBuffer, base::Unretained(this)), + base::Bind(&ProgressiveDemuxer::AllocateBuffer, + base::Unretained(this)), kDelay); return; } @@ -404,13 +411,14 @@ const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(100); blocking_thread_.message_loop()->task_runner()->PostDelayedTask( FROM_HERE, - base::Bind(&ShellDemuxer::AllocateBuffer, base::Unretained(this)), + base::Bind(&ProgressiveDemuxer::AllocateBuffer, + base::Unretained(this)), kDelay); } } } -void ShellDemuxer::Download(scoped_refptr<DecoderBuffer> buffer) { +void ProgressiveDemuxer::Download(scoped_refptr<DecoderBuffer> buffer) { DCHECK(blocking_thread_.task_runner()->BelongsToCurrentThread()); // We need a requested_au_ or to have canceled this request and // are buffering to a new location for this to make sense @@ -418,8 +426,9 @@ const char* ALLOW_UNUSED_TYPE event_type = requested_au_->GetType() == DemuxerStream::AUDIO ? "audio" : "video"; - TRACE_EVENT2("media_stack", "ShellDemuxer::Download()", "type", event_type, - "timestamp", requested_au_->GetTimestamp().InMicroseconds()); + TRACE_EVENT2("media_stack", "ProgressiveDemuxer::Download()", "type", + event_type, "timestamp", + requested_au_->GetTimestamp().InMicroseconds()); // do nothing if stopped if (HasStopCalled()) { DLOG(INFO) << "aborting download task, stopped"; @@ -466,11 +475,11 @@ host_->OnBufferedTimeRangesChanged(buffered); blocking_thread_.task_runner()->PostTask( - FROM_HERE, - base::Bind(&ShellDemuxer::IssueNextRequest, base::Unretained(this))); + FROM_HERE, base::Bind(&ProgressiveDemuxer::IssueNextRequest, + base::Unretained(this))); } -void ShellDemuxer::IssueNextRequest() { +void ProgressiveDemuxer::IssueNextRequest() { DCHECK(!requested_au_); // if we're stopped don't download anymore if (HasStopCalled()) { @@ -519,10 +528,10 @@ // running in a tight loop and seek or stop request has no chance to kick in. blocking_thread_.task_runner()->PostTask( FROM_HERE, - base::Bind(&ShellDemuxer::Request, base::Unretained(this), type)); + base::Bind(&ProgressiveDemuxer::Request, base::Unretained(this), type)); } -void ShellDemuxer::Stop() { +void ProgressiveDemuxer::Stop() { DCHECK(MessageLoopBelongsToCurrentThread()); // set our internal stop flag, to not treat read failures as // errors anymore but as a natural part of stopping @@ -535,8 +544,8 @@ reader_->Stop(); } -void ShellDemuxer::DataSourceStopped(const base::Closure& callback) { - TRACE_EVENT0("media_stack", "ShellDemuxer::DataSourceStopped()"); +void ProgressiveDemuxer::DataSourceStopped(const base::Closure& callback) { + TRACE_EVENT0("media_stack", "ProgressiveDemuxer::DataSourceStopped()"); DCHECK(MessageLoopBelongsToCurrentThread()); // stop the download thread blocking_thread_.Stop(); @@ -548,20 +557,23 @@ callback.Run(); } -bool ShellDemuxer::HasStopCalled() { +bool ProgressiveDemuxer::HasStopCalled() { base::AutoLock auto_lock(lock_for_stopped_); return stopped_; } -void ShellDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { +void ProgressiveDemuxer::Seek(base::TimeDelta time, + const PipelineStatusCB& cb) { blocking_thread_.message_loop()->task_runner()->PostTask( - FROM_HERE, base::Bind(&ShellDemuxer::SeekTask, base::Unretained(this), - time, BindToCurrentLoop(cb))); + FROM_HERE, + base::Bind(&ProgressiveDemuxer::SeekTask, base::Unretained(this), time, + BindToCurrentLoop(cb))); } // runs on blocking thread -void ShellDemuxer::SeekTask(base::TimeDelta time, const PipelineStatusCB& cb) { - TRACE_EVENT1("media_stack", "ShellDemuxer::SeekTask()", "timestamp", +void ProgressiveDemuxer::SeekTask(base::TimeDelta time, + const PipelineStatusCB& cb) { + TRACE_EVENT1("media_stack", "ProgressiveDemuxer::SeekTask()", "timestamp", time.InMicroseconds()); DLOG(INFO) << base::StringPrintf("seek to: %" PRId64 " ms", time.InMilliseconds()); @@ -586,7 +598,7 @@ } } -DemuxerStream* ShellDemuxer::GetStream(media::DemuxerStream::Type type) { +DemuxerStream* ProgressiveDemuxer::GetStream(media::DemuxerStream::Type type) { if (type == DemuxerStream::AUDIO) { return audio_demuxer_stream_.get(); } else if (type == DemuxerStream::VIDEO) { @@ -597,20 +609,20 @@ return NULL; } -base::TimeDelta ShellDemuxer::GetStartTime() const { +base::TimeDelta ProgressiveDemuxer::GetStartTime() const { // we always assume a start time of 0 return base::TimeDelta(); } -const AudioDecoderConfig& ShellDemuxer::AudioConfig() { +const AudioDecoderConfig& ProgressiveDemuxer::AudioConfig() { return parser_->AudioConfig(); } -const VideoDecoderConfig& ShellDemuxer::VideoConfig() { +const VideoDecoderConfig& ProgressiveDemuxer::VideoConfig() { return parser_->VideoConfig(); } -bool ShellDemuxer::MessageLoopBelongsToCurrentThread() const { +bool ProgressiveDemuxer::MessageLoopBelongsToCurrentThread() const { return message_loop_->BelongsToCurrentThread(); }
diff --git a/src/cobalt/media/filters/shell_demuxer.h b/src/cobalt/media/progressive/progressive_demuxer.h similarity index 81% rename from src/cobalt/media/filters/shell_demuxer.h rename to src/cobalt/media/progressive/progressive_demuxer.h index 38f3dde..6ecb323 100644 --- a/src/cobalt/media/filters/shell_demuxer.h +++ b/src/cobalt/media/progressive/progressive_demuxer.h
@@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef COBALT_MEDIA_FILTERS_SHELL_DEMUXER_H_ -#define COBALT_MEDIA_FILTERS_SHELL_DEMUXER_H_ +#ifndef COBALT_MEDIA_PROGRESSIVE_PROGRESSIVE_DEMUXER_H_ +#define COBALT_MEDIA_PROGRESSIVE_PROGRESSIVE_DEMUXER_H_ #include <deque> #include <memory> @@ -28,17 +28,17 @@ #include "cobalt/media/base/demuxer_stream.h" #include "cobalt/media/base/media_log.h" #include "cobalt/media/base/ranges.h" -#include "cobalt/media/filters/shell_parser.h" +#include "cobalt/media/progressive/progressive_parser.h" namespace cobalt { namespace media { class DecoderBuffer; -class ShellDemuxer; +class ProgressiveDemuxer; -class ShellDemuxerStream : public DemuxerStream { +class ProgressiveDemuxerStream : public DemuxerStream { public: - ShellDemuxerStream(ShellDemuxer* demuxer, Type type); + ProgressiveDemuxerStream(ProgressiveDemuxer* demuxer, Type type); // DemuxerStream implementation void Read(const ReadCB& read_cb) override; @@ -56,7 +56,7 @@ NOTREACHED(); } - // Functions used by ShellDemuxer + // Functions used by ProgressiveDemuxer Ranges<base::TimeDelta> GetBufferedRanges(); void EnqueueBuffer(scoped_refptr<DecoderBuffer> buffer); void FlushBuffers(); @@ -72,7 +72,7 @@ void RebuildEnqueuedRanges_Locked(); // non-owning pointer to avoid circular reference - ShellDemuxer* demuxer_; + ProgressiveDemuxer* demuxer_; Type type_; // Used to protect everything below. @@ -97,19 +97,19 @@ size_t total_buffer_size_ = 0; size_t total_buffer_count_ = 0; - DISALLOW_COPY_AND_ASSIGN(ShellDemuxerStream); + DISALLOW_COPY_AND_ASSIGN(ProgressiveDemuxerStream); }; -class MEDIA_EXPORT ShellDemuxer : public Demuxer { +class MEDIA_EXPORT ProgressiveDemuxer : public Demuxer { public: - ShellDemuxer(const scoped_refptr<base::SingleThreadTaskRunner>& message_loop, - DecoderBuffer::Allocator* buffer_allocator, - DataSource* data_source, - const scoped_refptr<MediaLog>& media_log); - ~ShellDemuxer() override; + ProgressiveDemuxer( + const scoped_refptr<base::SingleThreadTaskRunner>& message_loop, + DecoderBuffer::Allocator* buffer_allocator, DataSource* data_source, + const scoped_refptr<MediaLog>& media_log); + ~ProgressiveDemuxer() override; // Demuxer implementation. - std::string GetDisplayName() const override { return "ShellDemuxer"; } + std::string GetDisplayName() const override { return "ProgressiveDemuxer"; } void Initialize(DemuxerHost* host, const PipelineStatusCB& status_cb, bool enable_text_tracks) override; void AbortPendingReads() override {} @@ -140,12 +140,12 @@ // in to it, and enqueue the data in the appropriate demuxer stream. void Request(DemuxerStream::Type type); - // The DemuxerStream objects ask their parent ShellDemuxer stream class + // The DemuxerStream objects ask their parent ProgressiveDemuxer stream class // for these configuration data rather than duplicating in the child classes const AudioDecoderConfig& AudioConfig(); const VideoDecoderConfig& VideoConfig(); - // Provide access to ShellDemuxerStream. + // Provide access to ProgressiveDemuxerStream. bool MessageLoopBelongsToCurrentThread() const; private: @@ -170,17 +170,17 @@ base::Thread blocking_thread_; DataSource* data_source_; scoped_refptr<MediaLog> media_log_; - scoped_refptr<ShellDataSourceReader> reader_; + scoped_refptr<DataSourceReader> reader_; base::Lock lock_for_stopped_; bool stopped_; bool flushing_; - std::unique_ptr<ShellDemuxerStream> audio_demuxer_stream_; - std::unique_ptr<ShellDemuxerStream> video_demuxer_stream_; - scoped_refptr<ShellParser> parser_; + std::unique_ptr<ProgressiveDemuxerStream> audio_demuxer_stream_; + std::unique_ptr<ProgressiveDemuxerStream> video_demuxer_stream_; + scoped_refptr<ProgressiveParser> parser_; - scoped_refptr<ShellAU> requested_au_; + scoped_refptr<AvcAccessUnit> requested_au_; bool audio_reached_eos_; bool video_reached_eos_; }; @@ -188,4 +188,4 @@ } // namespace media } // namespace cobalt -#endif // COBALT_MEDIA_FILTERS_SHELL_DEMUXER_H_ +#endif // COBALT_MEDIA_PROGRESSIVE_PROGRESSIVE_DEMUXER_H_
diff --git a/src/cobalt/media/filters/shell_parser.cc b/src/cobalt/media/progressive/progressive_parser.cc similarity index 71% rename from src/cobalt/media/filters/shell_parser.cc rename to src/cobalt/media/progressive/progressive_parser.cc index 3ff978e..f9ffb84 100644 --- a/src/cobalt/media/filters/shell_parser.cc +++ b/src/cobalt/media/progressive/progressive_parser.cc
@@ -12,24 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "cobalt/media/filters/shell_parser.h" +#include "cobalt/media/progressive/progressive_parser.h" #include "base/logging.h" #include "cobalt/media/base/timestamp_constants.h" -#include "cobalt/media/filters/shell_mp4_parser.h" +#include "cobalt/media/progressive/mp4_parser.h" namespace cobalt { namespace media { -// ==== ShellParser ============================================================ +// ==== ProgressiveParser +// ============================================================ // how many bytes to download of the file to determine type? -const int ShellParser::kInitialHeaderSize = 9; +const int ProgressiveParser::kInitialHeaderSize = 9; // static -PipelineStatus ShellParser::Construct( - scoped_refptr<ShellDataSourceReader> reader, - scoped_refptr<ShellParser>* parser, +PipelineStatus ProgressiveParser::Construct( + scoped_refptr<DataSourceReader> reader, + scoped_refptr<ProgressiveParser>* parser, const scoped_refptr<MediaLog>& media_log) { DCHECK(parser); DCHECK(media_log); @@ -44,15 +45,15 @@ } // attempt to construct mp4 parser from this header - return ShellMP4Parser::Construct(reader, header, parser, media_log); + return MP4Parser::Construct(reader, header, parser, media_log); } -ShellParser::ShellParser(scoped_refptr<ShellDataSourceReader> reader) +ProgressiveParser::ProgressiveParser(scoped_refptr<DataSourceReader> reader) : reader_(reader), duration_(kInfiniteDuration), bits_per_second_(0) {} -ShellParser::~ShellParser() {} +ProgressiveParser::~ProgressiveParser() {} -bool ShellParser::IsConfigComplete() { +bool ProgressiveParser::IsConfigComplete() { return video_config_.IsValidConfig() && audio_config_.IsValidConfig() && duration_ != kInfiniteDuration; }
diff --git a/src/cobalt/media/filters/shell_parser.h b/src/cobalt/media/progressive/progressive_parser.h similarity index 77% rename from src/cobalt/media/filters/shell_parser.h rename to src/cobalt/media/progressive/progressive_parser.h index 119a20c..a0e6f41 100644 --- a/src/cobalt/media/filters/shell_parser.h +++ b/src/cobalt/media/progressive/progressive_parser.h
@@ -12,31 +12,31 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef COBALT_MEDIA_FILTERS_SHELL_PARSER_H_ -#define COBALT_MEDIA_FILTERS_SHELL_PARSER_H_ - +#ifndef COBALT_MEDIA_PROGRESSIVE_PARSER_H_ +#define COBALT_MEDIA_PROGRESSIVE_PARSER_H_ #include "base/memory/ref_counted.h" #include "cobalt/media/base/audio_decoder_config.h" #include "cobalt/media/base/demuxer_stream.h" #include "cobalt/media/base/media_log.h" #include "cobalt/media/base/pipeline.h" -#include "cobalt/media/base/shell_data_source_reader.h" #include "cobalt/media/base/video_decoder_config.h" -#include "cobalt/media/filters/shell_au.h" +#include "cobalt/media/progressive/avc_access_unit.h" +#include "cobalt/media/progressive/data_source_reader.h" namespace cobalt { namespace media { -// abstract base class to define a stream parser interface used by ShellDemuxer. -class ShellParser : public base::RefCountedThreadSafe<ShellParser> { +// abstract base class to define a stream parser interface used by +// ProgressiveDemuxer. +class ProgressiveParser : public base::RefCountedThreadSafe<ProgressiveParser> { public: static const int kInitialHeaderSize; // Determine stream type, construct appropriate parser object, and returns // PIPELINE_OK on success or error code. - static PipelineStatus Construct(scoped_refptr<ShellDataSourceReader> reader, - scoped_refptr<ShellParser>* parser, + static PipelineStatus Construct(scoped_refptr<DataSourceReader> reader, + scoped_refptr<ProgressiveParser>* parser, const scoped_refptr<MediaLog>& media_log); - explicit ShellParser(scoped_refptr<ShellDataSourceReader> reader); + explicit ProgressiveParser(scoped_refptr<DataSourceReader> reader); // Seek through the file looking for audio and video configuration info, // saving as much config state as is possible. Should try to be fast but this @@ -47,10 +47,10 @@ // downloding and decoding the next access unit in the stream, or NULL on // fatal error. On success this advances the respective audio or video cursor // to the next AU. - virtual scoped_refptr<ShellAU> GetNextAU(DemuxerStream::Type type) = 0; + virtual scoped_refptr<AvcAccessUnit> GetNextAU(DemuxerStream::Type type) = 0; // Write the appropriate prepend header for the supplied au into the supplied // buffer. Return false on error. - virtual bool Prepend(scoped_refptr<ShellAU> au, + virtual bool Prepend(scoped_refptr<AvcAccessUnit> au, scoped_refptr<DecoderBuffer> buffer) = 0; // Advance internal state to provided timestamp. Return false on error. virtual bool SeekTo(base::TimeDelta timestamp) = 0; @@ -68,9 +68,9 @@ protected: // only allow RefCountedThreadSafe to delete us - friend class base::RefCountedThreadSafe<ShellParser>; - virtual ~ShellParser(); - scoped_refptr<ShellDataSourceReader> reader_; + friend class base::RefCountedThreadSafe<ProgressiveParser>; + virtual ~ProgressiveParser(); + scoped_refptr<DataSourceReader> reader_; AudioDecoderConfig audio_config_; VideoDecoderConfig video_config_; base::TimeDelta duration_; @@ -80,4 +80,4 @@ } // namespace media } // namespace cobalt -#endif // COBALT_MEDIA_FILTERS_SHELL_PARSER_H_ +#endif // COBALT_MEDIA_PROGRESSIVE_PARSER_H_
diff --git a/src/cobalt/media/filters/shell_rbsp_stream.cc b/src/cobalt/media/progressive/rbsp_stream.cc similarity index 90% rename from src/cobalt/media/filters/shell_rbsp_stream.cc rename to src/cobalt/media/progressive/rbsp_stream.cc index 6a3fb50..ea90f7a 100644 --- a/src/cobalt/media/filters/shell_rbsp_stream.cc +++ b/src/cobalt/media/progressive/rbsp_stream.cc
@@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "cobalt/media/filters/shell_rbsp_stream.h" +#include "cobalt/media/progressive/rbsp_stream.h" #include "base/logging.h" namespace cobalt { namespace media { -ShellRBSPStream::ShellRBSPStream(const uint8* nalu_buffer, - size_t nalu_buffer_size) +RBSPStream::RBSPStream(const uint8* nalu_buffer, size_t nalu_buffer_size) : nalu_buffer_(nalu_buffer), nalu_buffer_size_(nalu_buffer_size), nalu_buffer_byte_offset_(0), @@ -29,7 +28,7 @@ rbsp_bit_offset_(0) {} // read unsigned Exp-Golomb coded integer, ISO 14496-10 Section 9.1 -bool ShellRBSPStream::ReadUEV(uint32* uev_out) { +bool RBSPStream::ReadUEV(uint32* uev_out) { DCHECK(uev_out); int leading_zero_bits = -1; for (uint8 b = 0; b == 0; leading_zero_bits++) { @@ -52,7 +51,7 @@ } // read signed Exp-Golomb coded integer, ISO 14496-10 Section 9.1 -bool ShellRBSPStream::ReadSEV(int32* sev_out) { +bool RBSPStream::ReadSEV(int32* sev_out) { DCHECK(sev_out); // we start off by reading an unsigned Exp-Golomb coded number uint32 uev = 0; @@ -71,7 +70,7 @@ // read and return up to 32 bits, filling from the right, meaning that // ReadBits(17) on a stream of all 1s would return 0x01ffff -bool ShellRBSPStream::ReadBits(size_t bits, uint32* bits_out) { +bool RBSPStream::ReadBits(size_t bits, uint32* bits_out) { DCHECK(bits_out); if (bits > 32) { return false; @@ -105,7 +104,7 @@ } // jump over bytes in the RBSP stream -bool ShellRBSPStream::SkipBytes(size_t bytes) { +bool RBSPStream::SkipBytes(size_t bytes) { for (int i = 0; i < bytes; ++i) { if (!ConsumeNALUByte()) { return false; @@ -115,7 +114,7 @@ } // jump over bits in the RBSP stream -bool ShellRBSPStream::SkipBits(size_t bits) { +bool RBSPStream::SkipBits(size_t bits) { // skip bytes first size_t bytes = bits >> 3; if (bytes > 0) { @@ -152,7 +151,7 @@ // advance by one byte through the NALU buffer, respecting the encoding of // 00 00 03 => 00 00. Updates the state of current_nalu_byte_ to the new value. -bool ShellRBSPStream::ConsumeNALUByte() { +bool RBSPStream::ConsumeNALUByte() { if (nalu_buffer_byte_offset_ >= nalu_buffer_size_) { return false; } @@ -174,7 +173,7 @@ // return single bit in the LSb from the RBSP stream. Bits are read from MSb // to LSb in the stream. -bool ShellRBSPStream::ReadRBSPBit(uint8* bit_out) { +bool RBSPStream::ReadRBSPBit(uint8* bit_out) { DCHECK(bit_out); // check to see if we need to consume a fresh byte if (rbsp_bit_offset_ == 0) { @@ -190,7 +189,7 @@ return true; } -bool ShellRBSPStream::ReadRBSPByte(uint8* byte_out) { +bool RBSPStream::ReadRBSPByte(uint8* byte_out) { DCHECK(byte_out); // fast path for byte-aligned access if (rbsp_bit_offset_ == 0) {
diff --git a/src/cobalt/media/filters/shell_rbsp_stream.h b/src/cobalt/media/progressive/rbsp_stream.h similarity index 91% rename from src/cobalt/media/filters/shell_rbsp_stream.h rename to src/cobalt/media/progressive/rbsp_stream.h index 5a46499..0c8d8bc 100644 --- a/src/cobalt/media/filters/shell_rbsp_stream.h +++ b/src/cobalt/media/progressive/rbsp_stream.h
@@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef COBALT_MEDIA_FILTERS_SHELL_RBSP_STREAM_H_ -#define COBALT_MEDIA_FILTERS_SHELL_RBSP_STREAM_H_ +#ifndef COBALT_MEDIA_PROGRESSIVE_RBSP_STREAM_H_ +#define COBALT_MEDIA_PROGRESSIVE_RBSP_STREAM_H_ #include "base/basictypes.h" @@ -25,11 +25,11 @@ // that some other atoms are defined. This class takes a non-owning reference // to a buffer and extract various types from the stream while silently // consuming the extra encoding bytes and advancing a bit stream pointer. -class ShellRBSPStream { +class RBSPStream { public: // NON-OWNING pointer to buffer. It is assumed the client will dispose of // this buffer. - ShellRBSPStream(const uint8* nalu_buffer, size_t nalu_buffer_size); + RBSPStream(const uint8* nalu_buffer, size_t nalu_buffer_size); // all Read/Skip methods return the value by reference and return true // on success, false on read error/EOB. Once the object has returned // false the consistency of the data is not guaranteed. @@ -70,4 +70,4 @@ } // namespace media } // namespace cobalt -#endif // COBALT_MEDIA_FILTERS_SHELL_RBSP_STREAM_H_ +#endif // COBALT_MEDIA_PROGRESSIVE_RBSP_STREAM_H_
diff --git a/src/cobalt/media/filters/shell_rbsp_stream_unittest.cc b/src/cobalt/media/progressive/rbsp_stream_unittest.cc similarity index 89% rename from src/cobalt/media/filters/shell_rbsp_stream_unittest.cc rename to src/cobalt/media/progressive/rbsp_stream_unittest.cc index 472639b..33669ed 100644 --- a/src/cobalt/media/filters/shell_rbsp_stream_unittest.cc +++ b/src/cobalt/media/progressive/rbsp_stream_unittest.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "cobalt/media/filters/shell_rbsp_stream.h" +#include "cobalt/media/progressive/rbsp_stream.h" #include <list> #include <memory> @@ -24,11 +24,11 @@ namespace cobalt { namespace media { -class ShellRBSPStreamTest : public testing::Test { +class RBSPStreamTest : public testing::Test { protected: - ShellRBSPStreamTest() {} + RBSPStreamTest() {} - virtual ~ShellRBSPStreamTest() {} + virtual ~RBSPStreamTest() {} // Given num encode the value in signed exp-golomb syntax and push // the value on the provided bitlist @@ -76,7 +76,7 @@ } // after building a bitlist in various fun ways call this method to - // create a buffer on the heap that can be passed to ShellRBSPStream + // create a buffer on the heap that can be passed to RBSPStream // for deserialization. std::unique_ptr<uint8[]> SerializeToBuffer(const std::list<bool>& bitlist, bool add_sequence_bytes, @@ -150,7 +150,7 @@ } }; -TEST_F(ShellRBSPStreamTest, ReadUEV) { +TEST_F(RBSPStreamTest, ReadUEV) { std::list<bool> fibbits; // encode first 47 Fibonacci numbers uint32 f_n_minus_2 = 0; @@ -171,9 +171,9 @@ size_t fib_buffer_no_sequence_size; std::unique_ptr<uint8[]> fib_buffer_no_sequence = SerializeToBuffer(fibbits, false, fib_buffer_no_sequence_size); - ShellRBSPStream fib_stream(fib_buffer.get(), fib_buffer_size); - ShellRBSPStream fib_stream_no_sequence(fib_buffer_no_sequence.get(), - fib_buffer_no_sequence_size); + RBSPStream fib_stream(fib_buffer.get(), fib_buffer_size); + RBSPStream fib_stream_no_sequence(fib_buffer_no_sequence.get(), + fib_buffer_no_sequence_size); // deserialize the same sequence from both buffers uint32 uev = 0; uint32 uev_n = 0; @@ -203,7 +203,7 @@ ASSERT_FALSE(fib_stream_no_sequence.ReadUEV(&uev_n)); } -TEST_F(ShellRBSPStreamTest, ReadSEV) { +TEST_F(RBSPStreamTest, ReadSEV) { std::list<bool> lucasbits; // encode first 44 Lucas numbers with alternating sign int32 l_n_minus_2 = 1; @@ -227,10 +227,9 @@ size_t lucas_deseq_buffer_size = 0; std::unique_ptr<uint8[]> lucas_deseq_buffer = SerializeToBuffer(lucasbits, false, lucas_deseq_buffer_size); - ShellRBSPStream lucas_seq_stream(lucas_seq_buffer.get(), - lucas_seq_buffer_size); - ShellRBSPStream lucas_deseq_stream(lucas_deseq_buffer.get(), - lucas_deseq_buffer_size); + RBSPStream lucas_seq_stream(lucas_seq_buffer.get(), lucas_seq_buffer_size); + RBSPStream lucas_deseq_stream(lucas_deseq_buffer.get(), + lucas_deseq_buffer_size); l_n_minus_2 = 1; l_n_minus_1 = 2; int32 sev = 0; @@ -286,10 +285,10 @@ // 1111 111+0 (to complete the byte) 0xfe}; -TEST_F(ShellRBSPStreamTest, ReadUEVTooLarge) { +TEST_F(RBSPStreamTest, ReadUEVTooLarge) { // construct a stream from the supplied test data - ShellRBSPStream uev_too_big(kTestRBSPExpGolombTooBig, - sizeof(kTestRBSPExpGolombTooBig)); + RBSPStream uev_too_big(kTestRBSPExpGolombTooBig, + sizeof(kTestRBSPExpGolombTooBig)); // first call should succeed uint32 uev = 0; ASSERT_TRUE(uev_too_big.ReadUEV(&uev)); @@ -301,10 +300,10 @@ ASSERT_FALSE(uev_too_big.ReadUEV(&uev)); } -TEST_F(ShellRBSPStreamTest, ReadSEVTooLarge) { +TEST_F(RBSPStreamTest, ReadSEVTooLarge) { // construct a stream from the supplied test data - ShellRBSPStream sev_too_big(kTestRBSPExpGolombTooBig, - sizeof(kTestRBSPExpGolombTooBig)); + RBSPStream sev_too_big(kTestRBSPExpGolombTooBig, + sizeof(kTestRBSPExpGolombTooBig)); // first call should succeed int32 sev = 0; ASSERT_TRUE(sev_too_big.ReadSEV(&sev)); @@ -316,7 +315,7 @@ ASSERT_FALSE(sev_too_big.ReadSEV(&sev)); } -TEST_F(ShellRBSPStreamTest, ReadBit) { +TEST_F(RBSPStreamTest, ReadBit) { std::list<bool> padded_ones; // build a bitfield of 1 padded by n zeros, for n in range[0, 1024] for (int i = 0; i < 1024; i++) { @@ -329,12 +328,12 @@ size_t sequence_buff_size = 0; std::unique_ptr<uint8[]> sequence_buff = SerializeToBuffer(padded_ones, true, sequence_buff_size); - ShellRBSPStream seq_stream(sequence_buff.get(), sequence_buff_size); + RBSPStream seq_stream(sequence_buff.get(), sequence_buff_size); size_t desequence_buff_size = 0; std::unique_ptr<uint8[]> desequence_buff = SerializeToBuffer(padded_ones, false, desequence_buff_size); - ShellRBSPStream deseq_stream(desequence_buff.get(), desequence_buff_size); + RBSPStream deseq_stream(desequence_buff.get(), desequence_buff_size); for (std::list<bool>::iterator it = padded_ones.begin(); it != padded_ones.end(); ++it) { uint8 bit = 0; @@ -351,7 +350,7 @@ ASSERT_FALSE(deseq_stream.ReadByte(&fail_byte)); } -TEST_F(ShellRBSPStreamTest, ReadByte) { +TEST_F(RBSPStreamTest, ReadByte) { // build a field of 16 x (0xaa byte followed by 0 bit) std::list<bool> aa_field; for (int i = 0; i < 16; ++i) { @@ -364,7 +363,7 @@ size_t aabuff_size = 0; std::unique_ptr<uint8[]> aabuff = SerializeToBuffer(aa_field, true, aabuff_size); - ShellRBSPStream aa_stream(aabuff.get(), aabuff_size); + RBSPStream aa_stream(aabuff.get(), aabuff_size); for (int i = 0; i < 16; ++i) { uint8 aa = 0; ASSERT_TRUE(aa_stream.ReadByte(&aa)); @@ -397,11 +396,11 @@ size_t zseqbuff_size = 0; std::unique_ptr<uint8[]> zseqbuff = SerializeToBuffer(zero_field, true, zseqbuff_size); - ShellRBSPStream zseq_stream(zseqbuff.get(), zseqbuff_size); + RBSPStream zseq_stream(zseqbuff.get(), zseqbuff_size); size_t zdseqbuff_size = 0; std::unique_ptr<uint8[]> zdseqbuff = SerializeToBuffer(zero_field, false, zdseqbuff_size); - ShellRBSPStream zdseq_stream(zdseqbuff.get(), zdseqbuff_size); + RBSPStream zdseq_stream(zdseqbuff.get(), zdseqbuff_size); for (int i = 0; i < 24; ++i) { // read the leading 1 bit uint8 seq_bit = 0; @@ -454,7 +453,7 @@ } } -TEST_F(ShellRBSPStreamTest, ReadBits) { +TEST_F(RBSPStreamTest, ReadBits) { // test the assertion in the ReadBits comment, as it had a bug :) std::list<bool> seventeen_ones; for (int i = 0; i < 17; ++i) { @@ -463,8 +462,8 @@ size_t seventeen_ones_size = 0; std::unique_ptr<uint8[]> seventeen_ones_buff = SerializeToBuffer(seventeen_ones, false, seventeen_ones_size); - ShellRBSPStream seventeen_ones_stream(seventeen_ones_buff.get(), - seventeen_ones_size); + RBSPStream seventeen_ones_stream(seventeen_ones_buff.get(), + seventeen_ones_size); uint32 seventeen_ones_word = 0; ASSERT_TRUE(seventeen_ones_stream.ReadBits(17, &seventeen_ones_word)); ASSERT_EQ(seventeen_ones_word, 0x0001ffff); @@ -479,7 +478,7 @@ } size_t pows_size = 0; std::unique_ptr<uint8[]> pows_buff = SerializeToBuffer(pows, true, pows_size); - ShellRBSPStream pows_stream(pows_buff.get(), pows_size); + RBSPStream pows_stream(pows_buff.get(), pows_size); // ReadBits(0) should succeed and not modify the value of the ref output or // internal bit iterator uint32 dont_touch = 0xfeedfeed; @@ -493,7 +492,7 @@ } } -TEST_F(ShellRBSPStreamTest, SkipBytes) { +TEST_F(RBSPStreamTest, SkipBytes) { // serialize all nine-bit values from zero to 512 std::list<bool> nines; for (int i = 0; i < 512; ++i) { @@ -507,8 +506,8 @@ size_t nines_deseq_size = 0; std::unique_ptr<uint8[]> nines_deseq_buff = SerializeToBuffer(nines, false, nines_deseq_size); - ShellRBSPStream nines_stream(nines_buff.get(), nines_size); - ShellRBSPStream nines_deseq_stream(nines_deseq_buff.get(), nines_deseq_size); + RBSPStream nines_stream(nines_buff.get(), nines_size); + RBSPStream nines_deseq_stream(nines_deseq_buff.get(), nines_deseq_size); // iterate through streams, skipping in one and reading in the other, always // comparing values. for (int i = 0; i < 512; ++i) { @@ -547,9 +546,9 @@ size_t run_length_deseq_size = 0; std::unique_ptr<uint8[]> run_length_deseq_buff = SerializeToBuffer(run_length, false, run_length_deseq_size); - ShellRBSPStream run_length_stream(run_length_buff.get(), run_length_size); - ShellRBSPStream run_length_deseq_stream(run_length_deseq_buff.get(), - run_length_deseq_size); + RBSPStream run_length_stream(run_length_buff.get(), run_length_size); + RBSPStream run_length_deseq_stream(run_length_deseq_buff.get(), + run_length_deseq_size); // read first bit, skip first byte from each stream, read next bit uint8 bit = 0; ASSERT_TRUE(run_length_stream.ReadBit(&bit)); @@ -593,7 +592,7 @@ ASSERT_FALSE(run_length_deseq_stream.SkipBytes(1)); } -TEST_F(ShellRBSPStreamTest, SkipBits) { +TEST_F(RBSPStreamTest, SkipBits) { std::list<bool> one_ohs; // encode one 1, followed by one zero, followed by 2 1s, followed by 2 zeros, // etc @@ -611,8 +610,8 @@ size_t skip_ohs_size = 0; std::unique_ptr<uint8[]> skip_ohs_buff = SerializeToBuffer(one_ohs, false, skip_ohs_size); - ShellRBSPStream skip_ones(skip_ones_buff.get(), skip_ones_size); - ShellRBSPStream skip_ohs(skip_ohs_buff.get(), skip_ohs_size); + RBSPStream skip_ones(skip_ones_buff.get(), skip_ones_size); + RBSPStream skip_ohs(skip_ohs_buff.get(), skip_ohs_size); for (int i = 1; i < 64; ++i) { // skip the ones ASSERT_TRUE(skip_ones.SkipBits(i));
diff --git a/src/cobalt/media/sandbox/demuxer_helper.cc b/src/cobalt/media/sandbox/demuxer_helper.cc index fa343fa..c5b2991 100644 --- a/src/cobalt/media/sandbox/demuxer_helper.cc +++ b/src/cobalt/media/sandbox/demuxer_helper.cc
@@ -24,7 +24,7 @@ #include "media/base/bind_to_loop.h" #include "media/base/decoder_buffer.h" #include "media/base/video_decoder_config.h" -#include "media/filters/shell_demuxer.h" +#include "media/progressive/progressive_demuxer.h" namespace cobalt { namespace media { @@ -263,7 +263,7 @@ fetcher_factory->network_module(), loader::kNoCORSMode, loader::Origin())); scoped_refptr<Demuxer> demuxer = - new ::media::ShellDemuxer(media_message_loop, data_source); + new ::media::ProgressiveDemuxer(media_message_loop, data_source); demuxer->Initialize( host_, base::Bind(&DemuxerHelper::OnDemuxerReady, base::Unretained(this), demuxer, demuxer_ready_cb, bytes_to_cache));
diff --git a/src/cobalt/media/sandbox/format_guesstimator.cc b/src/cobalt/media/sandbox/format_guesstimator.cc index 9d6c3f2..a616d53 100644 --- a/src/cobalt/media/sandbox/format_guesstimator.cc +++ b/src/cobalt/media/sandbox/format_guesstimator.cc
@@ -34,8 +34,8 @@ #include "cobalt/render_tree/image.h" #include "net/base/filename_util.h" #include "net/base/url_util.h" +#include "starboard/common/file.h" #include "starboard/common/string.h" -#include "starboard/file.h" #include "starboard/memory.h" #include "starboard/types.h"
diff --git a/src/cobalt/media/sandbox/web_media_player_sandbox.cc b/src/cobalt/media/sandbox/web_media_player_sandbox.cc index c947020..f97a2b6 100644 --- a/src/cobalt/media/sandbox/web_media_player_sandbox.cc +++ b/src/cobalt/media/sandbox/web_media_player_sandbox.cc
@@ -30,8 +30,8 @@ #include "cobalt/media/sandbox/media_sandbox.h" #include "cobalt/media/sandbox/web_media_player_helper.h" #include "cobalt/render_tree/image.h" +#include "starboard/common/file.h" #include "starboard/event.h" -#include "starboard/file.h" #include "starboard/log.h" #include "starboard/system.h"
diff --git a/src/cobalt/media_capture/encoders/audio_encoder.h b/src/cobalt/media_capture/encoders/audio_encoder.h index 63134e0..0efe09b 100644 --- a/src/cobalt/media_capture/encoders/audio_encoder.h +++ b/src/cobalt/media_capture/encoders/audio_encoder.h
@@ -20,10 +20,10 @@ #include "base/basictypes.h" #include "base/strings/string_piece.h" #include "base/time/time.h" +#include "cobalt/media/base/audio_bus.h" #include "cobalt/media_stream/audio_parameters.h" #include "starboard/common/mutex.h" -#include "cobalt/media/base/shell_audio_bus.h" namespace cobalt { namespace media_capture { @@ -31,7 +31,7 @@ class AudioEncoder { public: - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; class Listener { public: @@ -44,7 +44,7 @@ virtual ~AudioEncoder() = default; // Encode raw audio data. - virtual void Encode(const ShellAudioBus& audio_bus, + virtual void Encode(const AudioBus& audio_bus, base::TimeTicks reference_time) = 0; // Finish encoding. virtual void Finish(base::TimeTicks timecode) = 0;
diff --git a/src/cobalt/media_capture/encoders/flac_audio_encoder.cc b/src/cobalt/media_capture/encoders/flac_audio_encoder.cc index 0e45933..7c57c69 100644 --- a/src/cobalt/media_capture/encoders/flac_audio_encoder.cc +++ b/src/cobalt/media_capture/encoders/flac_audio_encoder.cc
@@ -59,11 +59,11 @@ base::Bind(&FlacAudioEncoder::DestroyEncoder, base::Unretained(this))); } -void FlacAudioEncoder::Encode(const ShellAudioBus& audio_bus, +void FlacAudioEncoder::Encode(const AudioBus& audio_bus, base::TimeTicks reference_time) { - std::unique_ptr<ShellAudioBus> audio_bus_copy( - new ShellAudioBus(audio_bus.channels(), audio_bus.frames(), - audio_bus.sample_type(), audio_bus.storage_type())); + std::unique_ptr<AudioBus> audio_bus_copy( + new AudioBus(audio_bus.channels(), audio_bus.frames(), + audio_bus.sample_type(), audio_bus.storage_type())); audio_bus_copy->Assign(audio_bus); // base::Unretained usage is safe here, since we're posting to a thread that @@ -107,7 +107,7 @@ void FlacAudioEncoder::DestroyEncoder() { flac_encoder_.reset(); } -void FlacAudioEncoder::DoEncode(std::unique_ptr<ShellAudioBus> audio_bus, +void FlacAudioEncoder::DoEncode(std::unique_ptr<AudioBus> audio_bus, base::TimeTicks reference_time) { DCHECK(flac_encoder_); flac_encoder_->Encode(audio_bus.get());
diff --git a/src/cobalt/media_capture/encoders/flac_audio_encoder.h b/src/cobalt/media_capture/encoders/flac_audio_encoder.h index 90d4bd4..a982eaf 100644 --- a/src/cobalt/media_capture/encoders/flac_audio_encoder.h +++ b/src/cobalt/media_capture/encoders/flac_audio_encoder.h
@@ -36,7 +36,7 @@ // Called from the thread the object is constructed on (usually // a dedicated audio thread). - void Encode(const ShellAudioBus& audio_bus, + void Encode(const AudioBus& audio_bus, base::TimeTicks reference_time) override; // This can be called from any thread @@ -54,7 +54,7 @@ // These functions are called on the encoder thread. void CreateEncoder(const media_stream::AudioParameters& params); void DestroyEncoder(); - void DoEncode(std::unique_ptr<ShellAudioBus> audio_bus, + void DoEncode(std::unique_ptr<AudioBus> audio_bus, base::TimeTicks reference_time); void DoFinish(base::TimeTicks reference_time);
diff --git a/src/cobalt/media_capture/encoders/linear16_audio_encoder.cc b/src/cobalt/media_capture/encoders/linear16_audio_encoder.cc index f18f035..c5148ac 100644 --- a/src/cobalt/media_capture/encoders/linear16_audio_encoder.cc +++ b/src/cobalt/media_capture/encoders/linear16_audio_encoder.cc
@@ -43,9 +43,9 @@ return match_iterator == mime_type_container.begin(); } -void Linear16AudioEncoder::Encode(const ShellAudioBus& audio_bus, +void Linear16AudioEncoder::Encode(const AudioBus& audio_bus, base::TimeTicks reference_time) { - DCHECK_EQ(audio_bus.sample_type(), ShellAudioBus::kInt16); + DCHECK_EQ(audio_bus.sample_type(), AudioBus::kInt16); DCHECK_EQ(audio_bus.channels(), size_t(1)); auto data = audio_bus.interleaved_data(); size_t data_size = audio_bus.GetSampleSizeInBytes() * audio_bus.frames();
diff --git a/src/cobalt/media_capture/encoders/linear16_audio_encoder.h b/src/cobalt/media_capture/encoders/linear16_audio_encoder.h index bb5f5d7..75040f4 100644 --- a/src/cobalt/media_capture/encoders/linear16_audio_encoder.h +++ b/src/cobalt/media_capture/encoders/linear16_audio_encoder.h
@@ -29,7 +29,7 @@ static bool IsLinear16MIMEType(const base::StringPiece& mime_type); Linear16AudioEncoder() = default; - void Encode(const ShellAudioBus& audio_bus, + void Encode(const AudioBus& audio_bus, base::TimeTicks reference_time) override; void Finish(base::TimeTicks reference_time) override; std::string GetMimeType() const override;
diff --git a/src/cobalt/media_capture/media_recorder.cc b/src/cobalt/media_capture/media_recorder.cc index 3a015f0..6642bfc 100644 --- a/src/cobalt/media_capture/media_recorder.cc +++ b/src/cobalt/media_capture/media_recorder.cc
@@ -161,10 +161,10 @@ StopRecording(); } -void MediaRecorder::OnData(const ShellAudioBus& audio_bus, +void MediaRecorder::OnData(const AudioBus& audio_bus, base::TimeTicks reference_time) { // The source is always int16 data from the microphone. - DCHECK_EQ(audio_bus.sample_type(), ShellAudioBus::kInt16); + DCHECK_EQ(audio_bus.sample_type(), AudioBus::kInt16); DCHECK_EQ(audio_bus.channels(), size_t(1)); DCHECK(audio_encoder_); audio_encoder_->Encode(audio_bus, reference_time);
diff --git a/src/cobalt/media_capture/media_recorder.h b/src/cobalt/media_capture/media_recorder.h index a7b1c9d..5883af8 100644 --- a/src/cobalt/media_capture/media_recorder.h +++ b/src/cobalt/media_capture/media_recorder.h
@@ -118,7 +118,7 @@ RecordingState state() { return recording_state_; } // MediaStreamAudioSink overrides. - void OnData(const ShellAudioBus& audio_bus, + void OnData(const AudioBus& audio_bus, base::TimeTicks reference_time) override; void OnSetFormat(const media_stream::AudioParameters& params) override; void OnReadyStateChanged(
diff --git a/src/cobalt/media_capture/media_recorder_test.cc b/src/cobalt/media_capture/media_recorder_test.cc index cfc5e3c..46fab4a 100644 --- a/src/cobalt/media_capture/media_recorder_test.cc +++ b/src/cobalt/media_capture/media_recorder_test.cc
@@ -52,7 +52,7 @@ frames.push_back(32767); frames.push_back(1000); frames.push_back(0); - cobalt::media_stream::MediaStreamAudioTrack::ShellAudioBus audio_bus( + cobalt::media_stream::MediaStreamAudioTrack::AudioBus audio_bus( 1, frames.size(), frames.data()); base::TimeTicks current_time = base::TimeTicks::Now(); media_recorder->OnData(audio_bus, current_time); @@ -68,9 +68,8 @@ MOCK_METHOD0(EnsureSourceIsStarted, bool()); MOCK_METHOD0(EnsureSourceIsStopped, void()); - void DeliverDataToTracks( - const MediaStreamAudioTrack::ShellAudioBus& audio_bus, - base::TimeTicks reference_time) { + void DeliverDataToTracks(const MediaStreamAudioTrack::AudioBus& audio_bus, + base::TimeTicks reference_time) { MediaStreamAudioSource::DeliverDataToTracks(audio_bus, reference_time); } @@ -191,8 +190,8 @@ frames.push_back(32767); frames.push_back(1000); frames.push_back(0); - media_stream::MediaStreamAudioTrack::ShellAudioBus audio_bus(1, frames.size(), - frames.data()); + media_stream::MediaStreamAudioTrack::AudioBus audio_bus(1, frames.size(), + frames.data()); base::TimeTicks current_time = base::TimeTicks::Now(); media_recorder_->OnData(audio_bus, current_time); current_time += base::TimeDelta::FromSecondsD(frames.size() / kSampleRate);
diff --git a/src/cobalt/media_session/media_session_client.cc b/src/cobalt/media_session/media_session_client.cc index 3263591..4b32aa9 100644 --- a/src/cobalt/media_session/media_session_client.cc +++ b/src/cobalt/media_session/media_session_client.cc
@@ -64,7 +64,6 @@ session_state->available_actions()); } } - } // namespace MediaSessionClient::MediaSessionClient( @@ -171,38 +170,41 @@ return result; } -void MediaSessionClient::UpdatePlatformPlaybackState( - MediaSessionPlaybackState state) { +void MediaSessionClient::UpdatePlatformCobaltExtensionPlaybackState( + CobaltExtensionMediaSessionPlaybackState state) { DCHECK(media_session_->task_runner_); if (!media_session_->task_runner_->BelongsToCurrentThread()) { media_session_->task_runner_->PostTask( - FROM_HERE, base::Bind(&MediaSessionClient::UpdatePlatformPlaybackState, - base::Unretained(this), state)); + FROM_HERE, + base::Bind( + &MediaSessionClient::UpdatePlatformCobaltExtensionPlaybackState, + base::Unretained(this), state)); return; } - platform_playback_state_ = state; + platform_playback_state_ = ConvertPlaybackState(state); if (session_state_.actual_playback_state() != ComputeActualPlaybackState()) { UpdateMediaSessionState(); } + + if (!is_active() && !maybe_freeze_callback_.is_null()) { + maybe_freeze_callback_.Run(); + } } void MediaSessionClient::InvokeActionInternal( - std::unique_ptr<MediaSessionActionDetails> details) { - DCHECK(details->has_action()); + CobaltExtensionMediaSessionActionDetails* details) { + DCHECK(details->action >= 0 && + details->action < kCobaltExtensionMediaSessionActionNumActions); // Some fields should only be set for applicable actions. - DCHECK(!details->has_seek_offset() || - details->action() == kMediaSessionActionSeekforward || - details->action() == kMediaSessionActionSeekbackward); - DCHECK(!details->has_seek_time() || - details->action() == kMediaSessionActionSeekto); - DCHECK(!details->has_fast_seek() || - details->action() == kMediaSessionActionSeekto); - - // Seek times/offsets are non-negative, even for seeking backwards. - DCHECK(!details->has_seek_time() || details->seek_time() >= 0.0); - DCHECK(!details->has_seek_offset() || details->seek_offset() >= 0.0); + DCHECK(details->seek_offset < 0.0 || + details->action == kCobaltExtensionMediaSessionActionSeekforward || + details->action == kCobaltExtensionMediaSessionActionSeekbackward); + DCHECK(details->seek_time < 0.0 || + details->action == kCobaltExtensionMediaSessionActionSeekto); + DCHECK(!details->fast_seek || + details->action == kCobaltExtensionMediaSessionActionSeekto); DCHECK(media_session_->task_runner_); if (!media_session_->task_runner_->BelongsToCurrentThread()) { @@ -212,14 +214,16 @@ return; } - MediaSession::ActionMap::iterator it = - media_session_->action_map_.find(details->action()); + MediaSession::ActionMap::iterator it = media_session_->action_map_.find( + ConvertMediaSessionAction(details->action)); if (it == media_session_->action_map_.end()) { return; } - it->second->value().Run(*details); + std::unique_ptr<MediaSessionActionDetails> script_details = + ConvertActionDetails(details); + it->second->value().Run(*script_details); // Queue a session update to reflect the effects of the action. if (!media_session_->media_position_state_) { @@ -270,13 +274,14 @@ const MediaSessionState& session_state) { if (extension_ && extension_->version >= 1) { CobaltExtensionMediaSessionState ext_state; - CobaltExtensionMediaMetadata ext_metadata = {0}; size_t artwork_size = 0; if (session_state.has_metadata() && session_state.metadata().value().has_artwork()) { artwork_size = session_state.metadata().value().artwork().size(); } - ext_metadata.artwork_count = artwork_size; + std::unique_ptr<CobaltExtensionMediaImage[]> ext_artwork = + std::unique_ptr<CobaltExtensionMediaImage[]>( + new CobaltExtensionMediaImage[artwork_size]); ext_state.duration = session_state.duration(); ext_state.actual_playback_rate = session_state.actual_playback_rate(); @@ -286,12 +291,15 @@ ConvertPlaybackState(session_state.actual_playback_state()); ConvertMediaSessionActions(session_state.available_actions(), ext_state.available_actions); + std::string album = ""; + std::string artist = ""; + std::string title = ""; if (session_state.has_metadata()) { const MediaMetadataInit& metadata = session_state.metadata().value(); - ext_metadata.album = metadata.album().c_str(); - ext_metadata.artist = metadata.artist().c_str(); - ext_metadata.title = metadata.title().c_str(); + album = metadata.album(); + artist = metadata.artist(); + title = metadata.title(); if (artwork_size > 0) { const MediaImageSequence& artwork(metadata.artwork()); for (MediaImageSequence::size_type i = 0; i < artwork_size; i++) { @@ -300,26 +308,63 @@ ext_image.src = media_image.src().c_str(); ext_image.size = media_image.sizes().c_str(); ext_image.type = media_image.type().c_str(); - ext_metadata.artwork[i] = ext_image; + ext_artwork[i] = ext_image; } } - ext_state.metadata = ext_metadata; } + CobaltExtensionMediaMetadata ext_metadata = { + album.c_str(), artist.c_str(), title.c_str(), ext_artwork.get(), + artwork_size}; + ext_state.metadata = &ext_metadata; + + ext_state.update_platform_playback_state_callback = + &UpdatePlatformPlaybackStateCallback; + ext_state.invoke_action_callback = &InvokeActionCallback; + ext_state.callback_context = this; extension_->OnMediaSessionStateChanged(ext_state); } } -CobaltExtensionPlaybackState MediaSessionClient::ConvertPlaybackState( - MediaSessionPlaybackState in_state) { - switch (in_state) { +// static +void MediaSessionClient::UpdatePlatformPlaybackStateCallback( + CobaltExtensionMediaSessionPlaybackState state, void* callback_context) { + MediaSessionClient* client = + static_cast<MediaSessionClient*>(callback_context); + client->UpdatePlatformCobaltExtensionPlaybackState(state); +} + +// static +void MediaSessionClient::InvokeActionCallback( + CobaltExtensionMediaSessionActionDetails details, void* callback_context) { + MediaSessionClient* client = + static_cast<MediaSessionClient*>(callback_context); + client->InvokeCobaltExtensionAction(details); +} + +CobaltExtensionMediaSessionPlaybackState +MediaSessionClient::ConvertPlaybackState(MediaSessionPlaybackState state) { + switch (state) { case kMediaSessionPlaybackStatePlaying: - return CobaltExtensionPlaybackState::kCobaltExtensionPlaying; + return kCobaltExtensionMediaSessionPlaying; case kMediaSessionPlaybackStatePaused: - return CobaltExtensionPlaybackState::kCobaltExtensionPaused; + return kCobaltExtensionMediaSessionPaused; case kMediaSessionPlaybackStateNone: default: - return CobaltExtensionPlaybackState::kCobaltExtensionNone; + return kCobaltExtensionMediaSessionNone; + } +} + +MediaSessionPlaybackState MediaSessionClient::ConvertPlaybackState( + CobaltExtensionMediaSessionPlaybackState state) { + switch (state) { + case kCobaltExtensionMediaSessionPlaying: + return kMediaSessionPlaybackStatePlaying; + case kCobaltExtensionMediaSessionPaused: + return kMediaSessionPlaybackStatePaused; + case kCobaltExtensionMediaSessionNone: + default: + return kMediaSessionPlaybackStateNone; } } @@ -328,32 +373,73 @@ bool result[kCobaltExtensionMediaSessionActionNumActions]) { for (int i = 0; i < kCobaltExtensionMediaSessionActionNumActions; i++) { result[i] = false; - } - if (actions[kMediaSessionActionPause]) { - result[kCobaltExtensionMediaSessionActionPause] = true; - } - if (actions[kMediaSessionActionPlay]) { - result[kCobaltExtensionMediaSessionActionPlay] = true; - } - if (actions[kMediaSessionActionSeekbackward]) { - result[kCobaltExtensionMediaSessionActionSeekbackward] = true; - } - if (actions[kMediaSessionActionPrevioustrack]) { - result[kCobaltExtensionMediaSessionActionPrevioustrack] = true; - } - if (actions[kMediaSessionActionNexttrack]) { - result[kCobaltExtensionMediaSessionActionNexttrack] = true; - } - if (actions[kMediaSessionActionSeekforward]) { - result[kCobaltExtensionMediaSessionActionSeekforward] = true; - } - if (actions[kMediaSessionActionSeekto]) { - result[kCobaltExtensionMediaSessionActionSeekto] = true; - } - if (actions[kMediaSessionActionStop]) { - result[kCobaltExtensionMediaSessionActionStop] = true; + MediaSessionAction action = static_cast<MediaSessionAction>(i); + if (actions[action]) { + result[ConvertMediaSessionAction(action)] = true; + } } } +std::unique_ptr<MediaSessionActionDetails> +MediaSessionClient::ConvertActionDetails( + CobaltExtensionMediaSessionActionDetails* ext_details) { + std::unique_ptr<MediaSessionActionDetails> details( + new MediaSessionActionDetails()); + details->set_action(ConvertMediaSessionAction(ext_details->action)); + if (ext_details->seek_offset >= 0.0) { + details->set_seek_offset(ext_details->seek_offset); + } + if (ext_details->seek_time >= 0.0) { + details->set_seek_time(ext_details->seek_time); + } + details->set_fast_seek(ext_details->fast_seek); + return details; +} + +CobaltExtensionMediaSessionAction MediaSessionClient::ConvertMediaSessionAction( + MediaSessionAction action) { + switch (action) { + case kMediaSessionActionPause: + return kCobaltExtensionMediaSessionActionPause; + case kMediaSessionActionSeekbackward: + return kCobaltExtensionMediaSessionActionSeekbackward; + case kMediaSessionActionPrevioustrack: + return kCobaltExtensionMediaSessionActionPrevioustrack; + case kMediaSessionActionNexttrack: + return kCobaltExtensionMediaSessionActionNexttrack; + case kMediaSessionActionSeekforward: + return kCobaltExtensionMediaSessionActionSeekforward; + case kMediaSessionActionSeekto: + return kCobaltExtensionMediaSessionActionSeekto; + case kMediaSessionActionStop: + return kCobaltExtensionMediaSessionActionStop; + case kMediaSessionActionPlay: + default: + return kCobaltExtensionMediaSessionActionPlay; + } +} + +MediaSessionAction MediaSessionClient::ConvertMediaSessionAction( + CobaltExtensionMediaSessionAction action) { + switch (action) { + case kCobaltExtensionMediaSessionActionPause: + return kMediaSessionActionPause; + case kCobaltExtensionMediaSessionActionSeekbackward: + return kMediaSessionActionSeekbackward; + case kCobaltExtensionMediaSessionActionPrevioustrack: + return kMediaSessionActionPrevioustrack; + case kCobaltExtensionMediaSessionActionNexttrack: + return kMediaSessionActionNexttrack; + case kCobaltExtensionMediaSessionActionSeekforward: + return kMediaSessionActionSeekforward; + case kCobaltExtensionMediaSessionActionSeekto: + return kMediaSessionActionSeekto; + case kCobaltExtensionMediaSessionActionStop: + return kMediaSessionActionStop; + case kCobaltExtensionMediaSessionActionPlay: + default: + return kMediaSessionActionPlay; + } +} } // namespace media_session } // namespace cobalt
diff --git a/src/cobalt/media_session/media_session_client.h b/src/cobalt/media_session/media_session_client.h index 9b5d6fa..d2d5221 100644 --- a/src/cobalt/media_session/media_session_client.h +++ b/src/cobalt/media_session/media_session_client.h
@@ -58,28 +58,66 @@ // the "guessed playback state" // https://wicg.github.io/mediasession/#guessed-playback-state // Can be invoked from any thread. - void UpdatePlatformPlaybackState(MediaSessionPlaybackState state); + void UpdatePlatformCobaltExtensionPlaybackState( + CobaltExtensionMediaSessionPlaybackState state); + + // Deprecated - use the alternative + // UpdatePlatformCobaltExtensionPlaybackState. + // TODO: Delete once platform migrations to CobaltExtensionMediaSessionApi are + // complete. + void UpdatePlatformPlaybackState(MediaSessionPlaybackState state) { + UpdatePlatformCobaltExtensionPlaybackState(ConvertPlaybackState(state)); + } // Invokes a given media session action // https://wicg.github.io/mediasession/#actions-model // Can be invoked from any thread. - void InvokeAction(MediaSessionAction action) { - std::unique_ptr<MediaSessionActionDetails> details( - new MediaSessionActionDetails()); - details->set_action(action); - InvokeActionInternal(std::move(details)); + void InvokeAction(CobaltExtensionMediaSessionAction action) { + CobaltExtensionMediaSessionActionDetails details = {}; + CobaltExtensionMediaSessionActionDetailsInit(&details, action); + InvokeActionInternal(std::move(&details)); } // Invokes a given media session action that takes additional details. - void InvokeAction(std::unique_ptr<MediaSessionActionDetails> details) { - InvokeActionInternal(std::move(details)); + void InvokeCobaltExtensionAction( + CobaltExtensionMediaSessionActionDetails details) { + InvokeActionInternal(&details); } + // Deprecated - use the alternative InvokeCobaltExtensionAction. + // TODO: Delete once platform migrations to CobaltExtensionMediaSessionApi are + // complete. + void InvokeAction(std::unique_ptr<MediaSessionActionDetails> details) { + CobaltExtensionMediaSessionActionDetails* ext_details = {}; + CobaltExtensionMediaSessionActionDetailsInit( + ext_details, ConvertMediaSessionAction(details->action())); + if (details->has_seek_offset()) { + ext_details->seek_offset = details->seek_offset().value(); + } + if (details->has_seek_time()) { + ext_details->seek_time = details->seek_time().value(); + } + if (details->has_fast_seek()) { + ext_details->fast_seek = details->fast_seek().value(); + } + InvokeActionInternal(std::move(ext_details)); + } // Invoked on the browser thread when any metadata, position state, playback // state, or supported session actions change. virtual void OnMediaSessionStateChanged( const MediaSessionState& session_state); + // Indicate the media session client is active or not depending on the + // media session playback state. + bool is_active() { + return platform_playback_state_ != kMediaSessionPlaybackStateNone; + } + + // Set maybe freeze callback. + void SetMaybeFreezeCallback(const base::Closure& maybe_freeze_callback) { + maybe_freeze_callback_ = maybe_freeze_callback; + } + private: THREAD_CHECKER(thread_checker_); scoped_refptr<MediaSession> media_session_; @@ -91,13 +129,31 @@ void UpdateMediaSessionState(); MediaSessionPlaybackState ComputeActualPlaybackState() const; MediaSessionState::AvailableActionsSet ComputeAvailableActions() const; - CobaltExtensionPlaybackState ConvertPlaybackState( - MediaSessionPlaybackState in_state); + void InvokeActionInternal(CobaltExtensionMediaSessionActionDetails* details); + void ConvertMediaSessionActions( const MediaSessionState::AvailableActionsSet& actions, bool result[kCobaltExtensionMediaSessionActionNumActions]); + std::unique_ptr<MediaSessionActionDetails> ConvertActionDetails( + CobaltExtensionMediaSessionActionDetails* ext_details); - void InvokeActionInternal(std::unique_ptr<MediaSessionActionDetails> details); + // Static callback wrappers for MediaSessionAPI extension. + static void UpdatePlatformPlaybackStateCallback( + CobaltExtensionMediaSessionPlaybackState state, void* callback_context); + static void InvokeActionCallback( + CobaltExtensionMediaSessionActionDetails details, void* callback_context); + + // MediaSessionAPI extension type conversion helpers. + CobaltExtensionMediaSessionPlaybackState ConvertPlaybackState( + MediaSessionPlaybackState state); + MediaSessionPlaybackState ConvertPlaybackState( + CobaltExtensionMediaSessionPlaybackState state); + CobaltExtensionMediaSessionAction ConvertMediaSessionAction( + MediaSessionAction action); + MediaSessionAction ConvertMediaSessionAction( + CobaltExtensionMediaSessionAction action); + + base::Closure maybe_freeze_callback_; DISALLOW_COPY_AND_ASSIGN(MediaSessionClient); };
diff --git a/src/cobalt/media_session/media_session_test.cc b/src/cobalt/media_session/media_session_test.cc index 687167a..8b2f22e 100644 --- a/src/cobalt/media_session/media_session_test.cc +++ b/src/cobalt/media_session/media_session_test.cc
@@ -20,6 +20,7 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "cobalt/bindings/testing/script_object_owner.h" +#include "cobalt/extension/media_session.h" #include "cobalt/media_session/media_session_client.h" #include "cobalt/script/callback_function.h" #include "cobalt/script/script_value.h" @@ -68,6 +69,7 @@ override { session_state_ = session_state; ++session_change_count_; + MediaSessionClient::OnMediaSessionStateChanged(session_state); } void WaitForSessionStateChange() { size_t current_change_count = session_change_count_; @@ -193,12 +195,12 @@ session->SetActionHandler(kMediaSessionActionPlay, holder); client.WaitForSessionStateChange(); EXPECT_EQ(1, client.GetMediaSessionState().available_actions().to_ulong()); - client.InvokeAction(kMediaSessionActionPlay); + client.InvokeAction(kCobaltExtensionMediaSessionActionPlay); session->SetActionHandler(kMediaSessionActionPlay, null_holder); client.WaitForSessionStateChange(); EXPECT_EQ(0, client.GetMediaSessionState().available_actions().to_ulong()); - client.InvokeAction(kMediaSessionActionPlay); + client.InvokeAction(kCobaltExtensionMediaSessionActionPlay); EXPECT_GE(client.GetMediaSessionChangeCount(), 3); } @@ -315,7 +317,7 @@ MockCallbackFunction cf; FakeScriptValue<MediaSession::MediaSessionActionHandler> holder(&cf); - std::unique_ptr<MediaSessionActionDetails> details; + CobaltExtensionMediaSessionActionDetails details; session->SetActionHandler(kMediaSessionActionSeekto, holder); session->SetActionHandler(kMediaSessionActionSeekforward, holder); @@ -323,31 +325,31 @@ EXPECT_CALL(cf, Run(SeekNoOffset(kMediaSessionActionSeekforward))) .WillOnce(Return(CallbackResult<void>())); - client.InvokeAction(kMediaSessionActionSeekforward); + client.InvokeAction(kCobaltExtensionMediaSessionActionSeekforward); EXPECT_CALL(cf, Run(SeekNoOffset(kMediaSessionActionSeekbackward))) .WillOnce(Return(CallbackResult<void>())); - client.InvokeAction(kMediaSessionActionSeekbackward); + client.InvokeAction(kCobaltExtensionMediaSessionActionSeekbackward); EXPECT_CALL(cf, Run(SeekTime(1.2))).WillOnce(Return(CallbackResult<void>())); - details.reset(new MediaSessionActionDetails()); - details->set_action(kMediaSessionActionSeekto); - details->set_seek_time(1.2); - client.InvokeAction(std::move(details)); + CobaltExtensionMediaSessionActionDetailsInit( + &details, kCobaltExtensionMediaSessionActionSeekto); + details.seek_time = 1.2; + client.InvokeCobaltExtensionAction(details); EXPECT_CALL(cf, Run(SeekOffset(kMediaSessionActionSeekforward, 3.4))) .WillOnce(Return(CallbackResult<void>())); - details.reset(new MediaSessionActionDetails()); - details->set_action(kMediaSessionActionSeekforward); - details->set_seek_offset(3.4); - client.InvokeAction(std::move(details)); + CobaltExtensionMediaSessionActionDetailsInit( + &details, kCobaltExtensionMediaSessionActionSeekforward); + details.seek_offset = 3.4; + client.InvokeCobaltExtensionAction(details); EXPECT_CALL(cf, Run(SeekOffset(kMediaSessionActionSeekbackward, 5.6))) .WillOnce(Return(CallbackResult<void>())); - details.reset(new MediaSessionActionDetails()); - details->set_action(kMediaSessionActionSeekbackward); - details->set_seek_offset(5.6); - client.InvokeAction(std::move(details)); + CobaltExtensionMediaSessionActionDetailsInit( + &details, kCobaltExtensionMediaSessionActionSeekbackward); + details.seek_offset = 5.6; + client.InvokeCobaltExtensionAction(details); client.WaitForSessionStateChange(); EXPECT_GE(client.GetMediaSessionChangeCount(), 0);
diff --git a/src/cobalt/media_stream/media_stream_audio_deliverer.h b/src/cobalt/media_stream/media_stream_audio_deliverer.h index 40628d4..b942bdd 100644 --- a/src/cobalt/media_stream/media_stream_audio_deliverer.h +++ b/src/cobalt/media_stream/media_stream_audio_deliverer.h
@@ -26,9 +26,10 @@ #include "base/threading/thread_checker.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" + +#include "cobalt/media/base/audio_bus.h" #include "cobalt/media_stream/audio_parameters.h" -#include "cobalt/media/base/shell_audio_bus.h" namespace cobalt { namespace media_stream { @@ -119,7 +120,7 @@ // Deliver data to all consumers. This method may be called on any thread. - void OnData(const media::ShellAudioBus& audio_bus, + void OnData(const media::AudioBus& audio_bus, base::TimeTicks reference_time) { TRACE_EVENT1("media_stream", "MediaStreamAudioDeliverer::OnData", "reference time (ms)",
diff --git a/src/cobalt/media_stream/media_stream_audio_sink.h b/src/cobalt/media_stream/media_stream_audio_sink.h index 680bbd3..034dbec 100644 --- a/src/cobalt/media_stream/media_stream_audio_sink.h +++ b/src/cobalt/media_stream/media_stream_audio_sink.h
@@ -15,12 +15,13 @@ #ifndef COBALT_MEDIA_STREAM_MEDIA_STREAM_AUDIO_SINK_H_ #define COBALT_MEDIA_STREAM_MEDIA_STREAM_AUDIO_SINK_H_ +#include "cobalt/media/base/audio_bus.h" + #include "cobalt/media_stream/audio_parameters.h" #include "cobalt/media_stream/media_stream_source.h" #include "cobalt/media_stream/media_stream_track.h" -#include "cobalt/media/base/shell_audio_bus.h" namespace cobalt { namespace media_stream { @@ -29,11 +30,11 @@ // Note: users of this class will call OnSetFormat is before OnData. class MediaStreamAudioSink { public: - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; MediaStreamAudioSink() = default; // These are called on the same thread. - virtual void OnData(const ShellAudioBus& audio_bus, + virtual void OnData(const AudioBus& audio_bus, base::TimeTicks reference_time) = 0; virtual void OnSetFormat(const media_stream::AudioParameters& params) = 0; virtual void OnReadyStateChanged(
diff --git a/src/cobalt/media_stream/media_stream_audio_source.cc b/src/cobalt/media_stream/media_stream_audio_source.cc index 6c20d49..2d15393 100644 --- a/src/cobalt/media_stream/media_stream_audio_source.cc +++ b/src/cobalt/media_stream/media_stream_audio_source.cc
@@ -60,7 +60,7 @@ } void MediaStreamAudioSource::DeliverDataToTracks( - const MediaStreamAudioTrack::ShellAudioBus& audio_bus, + const MediaStreamAudioTrack::AudioBus& audio_bus, base::TimeTicks reference_time) { deliverer_.OnData(audio_bus, reference_time); }
diff --git a/src/cobalt/media_stream/media_stream_audio_source.h b/src/cobalt/media_stream/media_stream_audio_source.h index 77c00d7..69d789c 100644 --- a/src/cobalt/media_stream/media_stream_audio_source.h +++ b/src/cobalt/media_stream/media_stream_audio_source.h
@@ -58,9 +58,8 @@ // Subclasses should call these methods. |DeliverDataToTracks| can be // called from a different thread than where MediaStreamAudioSource // was created. - void DeliverDataToTracks( - const MediaStreamAudioTrack::ShellAudioBus& audio_bus, - base::TimeTicks reference_time); + void DeliverDataToTracks(const MediaStreamAudioTrack::AudioBus& audio_bus, + base::TimeTicks reference_time); void SetFormat(const media_stream::AudioParameters& params) { DLOG(INFO) << "MediaStreamAudioSource@" << this << "::SetFormat("
diff --git a/src/cobalt/media_stream/media_stream_audio_source_test.cc b/src/cobalt/media_stream/media_stream_audio_source_test.cc index f526bba..4157d3d 100644 --- a/src/cobalt/media_stream/media_stream_audio_source_test.cc +++ b/src/cobalt/media_stream/media_stream_audio_source_test.cc
@@ -17,7 +17,7 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "cobalt/dom/testing/stub_environment_settings.h" -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #include "cobalt/media_stream/media_stream_audio_track.h" #include "cobalt/media_stream/testing/mock_media_stream_audio_source.h" #include "testing/gtest/include/gtest/gtest.h" @@ -35,7 +35,7 @@ namespace cobalt { namespace media_stream { -typedef media::ShellAudioBus ShellAudioBus; +typedef media::AudioBus AudioBus; class MediaStreamAudioSourceTest : public testing::Test { public:
diff --git a/src/cobalt/media_stream/media_stream_audio_track.cc b/src/cobalt/media_stream/media_stream_audio_track.cc index c6deb82..0823274 100644 --- a/src/cobalt/media_stream/media_stream_audio_track.cc +++ b/src/cobalt/media_stream/media_stream_audio_track.cc
@@ -69,7 +69,7 @@ stop_callback_ = stop_callback; } -void MediaStreamAudioTrack::OnData(const ShellAudioBus& audio_bus, +void MediaStreamAudioTrack::OnData(const AudioBus& audio_bus, base::TimeTicks reference_time) { deliverer_.OnData(audio_bus, reference_time); }
diff --git a/src/cobalt/media_stream/media_stream_audio_track.h b/src/cobalt/media_stream/media_stream_audio_track.h index b7d7708..f1b9b7d 100644 --- a/src/cobalt/media_stream/media_stream_audio_track.h +++ b/src/cobalt/media_stream/media_stream_audio_track.h
@@ -19,7 +19,7 @@ #include "base/strings/string_piece.h" #include "base/threading/thread_checker.h" #include "cobalt/dom/event_target.h" -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #include "cobalt/media_stream/audio_parameters.h" #include "cobalt/media_stream/media_stream_audio_deliverer.h" #include "cobalt/media_stream/media_stream_audio_sink.h" @@ -50,7 +50,7 @@ settings.set_sample_size(parameters.bits_per_sample()); return settings; } - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; explicit MediaStreamAudioTrack(script::EnvironmentSettings* settings) : MediaStreamTrack(settings) {} @@ -81,7 +81,7 @@ void Start(const base::Closure& stop_callback); // Called by MediaStreamAudioDeliverer. - void OnData(const ShellAudioBus& audio_bus, base::TimeTicks reference_time); + void OnData(const AudioBus& audio_bus, base::TimeTicks reference_time); void OnSetFormat(const media_stream::AudioParameters& params); THREAD_CHECKER(thread_checker_);
diff --git a/src/cobalt/media_stream/media_stream_audio_track_test.cc b/src/cobalt/media_stream/media_stream_audio_track_test.cc index 8fc542a..5512ae2 100644 --- a/src/cobalt/media_stream/media_stream_audio_track_test.cc +++ b/src/cobalt/media_stream/media_stream_audio_track_test.cc
@@ -16,7 +16,7 @@ #include "base/bind_helpers.h" #include "cobalt/dom/testing/stub_environment_settings.h" -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #include "cobalt/media_stream/media_stream_audio_deliverer.h" #include "cobalt/media_stream/testing/mock_media_stream_audio_sink.h" #include "testing/gtest/include/gtest/gtest.h" @@ -36,7 +36,7 @@ namespace cobalt { namespace media_stream { -typedef media::ShellAudioBus ShellAudioBus; +typedef media::AudioBus AudioBus; // This fixture is created, so it can be added as a friend to // |MediaStreamAudioTrack|. This enables calling a private method @@ -71,8 +71,8 @@ deliverer.OnSetFormat(expected_params); - ShellAudioBus audio_bus(kChannelCount, kFrameCount, ShellAudioBus::kInt16, - ShellAudioBus::kInterleaved); + AudioBus audio_bus(kChannelCount, kFrameCount, AudioBus::kInt16, + AudioBus::kInterleaved); deliverer.OnData(audio_bus, expected_time); } @@ -104,8 +104,8 @@ deliverer.OnSetFormat(expected_params); - ShellAudioBus audio_bus(kChannelCount, kFrameCount, ShellAudioBus::kInt16, - ShellAudioBus::kInterleaved); + AudioBus audio_bus(kChannelCount, kFrameCount, AudioBus::kInt16, + AudioBus::kInterleaved); deliverer.OnData(audio_bus, expected_time); } @@ -141,8 +141,8 @@ deliverer.OnSetFormat(expected_params); - ShellAudioBus audio_bus(kChannelCount, kFrameCount, ShellAudioBus::kInt16, - ShellAudioBus::kInterleaved); + AudioBus audio_bus(kChannelCount, kFrameCount, AudioBus::kInt16, + AudioBus::kInterleaved); deliverer.OnData(audio_bus, expected_time); } @@ -166,8 +166,8 @@ deliverer.OnSetFormat(expected_params); - ShellAudioBus audio_bus(kChannelCount, kFrameCount, ShellAudioBus::kInt16, - ShellAudioBus::kInterleaved); + AudioBus audio_bus(kChannelCount, kFrameCount, AudioBus::kInt16, + AudioBus::kInterleaved); track->RemoveSink(&mock_sink); deliverer.OnData(audio_bus, expected_time);
diff --git a/src/cobalt/media_stream/microphone_audio_source.cc b/src/cobalt/media_stream/microphone_audio_source.cc index 778223e..74eff37 100644 --- a/src/cobalt/media_stream/microphone_audio_source.cc +++ b/src/cobalt/media_stream/microphone_audio_source.cc
@@ -100,7 +100,7 @@ base::Unretained(this), options))) {} void MicrophoneAudioSource::OnDataReceived( - std::unique_ptr<MediaStreamAudioTrack::ShellAudioBus> audio_bus) { + std::unique_ptr<MediaStreamAudioTrack::AudioBus> audio_bus) { base::TimeTicks now = base::TimeTicks::Now(); DeliverDataToTracks(*audio_bus, now); }
diff --git a/src/cobalt/media_stream/microphone_audio_source.h b/src/cobalt/media_stream/microphone_audio_source.h index d3049d7..c930298 100644 --- a/src/cobalt/media_stream/microphone_audio_source.h +++ b/src/cobalt/media_stream/microphone_audio_source.h
@@ -70,7 +70,7 @@ int buffer_size_bytes); void OnDataReceived( - std::unique_ptr<MediaStreamAudioTrack::ShellAudioBus> audio_bus); + std::unique_ptr<MediaStreamAudioTrack::AudioBus> audio_bus); void OnDataCompletion(); void OnMicrophoneOpen();
diff --git a/src/cobalt/media_stream/testing/mock_media_stream_audio_sink.h b/src/cobalt/media_stream/testing/mock_media_stream_audio_sink.h index bd11714..7fa06b6 100644 --- a/src/cobalt/media_stream/testing/mock_media_stream_audio_sink.h +++ b/src/cobalt/media_stream/testing/mock_media_stream_audio_sink.h
@@ -24,8 +24,8 @@ class MockMediaStreamAudioSink : public MediaStreamAudioSink { public: - MOCK_METHOD2(OnData, void(const ShellAudioBus& audio_bus, - base::TimeTicks reference_time)); + MOCK_METHOD2(OnData, + void(const AudioBus& audio_bus, base::TimeTicks reference_time)); MOCK_METHOD1(OnSetFormat, void(const media_stream::AudioParameters& params)); MOCK_METHOD1(OnReadyStateChanged, void(media_stream::MediaStreamTrack::ReadyState new_state));
diff --git a/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.cc b/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.cc index 09ce038..9ba721f 100644 --- a/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.cc +++ b/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.cc
@@ -96,6 +96,16 @@ SelectAtlasCache(&offscreen_atlases_, &offscreen_cache_); SelectAtlasCache(&offscreen_atlases_1d_, &offscreen_cache_1d_); + // Delete skottie targets that were not used in the previous render frame. + for (size_t index = 0; index < skottie_targets_.size();) { + if (skottie_targets_[index]->allocations_used == 0) { + skottie_targets_.erase(skottie_targets_.begin() + index); + } else { + skottie_targets_[index]->allocations_used = 0; + ++index; + } + } + // Delete uncached targets that were not used in the previous render frame. for (size_t index = 0; index < uncached_targets_.size();) { if (uncached_targets_[index]->allocations_used == 0) { @@ -215,6 +225,33 @@ return false; } +bool OffscreenTargetManager::GetCachedTarget( + const skia::SkottieAnimation* skottie_animation, const math::SizeF& size, + TargetInfo* out_target_info) { + // Each SkottieAnimation uses its own render target cache. The cache is keyed + // off the SkottieAnimation's size and pointer value. Using the pointer can + // be risky as an object may be destroyed and a new one created with the same + // pointer value. However, since each SkottieAnimation is created assuming + // the render cache is dirty, it is safe to accidentally use the render cache + // of an old SkottieAnimation with a new one. + int64_t id = reinterpret_cast<int64_t>(skottie_animation); + math::RectF target_size(std::ceil(size.width()), std::ceil(size.height())); + for (size_t i = 0; i < skottie_targets_.size(); ++i) { + OffscreenAtlas* target = skottie_targets_[i].get(); + auto iter = target->allocation_map.find(id); + if (iter != target->allocation_map.end() && + iter->second.error_data == target_size) { + target->allocations_used += 1; + out_target_info->framebuffer = target->framebuffer.get(); + out_target_info->skia_canvas = target->skia_surface->getCanvas(); + out_target_info->region = iter->second.target_region; + return true; + } + } + + return false; +} + void OffscreenTargetManager::AllocateCachedTarget(const render_tree::Node* node, const math::SizeF& size, const ErrorData& error_data, @@ -325,6 +362,34 @@ } } +void OffscreenTargetManager::AllocateCachedTarget( + const skia::SkottieAnimation* skottie_animation, const math::SizeF& size, + TargetInfo* out_target_info) { + // Each SkottieAnimation has its own offscreen atlas. + math::Size target_size(static_cast<int>(std::ceil(size.width())), + static_cast<int>(std::ceil(size.height()))); + OffscreenAtlas* atlas = CreateOffscreenAtlas(target_size, true).release(); + if (!atlas) { + // If there was an error allocating the offscreen atlas, indicate by + // marking framebuffer and skia canvas as null and returning early. + out_target_info->framebuffer = nullptr; + out_target_info->skia_canvas = nullptr; + return; + } + + int64_t id = reinterpret_cast<int64_t>(skottie_animation); + // |target_rect| must be calculated the same way as in GetCachedTarget(). + math::RectF target_rect(std::ceil(size.width()), std::ceil(size.height())); + atlas->allocation_map.insert(AllocationMap::value_type( + id, AllocationMapValue(target_rect, target_rect))); + skottie_targets_.emplace_back(atlas); + + atlas->allocations_used = 1; + out_target_info->framebuffer = atlas->framebuffer.get(); + out_target_info->skia_canvas = atlas->skia_surface->getCanvas(); + out_target_info->region = target_rect; +} + void OffscreenTargetManager::AllocateUncachedTarget( const math::SizeF& size, TargetInfo* out_target_info) { // Align up the requested target size to increase the chances that it can
diff --git a/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.h b/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.h index ec64a19..69e4bde 100644 --- a/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.h +++ b/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.h
@@ -23,6 +23,7 @@ #include "cobalt/render_tree/node.h" #include "cobalt/renderer/backend/egl/framebuffer_render_target.h" #include "cobalt/renderer/backend/egl/graphics_context.h" +#include "cobalt/renderer/rasterizer/skia/skottie_animation.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkSurface.h" @@ -85,6 +86,9 @@ bool GetCachedTarget(const render_tree::Node* node, const CacheErrorFunction1D& error_function, TargetInfo* out_target_info); + bool GetCachedTarget(const skia::SkottieAnimation* skottie_animation, + const math::SizeF& size, + TargetInfo* out_target_info); // Allocate a cached offscreen target of the specified size. // The returned values are only valid until the next call to Update(). @@ -95,6 +99,9 @@ void AllocateCachedTarget(const render_tree::Node* node, float size, const ErrorData1D& error_data, TargetInfo* out_target_info); + void AllocateCachedTarget(const skia::SkottieAnimation* skottie_animation, + const math::SizeF& size, + TargetInfo* out_target_info); // Allocate an uncached render target. The contents of the target cannot be // reused in subsequent frames. If there was an error allocating the @@ -122,6 +129,7 @@ std::unique_ptr<OffscreenAtlas> offscreen_cache_1d_; std::vector<std::unique_ptr<OffscreenAtlas>> uncached_targets_; + std::vector<std::unique_ptr<OffscreenAtlas>> skottie_targets_; // Align offscreen targets to a particular size to more efficiently use the // offscreen target atlas. Use a power of 2 for the alignment so that a bit
diff --git a/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc index 263afa5..ec33f8f 100644 --- a/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc +++ b/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc
@@ -44,6 +44,7 @@ #include "cobalt/renderer/rasterizer/egl/draw_rrect_color_texture.h" #include "cobalt/renderer/rasterizer/skia/hardware_image.h" #include "cobalt/renderer/rasterizer/skia/image.h" +#include "cobalt/renderer/rasterizer/skia/skottie_animation.h" namespace cobalt { namespace renderer { @@ -111,6 +112,17 @@ 0, 1); } +math::SizeF GetTransformScale(const math::Matrix3F& transform) { + math::PointF mapped_origin = transform * math::PointF(0, 0); + math::PointF mapped_x = transform * math::PointF(1, 0); + math::PointF mapped_y = transform * math::PointF(0, 1); + math::Vector2dF mapped_vecx(mapped_x.x() - mapped_origin.x(), + mapped_x.y() - mapped_origin.y()); + math::Vector2dF mapped_vecy(mapped_y.x() - mapped_origin.x(), + mapped_y.y() - mapped_origin.y()); + return math::SizeF(mapped_vecx.Length(), mapped_vecy.Length()); +} + bool ImageNodeSupportedNatively(render_tree::ImageNode* image_node) { // The image node may contain nothing. For example, when it represents a video // element before any frame is decoded. @@ -407,17 +419,9 @@ } draw_state_.opacity = 1.0f; - math::PointF mapped_origin = draw_state_.transform * math::PointF(0, 0); - math::PointF mapped_x = draw_state_.transform * math::PointF(1, 0); - math::PointF mapped_y = draw_state_.transform * math::PointF(0, 1); - math::Vector2dF mapped_vecx(mapped_x.x() - mapped_origin.x(), - mapped_x.y() - mapped_origin.y()); - math::Vector2dF mapped_vecy(mapped_y.x() - mapped_origin.x(), - mapped_y.y() - mapped_origin.y()); - float scale_x = mapped_vecx.Length(); - float scale_y = mapped_vecy.Length(); - draw_state_.transform = math::ScaleMatrix(std::max(1.0f, scale_x), - std::max(1.0f, scale_y)); + math::SizeF scale = GetTransformScale(draw_state_.transform); + draw_state_.transform = math::ScaleMatrix( + std::max(1.0f, scale.width()), std::max(1.0f, scale.height())); // Don't clip the source since it is in its own local space. bool limit_to_screen_size = false; @@ -672,12 +676,63 @@ } void RenderTreeNodeVisitor::Visit(render_tree::LottieNode* lottie_node) { - if (!IsVisible(lottie_node->GetBounds())) { + const render_tree::LottieNode::Builder& data = lottie_node->data(); + math::RectF content_rect = data.destination_rect; + if (!IsVisible(content_rect)) { return; } - // Use Skottie to render Lottie animations. - FallbackRasterize(lottie_node); + skia::SkottieAnimation* animation = + base::polymorphic_downcast<skia::SkottieAnimation*>(data.animation.get()); + if (animation->GetSize().GetArea() == 0) { + return; + } + animation->SetAnimationTime(data.animation_time); + + // Get an offscreen target to cache the animation. Make the target big enough + // to avoid scaling artifacts. + math::SizeF scale = GetTransformScale(draw_state_.transform); + math::SizeF mapped_size = content_rect.size(); + // Use a uniform scale to avoid impacting aspect ratio calculations. + mapped_size.Scale(std::max(scale.width(), scale.height())); + + OffscreenTargetManager::TargetInfo target_info; + if (!offscreen_target_manager_->GetCachedTarget( + animation, mapped_size, &target_info)) { + // No pre-existing target was found. Allocate a new target. + animation->ResetRenderCache(); + offscreen_target_manager_->AllocateCachedTarget( + animation, mapped_size, &target_info); + } + if (target_info.framebuffer == nullptr) { + // Unable to allocate the render target for the animation cache. + return; + } + + // Add a draw call to update the cache. + std::unique_ptr<DrawObject> update_cache(new DrawCallback( + base::Bind(&skia::SkottieAnimation::UpdateRenderCache, + base::Unretained(animation), + base::Unretained(target_info.skia_canvas), + target_info.region.size()))); + draw_object_manager_->AddBatchedExternalDraw( + std::move(update_cache), lottie_node->GetTypeId(), + target_info.framebuffer, target_info.region); + + // Add a draw call to render the cached animation to the current target. + backend::TextureEGL* texture = target_info.framebuffer->GetColorTexture(); + math::Matrix3F texcoord_transform = GetTexcoordTransform(target_info); + if (IsOpaque(draw_state_.opacity)) { + std::unique_ptr<DrawObject> draw( + new DrawRectTexture(graphics_state_, draw_state_, content_rect, texture, + texcoord_transform)); + AddDraw(std::move(draw), content_rect, DrawObjectManager::kBlendSrcAlpha); + } else { + std::unique_ptr<DrawObject> draw(new DrawRectColorTexture( + graphics_state_, draw_state_, content_rect, kOpaqueWhite, texture, + texcoord_transform, false /* clamp_texcoords */)); + AddDraw(std::move(draw), content_rect, DrawObjectManager::kBlendSrcAlpha); + } } void RenderTreeNodeVisitor::Visit(
diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc index 464ef3d..a751832 100644 --- a/src/cobalt/renderer/rasterizer/pixel_test.cc +++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -4538,6 +4538,61 @@ TestTree(lottie_node); } +TEST_F(PixelTest, LottiePreserveAspectRatioTooShortAnimationTest) { + std::vector<uint8> animation_data = + GetFileData(GetTestFilePath("white_material_wave_loading.json")); + scoped_refptr<LottieAnimation> animation = + GetResourceProvider()->CreateLottieAnimation( + reinterpret_cast<char*>(&animation_data[0]), animation_data.size()); + LottieAnimation::LottieProperties lottie_properties; + lottie_properties.UpdateState(LottieAnimation::LottieState::kPlaying); + animation->BeginRenderFrame(lottie_properties); + + LottieNode::Builder node_builder = + LottieNode::Builder(animation, RectF(output_surface_size().width(), + 100.0f)); + node_builder.animation_time = base::TimeDelta::FromSecondsD(0); + scoped_refptr<LottieNode> lottie_node = new LottieNode(node_builder); + TestTree(lottie_node); +} + +TEST_F(PixelTest, LottiePreserveAspectRatioTooNarrowAnimationTest) { + std::vector<uint8> animation_data = + GetFileData(GetTestFilePath("white_material_wave_loading.json")); + scoped_refptr<LottieAnimation> animation = + GetResourceProvider()->CreateLottieAnimation( + reinterpret_cast<char*>(&animation_data[0]), animation_data.size()); + LottieAnimation::LottieProperties lottie_properties; + lottie_properties.UpdateState(LottieAnimation::LottieState::kPlaying); + animation->BeginRenderFrame(lottie_properties); + + LottieNode::Builder node_builder = + LottieNode::Builder(animation, RectF(100.0f, + output_surface_size().height())); + node_builder.animation_time = base::TimeDelta::FromSecondsD(0); + scoped_refptr<LottieNode> lottie_node = new LottieNode(node_builder); + TestTree(lottie_node); +} + +TEST_F(PixelTest, LottieScaledWideAnimationTest) { + std::vector<uint8> animation_data = + GetFileData(GetTestFilePath("white_material_wave_loading.json")); + scoped_refptr<LottieAnimation> animation = + GetResourceProvider()->CreateLottieAnimation( + reinterpret_cast<char*>(&animation_data[0]), animation_data.size()); + LottieAnimation::LottieProperties lottie_properties; + lottie_properties.UpdateState(LottieAnimation::LottieState::kPlaying); + animation->BeginRenderFrame(lottie_properties); + + LottieNode::Builder node_builder = + LottieNode::Builder(animation, RectF(output_surface_size())); + node_builder.animation_time = base::TimeDelta::FromSecondsD(0); + scoped_refptr<LottieNode> lottie_node = new LottieNode(node_builder); + TestTree(new MatrixTransformNode(lottie_node, + ScaleMatrix(4.0f, 1.0f) * + TranslateMatrix(output_surface_size().width() * -0.5f, 0.0f))); +} + #endif // !SB_HAS(BLITTER) } // namespace rasterizer
diff --git a/src/cobalt/renderer/rasterizer/skia/skottie_animation.cc b/src/cobalt/renderer/rasterizer/skia/skottie_animation.cc index 4fae87f..224b4a9 100644 --- a/src/cobalt/renderer/rasterizer/skia/skottie_animation.cc +++ b/src/cobalt/renderer/rasterizer/skia/skottie_animation.cc
@@ -15,6 +15,7 @@ #include "cobalt/renderer/rasterizer/skia/skottie_animation.h" #include "base/bind.h" +#include "third_party/skia/include/core/SkRect.h" namespace cobalt { namespace renderer { @@ -23,6 +24,7 @@ SkottieAnimation::SkottieAnimation(const char* data, size_t length) : last_updated_animation_time_(base::TimeDelta()) { + ResetRenderCache(); skottie::Animation::Builder builder; skottie_animation_ = builder.make(data, length); animation_size_ = math::Size(skottie_animation_->size().width(), @@ -72,6 +74,11 @@ return; } + // Do not update the animation time if it has already reached the last frame. + if (is_complete_) { + return; + } + base::TimeDelta current_animation_time = last_updated_animation_time_; base::TimeDelta time_elapsed = animate_function_time - last_updated_animate_function_time_; @@ -124,6 +131,21 @@ animate_function_time); } +void SkottieAnimation::UpdateRenderCache(SkCanvas* render_target, + const math::SizeF& size) { + DCHECK(render_target); + if (cached_animation_time_ == last_updated_animation_time_) { + // The render cache is already up-to-date. + return; + } + + cached_animation_time_ = last_updated_animation_time_; + SkRect bounding_rect = SkRect::MakeWH(size.width(), size.height()); + render_target->clear(SK_ColorTRANSPARENT); + skottie_animation_->render(render_target, &bounding_rect); + render_target->flush(); +} + void SkottieAnimation::UpdateAnimationFrameAndAnimateFunctionTimes( base::TimeDelta current_animation_time, base::TimeDelta current_animate_function_time) {
diff --git a/src/cobalt/renderer/rasterizer/skia/skottie_animation.h b/src/cobalt/renderer/rasterizer/skia/skottie_animation.h index 3d5531c..0acb854 100644 --- a/src/cobalt/renderer/rasterizer/skia/skottie_animation.h +++ b/src/cobalt/renderer/rasterizer/skia/skottie_animation.h
@@ -15,7 +15,9 @@ #ifndef COBALT_RENDERER_RASTERIZER_SKIA_SKOTTIE_ANIMATION_H_ #define COBALT_RENDERER_RASTERIZER_SKIA_SKOTTIE_ANIMATION_H_ +#include "cobalt/math/size_f.h" #include "cobalt/render_tree/lottie_animation.h" +#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/modules/skottie/include/Skottie.h" namespace cobalt { @@ -41,6 +43,12 @@ sk_sp<skottie::Animation> GetSkottieAnimation() { return skottie_animation_; } + // Rendering the lottie animation can be CPU-intensive. To minimize the cost, + // the animation can be updated in an offscreen render target only as needed, + // then the offscreen target rendered to the screen. + void ResetRenderCache() { cached_animation_time_ = base::TimeDelta::Min(); } + void UpdateRenderCache(SkCanvas* render_target, const math::SizeF& size); + private: void UpdateAnimationFrameAndAnimateFunctionTimes( base::TimeDelta current_animation_time, @@ -79,6 +87,9 @@ // The most recently updated frame time for |skottie_animation_|. base::TimeDelta last_updated_animation_time_; + + // This is the animation time used for the last cache update. + base::TimeDelta cached_animation_time_; }; } // namespace skia
diff --git a/src/cobalt/renderer/rasterizer/testdata/LottiePreserveAspectRatioTooNarrowAnimationTest-expected.png b/src/cobalt/renderer/rasterizer/testdata/LottiePreserveAspectRatioTooNarrowAnimationTest-expected.png new file mode 100644 index 0000000..803f356 --- /dev/null +++ b/src/cobalt/renderer/rasterizer/testdata/LottiePreserveAspectRatioTooNarrowAnimationTest-expected.png Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/LottiePreserveAspectRatioTooShortAnimationTest-expected.png b/src/cobalt/renderer/rasterizer/testdata/LottiePreserveAspectRatioTooShortAnimationTest-expected.png new file mode 100644 index 0000000..804797d --- /dev/null +++ b/src/cobalt/renderer/rasterizer/testdata/LottiePreserveAspectRatioTooShortAnimationTest-expected.png Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/LottieScaledWideAnimationTest-expected.png b/src/cobalt/renderer/rasterizer/testdata/LottieScaledWideAnimationTest-expected.png new file mode 100644 index 0000000..86784fd --- /dev/null +++ b/src/cobalt/renderer/rasterizer/testdata/LottieScaledWideAnimationTest-expected.png Binary files differ
diff --git a/src/cobalt/renderer/render_tree_pixel_tester.cc b/src/cobalt/renderer/render_tree_pixel_tester.cc index f617aab..d6e8be3 100644 --- a/src/cobalt/renderer/render_tree_pixel_tester.cc +++ b/src/cobalt/renderer/render_tree_pixel_tester.cc
@@ -77,6 +77,12 @@ // static bool RenderTreePixelTester::IsReferencePlatform() { +#if SB_API_VERSION < 12 && SB_HAS(BLITTER) + // The blitter rasterizer often relies on software rendering which may not + // produce the same results as GPU-based rendering. + return false; +#endif + const char* rasterizer_type = configuration::Configuration::GetInstance()->CobaltRasterizerType(); const bool is_opengles_rasterizer =
diff --git a/src/cobalt/script/v8c/v8c_global_environment.cc b/src/cobalt/script/v8c/v8c_global_environment.cc index 010b61d..4d43ade 100644 --- a/src/cobalt/script/v8c/v8c_global_environment.cc +++ b/src/cobalt/script/v8c/v8c_global_environment.cc
@@ -105,8 +105,6 @@ "V8cGlobalEnvironment::~V8cGlobalEnvironment()"); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); InvalidateWeakPtrs(); - destruction_helper_.global_wrappable_ = global_wrappable_.get(); - destruction_helper_.wrapper_factory_ = wrapper_factory_.get(); } void V8cGlobalEnvironment::CreateGlobalObject() { @@ -322,13 +320,6 @@ // Another GC to make sure global object is collected. isolate_->LowMemoryNotification(); isolate_->SetEmbedderHeapTracer(nullptr); - if (global_wrappable_ && global_wrappable_->RefCounts() != 1) { - // At this point only environment should hold the last reference. - DLOG(INFO) << "[Temporary debugging] more than one ref alive, ref_count: " - << global_wrappable_->RefCounts(); - DLOG(INFO) << "[Temporary debugging] window's v8 wrapper alive?" - << wrapper_factory_->HasWrapper(global_wrappable_); - } } // static
diff --git a/src/cobalt/script/v8c/v8c_global_environment.h b/src/cobalt/script/v8c/v8c_global_environment.h index be1f6aa..c131a8d 100644 --- a/src/cobalt/script/v8c/v8c_global_environment.h +++ b/src/cobalt/script/v8c/v8c_global_environment.h
@@ -132,9 +132,6 @@ explicit DestructionHelper(v8::Isolate* isolate) : isolate_(isolate) {} ~DestructionHelper(); - script::Wrappable* global_wrappable_; - WrapperFactory* wrapper_factory_; - private: v8::Isolate* isolate_; }; @@ -165,10 +162,10 @@ // destruct. Were we to not do this, finalizers can run in the order (e.g.) // document window, which the Cobalt DOM does not support. scoped_refptr<Wrappable> global_wrappable_; - std::unique_ptr<WrapperFactory> wrapper_factory_; DestructionHelper destruction_helper_; v8::Global<v8::Context> context_; + std::unique_ptr<WrapperFactory> wrapper_factory_; std::unique_ptr<V8cScriptValueFactory> script_value_factory_; // Data that is cached on a per-interface basis. Note that we can get to
diff --git a/src/cobalt/script/v8c/wrapper_factory.cc b/src/cobalt/script/v8c/wrapper_factory.cc index 27c3463..e123d1d 100644 --- a/src/cobalt/script/v8c/wrapper_factory.cc +++ b/src/cobalt/script/v8c/wrapper_factory.cc
@@ -38,17 +38,6 @@ << "RegisterWrappableType registered for type more than once."; } -bool WrapperFactory::HasWrapper(Wrappable* wrappable) { - v8::Local<v8::Object> wrapper; - v8::MaybeLocal<v8::Object> maybe_wrapper = - V8cWrapperHandle::MaybeGetObject(isolate_, GetCachedWrapper(wrappable)); - if (!maybe_wrapper.ToLocal(&wrapper)) { - return false; - } else { - return true; - } -} - v8::Local<v8::Object> WrapperFactory::GetWrapper( const scoped_refptr<Wrappable>& wrappable) { v8::Local<v8::Object> wrapper;
diff --git a/src/cobalt/script/v8c/wrapper_factory.h b/src/cobalt/script/v8c/wrapper_factory.h index 986e740..a78a9de 100644 --- a/src/cobalt/script/v8c/wrapper_factory.h +++ b/src/cobalt/script/v8c/wrapper_factory.h
@@ -50,8 +50,6 @@ v8::Local<v8::Object> GetWrapper(const scoped_refptr<Wrappable>& wrappable); - // Added temporarily for debugging purpose, will be removed soon. - bool HasWrapper(Wrappable* wrappable); // Attempt to get the |WrapperPrivate| associated with |wrappable|. Returns // |nullptr| if no |WrapperPrivate| was found. WrapperPrivate* MaybeGetWrapperPrivate(Wrappable* wrappable);
diff --git a/src/cobalt/site/docs/development/setup-android.md b/src/cobalt/site/docs/development/setup-android.md index 676c2e1..4a6f2b0 100644 --- a/src/cobalt/site/docs/development/setup-android.md +++ b/src/cobalt/site/docs/development/setup-android.md
@@ -37,6 +37,19 @@ python -m pip install requests ``` +1. Install ccache to support build acceleration. ccache is automatically used + when available, otherwise defaults to unaccelerated building: + + ``` + $ sudo apt-get install ccache + ``` + + We recommend adjusting the cache size as needed to increase cache hits: + + ``` + $ ccache --max-size=20G + ``` + 1. Download and install [Android Studio](https://developer.android.com/studio/). 1. Run `cobalt/build/gyp_cobalt android-x86` to configure the Cobalt build, which also installs the SDK and NDK. (This step will have to be repeated
diff --git a/src/cobalt/site/docs/development/setup-linux.md b/src/cobalt/site/docs/development/setup-linux.md index c0ac49e..3c4d49f 100644 --- a/src/cobalt/site/docs/development/setup-linux.md +++ b/src/cobalt/site/docs/development/setup-linux.md
@@ -9,6 +9,8 @@ on the machine that you are using to view the client. For example, you cannot SSH into another machine and run the binary on that machine. +## Set up your workstation + 1. Choose where you want to put the `depot_tools` directory, which is used by the Cobalt code. An easy option is to put them in `~/depot_tools`. Clone the tools by running the following command: @@ -48,6 +50,19 @@ && nvm use default ``` +1. Install ccache to support build acceleration. ccache is automatically used + when available, otherwise defaults to unaccelerated building: + + ``` + $ sudo apt install -qqy --no-install-recommends ccache + ``` + + We recommend adjusting the cache size as needed to increase cache hits: + + ``` + $ ccache --max-size=20G + ``` + 1. Clone the Cobalt code repository. The following `git` command creates a `cobalt` directory that contains the repository: @@ -55,6 +70,8 @@ $ git clone https://cobalt.googlesource.com/cobalt ``` +## Build and Run Cobalt + 1. Build the code by navigating to the `src` directory in your new `cobalt` directory and running the following command. You must specify a platform when running this command. On Ubuntu Linux, the
diff --git a/src/cobalt/site/docs/development/setup-raspi.md b/src/cobalt/site/docs/development/setup-raspi.md index 13936bb..3e88d8c 100644 --- a/src/cobalt/site/docs/development/setup-raspi.md +++ b/src/cobalt/site/docs/development/setup-raspi.md
@@ -48,15 +48,27 @@ $ apt-get remove -y --purge --auto-remove libgl1-mesa-dev \ libegl1-mesa-dev libgles2-mesa libgles2-mesa-dev $ apt-get install -y libpulse-dev libasound2-dev libavformat-dev \ - libavresample-dev + libavresample-dev rsync ``` ## Set up your workstation +<aside class="note"> +<b>Note:</b> Before proceeding further, refer to the documentation for ["Set up your environment - Linux"](setup-linux.md). Complete the section **Set up your workstation**, then return and complete the following steps. +</aside> + The following steps install the cross-compiling toolchain on your workstation. The toolchain runs on an x86 workstation and compiles binaries for your ARM Raspberry Pi. +1. Run the following command to install packages needed to build and run + Cobalt for Raspberry Pi: + + ``` + $ sudo apt install -qqy --no-install-recommends g++-multilib \ + python-requests wget xz-utils + ``` + 1. Choose a location for the installed toolchain – e.g. `raspi-tools` – and set `$RASPI_HOME` to that location. @@ -94,10 +106,16 @@ ## Build, install, and run Cobalt for Raspberry Pi -1. Run the following commands to build Cobalt: +1. Build the code by navigating to the src directory in your cobalt directory and run the + following command : ``` - $ gyp_cobalt raspi-2 + $ cobalt/build/gyp_cobalt raspi-2 + ``` + +1. Compile the code from the `src/` directory: + + ``` $ ninja -C out/raspi-2_debug cobalt ``` @@ -105,7 +123,7 @@ on the device: ``` - rsync -avzh --exclude="obj*" \ + rsync -avzLPh --exclude="obj*" --exclude="gen/" \ $COBALT_SRC/out/raspi-2_debug pi@$RASPI_ADDR:~/ ``` @@ -129,3 +147,21 @@ Note that you can also exit YouTube on Cobalt by hitting the `[Esc]` key enough times to bring up the "Do you want to quit YouTube?" dialog and selecting "yes". + +### Improving Cobalt performance on Raspberry Pi + +1. You will find that there are some processes installed by default that run on the + Raspberry Pi and can take away CPU time from Cobalt. You may wish to consider + disabling these processes for maximum (and more consistent) performance, as they + have been found to occasionally take >10% of the CPU according to `top`. + You can do this by typing: + + ``` + apt-get remove -y --auto-remove [PACKAGE_NAME, ...] + ``` + + For example: + + ``` + apt-get remove -y --auto-remove avahi-daemon + ```
diff --git a/src/cobalt/site/docs/reference/starboard/modules/10/file.md b/src/cobalt/site/docs/reference/starboard/modules/10/file.md index b115501..b9c0e36 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/10/file.md +++ b/src/cobalt/site/docs/reference/starboard/modules/10/file.md
@@ -169,7 +169,7 @@ is used primarily to clean up after unit tests. On some platforms, this function fails if the file in question is being held open. -`path`: The absolute path fo the file, symlink, or directory to be deleted. +`path`: The absolute path of the file, symlink, or directory to be deleted. #### Declaration ####
diff --git a/src/cobalt/site/docs/reference/starboard/modules/10/media.md b/src/cobalt/site/docs/reference/starboard/modules/10/media.md index 9b83d06..7271b29 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/10/media.md +++ b/src/cobalt/site/docs/reference/starboard/modules/10/media.md
@@ -665,6 +665,8 @@ outputs. If `true`, then non-protection-capable outputs are expected to be blanked. +presubmit: allow sb_export mismatch + #### Declaration #### ``` @@ -700,6 +702,8 @@ `enabled`: Indicates whether output protection is enabled (`true`) or disabled. +presubmit: allow sb_export mismatch + #### Declaration #### ```
diff --git a/src/cobalt/site/docs/reference/starboard/modules/11/file.md b/src/cobalt/site/docs/reference/starboard/modules/11/file.md index ad890dc..f910cb0 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/11/file.md +++ b/src/cobalt/site/docs/reference/starboard/modules/11/file.md
@@ -168,7 +168,7 @@ is used primarily to clean up after unit tests. On some platforms, this function fails if the file in question is being held open. -`path`: The absolute path fo the file, symlink, or directory to be deleted. +`path`: The absolute path of the file, symlink, or directory to be deleted. #### Declaration ####
diff --git a/src/cobalt/site/docs/reference/starboard/modules/11/media.md b/src/cobalt/site/docs/reference/starboard/modules/11/media.md index 8d94612..377cb2b 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/11/media.md +++ b/src/cobalt/site/docs/reference/starboard/modules/11/media.md
@@ -659,6 +659,8 @@ outputs. If `true`, then non-protection-capable outputs are expected to be blanked. +presubmit: allow sb_export mismatch + #### Declaration #### ``` @@ -712,6 +714,8 @@ `enabled`: Indicates whether output protection is enabled (`true`) or disabled. +presubmit: allow sb_export mismatch + #### Declaration #### ```
diff --git a/src/cobalt/site/docs/reference/starboard/modules/12/condition_variable.md b/src/cobalt/site/docs/reference/starboard/modules/12/condition_variable.md index 836c4b8..22c2b79 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/12/condition_variable.md +++ b/src/cobalt/site/docs/reference/starboard/modules/12/condition_variable.md
@@ -40,7 +40,7 @@ #### Definition #### ``` -typedef union SbConditionVariable SbConditionVariable +typedef union SbConditionVariable SbConditionVariable ``` ## Functions ##
diff --git a/src/cobalt/site/docs/reference/starboard/modules/12/file.md b/src/cobalt/site/docs/reference/starboard/modules/12/file.md index c3ba551..e22edeb 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/12/file.md +++ b/src/cobalt/site/docs/reference/starboard/modules/12/file.md
@@ -184,7 +184,7 @@ is used primarily to clean up after unit tests. On some platforms, this function fails if the file in question is being held open. -`path`: The absolute path fo the file, symlink, or directory to be deleted. +`path`: The absolute path of the file, symlink, or directory to be deleted. #### Declaration ####
diff --git a/src/cobalt/site/docs/reference/starboard/modules/12/mutex.md b/src/cobalt/site/docs/reference/starboard/modules/12/mutex.md index 58f1907..a9d2a9a 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/12/mutex.md +++ b/src/cobalt/site/docs/reference/starboard/modules/12/mutex.md
@@ -40,7 +40,7 @@ #### Definition #### ``` -typedef union SbMutex SbMutex +typedef union SbMutex SbMutex ``` ## Functions ##
diff --git a/src/cobalt/site/docs/reference/starboard/modules/12/once.md b/src/cobalt/site/docs/reference/starboard/modules/12/once.md index ce3c4d6..61aad5d 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/12/once.md +++ b/src/cobalt/site/docs/reference/starboard/modules/12/once.md
@@ -22,7 +22,7 @@ #### Definition #### ``` -typedef union SbOnceControl SbOnceControl +typedef union SbOnceControl SbOnceControl ``` ### SbOnceInitRoutine ###
diff --git a/src/cobalt/site/docs/reference/starboard/modules/condition_variable.md b/src/cobalt/site/docs/reference/starboard/modules/condition_variable.md index 836c4b8..22c2b79 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/condition_variable.md +++ b/src/cobalt/site/docs/reference/starboard/modules/condition_variable.md
@@ -40,7 +40,7 @@ #### Definition #### ``` -typedef union SbConditionVariable SbConditionVariable +typedef union SbConditionVariable SbConditionVariable ``` ## Functions ##
diff --git a/src/cobalt/site/docs/reference/starboard/modules/file.md b/src/cobalt/site/docs/reference/starboard/modules/file.md index c3ba551..e22edeb 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/file.md +++ b/src/cobalt/site/docs/reference/starboard/modules/file.md
@@ -184,7 +184,7 @@ is used primarily to clean up after unit tests. On some platforms, this function fails if the file in question is being held open. -`path`: The absolute path fo the file, symlink, or directory to be deleted. +`path`: The absolute path of the file, symlink, or directory to be deleted. #### Declaration ####
diff --git a/src/cobalt/site/docs/reference/starboard/modules/mutex.md b/src/cobalt/site/docs/reference/starboard/modules/mutex.md index 58f1907..a9d2a9a 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/mutex.md +++ b/src/cobalt/site/docs/reference/starboard/modules/mutex.md
@@ -40,7 +40,7 @@ #### Definition #### ``` -typedef union SbMutex SbMutex +typedef union SbMutex SbMutex ``` ## Functions ##
diff --git a/src/cobalt/site/docs/reference/starboard/modules/once.md b/src/cobalt/site/docs/reference/starboard/modules/once.md index ce3c4d6..61aad5d 100644 --- a/src/cobalt/site/docs/reference/starboard/modules/once.md +++ b/src/cobalt/site/docs/reference/starboard/modules/once.md
@@ -22,7 +22,7 @@ #### Definition #### ``` -typedef union SbOnceControl SbOnceControl +typedef union SbOnceControl SbOnceControl ``` ### SbOnceInitRoutine ###
diff --git a/src/cobalt/speech/audio_encoder_flac.cc b/src/cobalt/speech/audio_encoder_flac.cc index c6899de..279b5fe 100644 --- a/src/cobalt/speech/audio_encoder_flac.cc +++ b/src/cobalt/speech/audio_encoder_flac.cc
@@ -56,18 +56,18 @@ FLAC__stream_encoder_delete(encoder_); } -void AudioEncoderFlac::Encode(const ShellAudioBus* audio_bus) { +void AudioEncoderFlac::Encode(const AudioBus* audio_bus) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_EQ(audio_bus->channels(), size_t(1)); uint32 frames = static_cast<uint32>(audio_bus->frames()); std::unique_ptr<FLAC__int32[]> flac_samples(new FLAC__int32[frames]); for (uint32 i = 0; i < frames; ++i) { - if (audio_bus->sample_type() == ShellAudioBus::kFloat32) { + if (audio_bus->sample_type() == AudioBus::kFloat32) { flac_samples[i] = static_cast<FLAC__int32>( audio_bus->GetFloat32Sample(0, i) * kMaxInt16AsFloat32); } else { - DCHECK_EQ(audio_bus->sample_type(), ShellAudioBus::kInt16); + DCHECK_EQ(audio_bus->sample_type(), AudioBus::kInt16); flac_samples[i] = static_cast<FLAC__int32>(audio_bus->GetInt16Sample(0, i)); }
diff --git a/src/cobalt/speech/audio_encoder_flac.h b/src/cobalt/speech/audio_encoder_flac.h index 71b1822..3317af9 100644 --- a/src/cobalt/speech/audio_encoder_flac.h +++ b/src/cobalt/speech/audio_encoder_flac.h
@@ -20,7 +20,7 @@ #include "base/basictypes.h" #include "base/callback.h" #include "base/threading/thread_checker.h" -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #include "third_party/flac/include/FLAC/stream_encoder.h" namespace cobalt { @@ -29,13 +29,13 @@ // Encode raw audio to using FLAC codec. class AudioEncoderFlac { public: - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; explicit AudioEncoderFlac(int sample_rate); ~AudioEncoderFlac(); // Encode raw audio data. - void Encode(const ShellAudioBus* audio_bus); + void Encode(const AudioBus* audio_bus); // Finish encoding. void Finish();
diff --git a/src/cobalt/speech/cobalt_speech_recognizer.cc b/src/cobalt/speech/cobalt_speech_recognizer.cc index eb9fd8d..0d61e70 100644 --- a/src/cobalt/speech/cobalt_speech_recognizer.cc +++ b/src/cobalt/speech/cobalt_speech_recognizer.cc
@@ -123,7 +123,7 @@ } void CobaltSpeechRecognizer::OnDataReceived( - std::unique_ptr<ShellAudioBus> audio_bus) { + std::unique_ptr<AudioBus> audio_bus) { if (endpointer_delegate_.IsFirstTimeSoundStarted(*audio_bus)) { RunEventCallback(new dom::Event(base::Tokens::soundstart())); } @@ -135,8 +135,8 @@ // silence at the end in case encoder had no data already. size_t dummy_frames = static_cast<size_t>(kSampleRate * kAudioPacketDurationInSeconds); - std::unique_ptr<ShellAudioBus> dummy_audio_bus(new ShellAudioBus( - 1, dummy_frames, ShellAudioBus::kInt16, ShellAudioBus::kInterleaved)); + std::unique_ptr<AudioBus> dummy_audio_bus( + new AudioBus(1, dummy_frames, AudioBus::kInt16, AudioBus::kInterleaved)); dummy_audio_bus->ZeroAllFrames(); service_->RecognizeAudio(std::move(dummy_audio_bus), true); }
diff --git a/src/cobalt/speech/cobalt_speech_recognizer.h b/src/cobalt/speech/cobalt_speech_recognizer.h index f9ca9d4..d67ab5e 100644 --- a/src/cobalt/speech/cobalt_speech_recognizer.h +++ b/src/cobalt/speech/cobalt_speech_recognizer.h
@@ -18,7 +18,7 @@ #include <memory> #include <string> -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #include "cobalt/network/network_module.h" #include "cobalt/speech/endpointer_delegate.h" #include "cobalt/speech/google_speech_service.h" @@ -39,7 +39,7 @@ // from there. class CobaltSpeechRecognizer : public SpeechRecognizer { public: - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; CobaltSpeechRecognizer(network::NetworkModule* network_module, const Microphone::Options& microphone_options, @@ -51,7 +51,7 @@ private: // Callbacks from mic. - void OnDataReceived(std::unique_ptr<ShellAudioBus> audio_bus); + void OnDataReceived(std::unique_ptr<AudioBus> audio_bus); void OnDataCompletion(); void OnMicrophoneError(MicrophoneManager::MicrophoneError error, std::string error_message);
diff --git a/src/cobalt/speech/endpointer_delegate.cc b/src/cobalt/speech/endpointer_delegate.cc index 6340eea..1fc2658 100644 --- a/src/cobalt/speech/endpointer_delegate.cc +++ b/src/cobalt/speech/endpointer_delegate.cc
@@ -45,8 +45,7 @@ void EndPointerDelegate::Stop() { endpointer_.EndSession(); } -bool EndPointerDelegate::IsFirstTimeSoundStarted( - const ShellAudioBus& audio_bus) { +bool EndPointerDelegate::IsFirstTimeSoundStarted(const AudioBus& audio_bus) { if (is_first_time_sound_started_) { return false; }
diff --git a/src/cobalt/speech/endpointer_delegate.h b/src/cobalt/speech/endpointer_delegate.h index fe2f18b..e222f02 100644 --- a/src/cobalt/speech/endpointer_delegate.h +++ b/src/cobalt/speech/endpointer_delegate.h
@@ -15,8 +15,8 @@ #ifndef COBALT_SPEECH_ENDPOINTER_DELEGATE_H_ #define COBALT_SPEECH_ENDPOINTER_DELEGATE_H_ +#include "cobalt/media/base/audio_bus.h" #include "content/browser/speech/endpointer/endpointer.h" -#include "cobalt/media/base/shell_audio_bus.h" namespace cobalt { namespace speech { @@ -25,7 +25,7 @@ // speech session (from start speaking to end of speaking). class EndPointerDelegate { public: - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; explicit EndPointerDelegate(int sample_rate); ~EndPointerDelegate(); @@ -36,7 +36,7 @@ void Stop(); // Return true if it is the first time that the sound started. - bool IsFirstTimeSoundStarted(const ShellAudioBus& audio_bus); + bool IsFirstTimeSoundStarted(const AudioBus& audio_bus); private: // Used for detecting sound start event.
diff --git a/src/cobalt/speech/google_speech_service.cc b/src/cobalt/speech/google_speech_service.cc index 83ef7ec..0bd11ac 100644 --- a/src/cobalt/speech/google_speech_service.cc +++ b/src/cobalt/speech/google_speech_service.cc
@@ -220,8 +220,8 @@ base::Bind(&GoogleSpeechService::StopInternal, base::Unretained(this))); } -void GoogleSpeechService::RecognizeAudio( - std::unique_ptr<ShellAudioBus> audio_bus, bool is_last_chunk) { +void GoogleSpeechService::RecognizeAudio(std::unique_ptr<AudioBus> audio_bus, + bool is_last_chunk) { // Called by the speech recognition manager thread. thread_.message_loop()->task_runner()->PostTask( FROM_HERE, base::Bind(&GoogleSpeechService::UploadAudioDataInternal, @@ -393,7 +393,7 @@ } void GoogleSpeechService::UploadAudioDataInternal( - std::unique_ptr<ShellAudioBus> audio_bus, bool is_last_chunk) { + std::unique_ptr<AudioBus> audio_bus, bool is_last_chunk) { DCHECK_EQ(thread_.message_loop(), base::MessageLoop::current()); DCHECK(audio_bus);
diff --git a/src/cobalt/speech/google_speech_service.h b/src/cobalt/speech/google_speech_service.h index b0002ae..a1ea1e5 100644 --- a/src/cobalt/speech/google_speech_service.h +++ b/src/cobalt/speech/google_speech_service.h
@@ -21,7 +21,7 @@ #include "base/threading/thread.h" #include "cobalt/loader/url_fetcher_string_writer.h" -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #include "cobalt/network/network_module.h" #include "cobalt/speech/audio_encoder_flac.h" #include "cobalt/speech/google_streaming_api.pb.h" @@ -43,7 +43,7 @@ // manager. class GoogleSpeechService : public net::URLFetcherDelegate { public: - typedef media::ShellAudioBus ShellAudioBus; + typedef media::AudioBus AudioBus; typedef base::Callback<void(const scoped_refptr<dom::Event>&)> EventCallback; typedef SpeechRecognitionResultList::SpeechRecognitionResults SpeechRecognitionResults; @@ -63,8 +63,7 @@ // Stop speech recognizer. void Stop(); // An encoded audio data is available and ready to be recognized. - void RecognizeAudio(std::unique_ptr<ShellAudioBus> audio_bus, - bool is_last_chunk); + void RecognizeAudio(std::unique_ptr<AudioBus> audio_bus, bool is_last_chunk); // net::URLFetcherDelegate interface void OnURLFetchDownloadProgress(const net::URLFetcher* source, @@ -81,7 +80,7 @@ void StopInternal(); // This method handles wrappables and should run on the MainWebModule thread. void ClearFinalResults(); - void UploadAudioDataInternal(std::unique_ptr<ShellAudioBus> audio_bus, + void UploadAudioDataInternal(std::unique_ptr<AudioBus> audio_bus, bool is_last_chunk); // This method handles wrappables, and so it must run on the MainWebModule. void ProcessAndFireSuccessEvent(proto::SpeechRecognitionEvent event);
diff --git a/src/cobalt/speech/microphone_fake.cc b/src/cobalt/speech/microphone_fake.cc index 15c955a..a85c191 100644 --- a/src/cobalt/speech/microphone_fake.cc +++ b/src/cobalt/speech/microphone_fake.cc
@@ -24,14 +24,14 @@ #include "base/path_service.h" #include "base/rand_util.h" #include "cobalt/audio/audio_file_reader.h" -#include "starboard/file.h" +#include "starboard/common/file.h" #include "starboard/memory.h" #include "starboard/time.h" namespace cobalt { namespace speech { -typedef audio::ShellAudioBus ShellAudioBus; +typedef audio::AudioBus AudioBus; namespace { @@ -89,10 +89,10 @@ } else { file_length_ = std::min(options.audio_data_size, kMaxBufferSize); DCHECK_GT(file_length_, 0); - audio_bus_.reset(new ShellAudioBus( - kSupportedMonoChannel, - file_length_ / audio::GetSampleTypeSize(ShellAudioBus::kInt16), - ShellAudioBus::kInt16, ShellAudioBus::kInterleaved)); + audio_bus_.reset( + new AudioBus(kSupportedMonoChannel, + file_length_ / audio::GetSampleTypeSize(AudioBus::kInt16), + AudioBus::kInt16, AudioBus::kInterleaved)); SbMemoryCopy(audio_bus_->interleaved_data(), options.external_audio_data, file_length_); } @@ -131,14 +131,14 @@ const float kSupportedSampleRate = 16000.0f; if (!reader) { // If it is not a WAV file, read audio data as raw audio. - audio_bus_.reset(new ShellAudioBus( + audio_bus_.reset(new AudioBus( kSupportedMonoChannel, - file_buffer_size / audio::GetSampleTypeSize(ShellAudioBus::kInt16), - ShellAudioBus::kInt16, ShellAudioBus::kInterleaved)); + file_buffer_size / audio::GetSampleTypeSize(AudioBus::kInt16), + AudioBus::kInt16, AudioBus::kInterleaved)); SbMemoryCopy(audio_bus_->interleaved_data(), audio_input.get(), file_buffer_size); file_length_ = file_buffer_size; - } else if (reader->sample_type() != ShellAudioBus::kInt16 || + } else if (reader->sample_type() != AudioBus::kInt16 || reader->sample_rate() != kSupportedSampleRate || reader->number_of_channels() != kSupportedMonoChannel) { // If it is a WAV file but it doesn't meet the audio input criteria, treat
diff --git a/src/cobalt/speech/microphone_fake.h b/src/cobalt/speech/microphone_fake.h index ac4cf8b..3f6cbbc 100644 --- a/src/cobalt/speech/microphone_fake.h +++ b/src/cobalt/speech/microphone_fake.h
@@ -52,7 +52,7 @@ bool read_data_from_file_; std::vector<base::FilePath> file_paths_; - std::unique_ptr<audio::ShellAudioBus> audio_bus_; + std::unique_ptr<audio::AudioBus> audio_bus_; int file_length_; int read_index_; bool is_valid_;
diff --git a/src/cobalt/speech/microphone_manager.cc b/src/cobalt/speech/microphone_manager.cc index a957f2d..cddf31e 100644 --- a/src/cobalt/speech/microphone_manager.cc +++ b/src/cobalt/speech/microphone_manager.cc
@@ -145,9 +145,9 @@ // If |read_bytes| is zero, nothing should happen. if (read_bytes > 0 && read_bytes % sizeof(int16_t) == 0) { size_t frames = read_bytes / sizeof(int16_t); - std::unique_ptr<ShellAudioBus> output_audio_bus(new ShellAudioBus( - 1, frames, ShellAudioBus::kInt16, ShellAudioBus::kInterleaved)); - ShellAudioBus source(1, frames, samples); + std::unique_ptr<AudioBus> output_audio_bus( + new AudioBus(1, frames, AudioBus::kInt16, AudioBus::kInterleaved)); + AudioBus source(1, frames, samples); output_audio_bus->Assign(source); data_received_callback_.Run(std::move(output_audio_bus)); } else if (read_bytes != 0) {
diff --git a/src/cobalt/speech/microphone_manager.h b/src/cobalt/speech/microphone_manager.h index 765d2b6..602f6bf 100644 --- a/src/cobalt/speech/microphone_manager.h +++ b/src/cobalt/speech/microphone_manager.h
@@ -25,7 +25,7 @@ #include "base/threading/thread.h" #include "base/timer/timer.h" #include "cobalt/dom/event.h" -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #include "cobalt/speech/microphone.h" namespace cobalt { @@ -39,9 +39,8 @@ kAudioCapture, kAborted, }; - typedef media::ShellAudioBus ShellAudioBus; - typedef base::Callback<void(std::unique_ptr<ShellAudioBus>)> - DataReceivedCallback; + typedef media::AudioBus AudioBus; + typedef base::Callback<void(std::unique_ptr<AudioBus>)> DataReceivedCallback; typedef base::Closure CompletionCallback; typedef base::Closure SuccessfulOpenCallback; typedef base::Callback<void(MicrophoneError, std::string)> ErrorCallback;
diff --git a/src/cobalt/ui_navigation/nav_item.cc b/src/cobalt/ui_navigation/nav_item.cc index 05f49d6..8eaf1f3 100644 --- a/src/cobalt/ui_navigation/nav_item.cc +++ b/src/cobalt/ui_navigation/nav_item.cc
@@ -31,7 +31,9 @@ onfocus_callback_(onfocus_callback), onscroll_callback_(onscroll_callback), nav_item_type_(type), - nav_item_(GetInterface().create_item(type, &s_callbacks_, this)) {} + nav_item_(GetInterface().create_item(type, &s_callbacks_, this)) { + SbAtomicNoBarrier_Store8(&enabled_, 0); +} NavItem::~NavItem() { GetInterface().set_item_enabled(nav_item_, false);
diff --git a/src/cobalt/ui_navigation/nav_item.h b/src/cobalt/ui_navigation/nav_item.h index 64d6aac..c43662f 100644 --- a/src/cobalt/ui_navigation/nav_item.h +++ b/src/cobalt/ui_navigation/nav_item.h
@@ -18,6 +18,7 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "cobalt/ui_navigation/interface.h" +#include "starboard/atomic.h" namespace cobalt { namespace ui_navigation { @@ -39,10 +40,19 @@ } void Focus() { - GetInterface().set_focus(nav_item_); + if (SbAtomicNoBarrier_Load8(&enabled_)) { + GetInterface().set_focus(nav_item_); + } + } + + void UnfocusAll() { +#if SB_API_VERSION >= SB_UI_NAVIGATION2_VERSION + GetInterface().set_focus(kNativeItemInvalid); +#endif } void SetEnabled(bool enabled) { + SbAtomicNoBarrier_Store8(&enabled_, enabled ? 1 : 0); GetInterface().set_item_enabled(nav_item_, enabled); } @@ -104,6 +114,7 @@ NativeItemType nav_item_type_; NativeItem nav_item_; + SbAtomic8 enabled_; static NativeCallbacks s_callbacks_; };
diff --git a/src/cobalt/updater/configurator.cc b/src/cobalt/updater/configurator.cc index d626083..210f088 100644 --- a/src/cobalt/updater/configurator.cc +++ b/src/cobalt/updater/configurator.cc
@@ -31,6 +31,7 @@ #if defined(COBALT_BUILD_TYPE_DEBUG) || defined(COBALT_BUILD_TYPE_DEVEL) const std::set<std::string> valid_channels = {"dev"}; +const std::string kDefaultUpdaterChannel = "dev"; #elif defined(COBALT_BUILD_TYPE_QA) // Find more information about these test channels in the Evergreen test plan. const std::set<std::string> valid_channels = { @@ -51,8 +52,10 @@ // Test an update that's larger than the available storage on the device "tistore", }; +const std::string kDefaultUpdaterChannel = "qa"; #elif defined(COBALT_BUILD_TYPE_GOLD) const std::set<std::string> valid_channels = {"prod", "dogfood"}; +const std::string kDefaultUpdaterChannel = "prod"; #endif std::string GetDeviceProperty(SbSystemPropertyId id) { @@ -74,10 +77,21 @@ Configurator::Configurator(network::NetworkModule* network_module) : pref_service_(CreatePrefService()), + persisted_data_(std::make_unique<update_client::PersistedData>( + pref_service_.get(), nullptr)), + is_channel_changed_(0), unzip_factory_(base::MakeRefCounted<UnzipperFactory>()), network_fetcher_factory_( base::MakeRefCounted<NetworkFetcherFactoryCobalt>(network_module)), - patch_factory_(base::MakeRefCounted<PatcherFactory>()) {} + patch_factory_(base::MakeRefCounted<PatcherFactory>()) { + const std::string persisted_channel = + persisted_data_->GetUpdaterChannel(GetAppGuid()); + if (persisted_channel.empty()) { + SetChannel(kDefaultUpdaterChannel); + } else { + SetChannel(persisted_channel); + } +} Configurator::~Configurator() = default; int Configurator::InitialDelay() const { return 0; } @@ -134,9 +148,9 @@ params.insert(std::make_pair("sbversion", std::to_string(SB_API_VERSION))); params.insert(std::make_pair( "jsengine", script::GetJavaScriptEngineNameAndVersion())); - params.insert(std::make_pair("updaterchannelchanged", - IsChannelChanged() ? "True" : "False")); - + params.insert(std::make_pair( + "updaterchannelchanged", + SbAtomicNoBarrier_Load(&is_channel_changed_) == 1 ? "True" : "False")); // Brand name params.insert( std::make_pair("brand", GetDeviceProperty(kSbSystemPropertyBrandName))); @@ -200,6 +214,10 @@ return {}; } +void Configurator::CompareAndSwapChannelChanged(int old_value, int new_value) { + SbAtomicNoBarrier_CompareAndSwap(&is_channel_changed_, old_value, new_value); +} + // The updater channel is get and set by main web module thread and update // client thread. The getter and set use a lock to prevent synchronization // issue. @@ -211,6 +229,7 @@ void Configurator::SetChannel(const std::string& updater_channel) { base::AutoLock auto_lock(updater_channel_lock_); updater_channel_ = updater_channel; + persisted_data_->SetUpdaterChannel(GetAppGuid(), updater_channel); } bool Configurator::IsChannelValid(const std::string& channel) {
diff --git a/src/cobalt/updater/configurator.h b/src/cobalt/updater/configurator.h index 8012b2f..e335b4f 100644 --- a/src/cobalt/updater/configurator.h +++ b/src/cobalt/updater/configurator.h
@@ -17,6 +17,7 @@ #include "base/synchronization/lock.h" #include "cobalt/network/network_module.h" #include "components/update_client/configurator.h" +#include "components/update_client/persisted_data.h" class GURL; class PrefService; @@ -76,8 +77,8 @@ void SetChannel(const std::string& updater_channel) override; - void MarkChannelChanged() { is_channel_changed = true; } - bool IsChannelChanged() const override { return is_channel_changed; } + void CompareAndSwapChannelChanged(int old_value, int new_value) override; + bool IsChannelValid(const std::string& channel); std::string GetUpdaterStatus() const; @@ -88,12 +89,13 @@ ~Configurator() override; std::unique_ptr<PrefService> pref_service_; + std::unique_ptr<update_client::PersistedData> persisted_data_; scoped_refptr<update_client::NetworkFetcherFactory> network_fetcher_factory_; scoped_refptr<update_client::UnzipperFactory> unzip_factory_; scoped_refptr<update_client::PatcherFactory> patch_factory_; std::string updater_channel_; base::Lock updater_channel_lock_; - bool is_channel_changed = false; + SbAtomic32 is_channel_changed_; std::string updater_status_; base::Lock updater_status_lock_;
diff --git a/src/cobalt/updater/crash_sandbox.cc b/src/cobalt/updater/crash_sandbox.cc index 8f69c81..869c589 100644 --- a/src/cobalt/updater/crash_sandbox.cc +++ b/src/cobalt/updater/crash_sandbox.cc
@@ -18,5 +18,6 @@ #include "starboard/event.h" void SbEventHandle(const SbEvent* event) { - SB_CHECK(false); + volatile int* a = (int*)(NULL); + *a = 1; }
diff --git a/src/cobalt/updater/updater_module.cc b/src/cobalt/updater/updater_module.cc index 0a7904e..2f0452b 100644 --- a/src/cobalt/updater/updater_module.cc +++ b/src/cobalt/updater/updater_module.cc
@@ -246,6 +246,10 @@ base::TimeDelta::FromHours(kNextUpdateCheckHours)); } +void UpdaterModule::CompareAndSwapChannelChanged(int old_value, int new_value) { + updater_configurator_->CompareAndSwapChannelChanged(old_value, new_value); +} + // The following three methods all called by the main web module thread. std::string UpdaterModule::GetUpdaterChannel() const { return updater_configurator_->GetChannel();
diff --git a/src/cobalt/updater/updater_module.h b/src/cobalt/updater/updater_module.h index c441d1d..d275556 100644 --- a/src/cobalt/updater/updater_module.h +++ b/src/cobalt/updater/updater_module.h
@@ -65,8 +65,7 @@ std::string GetUpdaterChannel() const; void SetUpdaterChannel(const std::string& updater_channel); - void MarkChannelChanged() { updater_configurator_->MarkChannelChanged(); } - bool IsChannelChanged() { return updater_configurator_->IsChannelChanged(); } + void CompareAndSwapChannelChanged(int old_value, int new_value); bool IsChannelValid(const std::string& channel) { return updater_configurator_->IsChannelValid(channel); }
diff --git a/src/cobalt/updater/utils.cc b/src/cobalt/updater/utils.cc index 17f0822..dab4b92 100644 --- a/src/cobalt/updater/utils.cc +++ b/src/cobalt/updater/utils.cc
@@ -22,6 +22,12 @@ namespace cobalt { namespace updater { +namespace { +// The default manifest version to assume when the actual manifest cannot be +// parsed for any reason. This should not be used for installation manager +// errors, or any other error unrelated to parsing the manifest. +const std::string kDefaultManifestVersion = "1.0.0"; +} // namespace bool CreateProductDirectory(base::FilePath* path) { if (!GetProductDirectoryPath(path)) { @@ -112,6 +118,12 @@ std::string(installation_path.begin(), installation_path.end()))); if (!version.IsValid()) { + if (!index) { + SB_LOG(ERROR) << "Failed to get the Everegreen version. Defaulting to " + << kDefaultManifestVersion << "."; + return kDefaultManifestVersion; + } + SB_LOG(ERROR) << "Failed to get the Everegreen version."; return ""; }
diff --git a/src/cobalt/xhr/url_fetcher_buffer_writer.cc b/src/cobalt/xhr/url_fetcher_buffer_writer.cc index a01a9a8..3b43b8a 100644 --- a/src/cobalt/xhr/url_fetcher_buffer_writer.cc +++ b/src/cobalt/xhr/url_fetcher_buffer_writer.cc
@@ -103,7 +103,8 @@ return copy_of_data_as_string_; } -void URLFetcherResponseWriter::Buffer::GetAndReset(std::string* str) { +void URLFetcherResponseWriter::Buffer::GetAndResetDataAndDownloadProgress( + std::string* str) { DCHECK(str); ReleaseMemory(str); @@ -119,9 +120,15 @@ } data_as_string_.swap(*str); + + // It is important to reset the |download_progress_| and return the data in + // one function to avoid potential race condition that may prevent the last + // bit of data of Fetcher from being downloaded, because the data download is + // guarded by HasProgressSinceLastGetAndReset(). + download_progress_ = 0; } -void URLFetcherResponseWriter::Buffer::GetAndReset( +void URLFetcherResponseWriter::Buffer::GetAndResetData( PreallocatedArrayBufferData* data) { DCHECK(data);
diff --git a/src/cobalt/xhr/url_fetcher_buffer_writer.h b/src/cobalt/xhr/url_fetcher_buffer_writer.h index c82ce32..8eb9736 100644 --- a/src/cobalt/xhr/url_fetcher_buffer_writer.h +++ b/src/cobalt/xhr/url_fetcher_buffer_writer.h
@@ -57,8 +57,8 @@ // public member function is called on this object. const std::string& GetTemporaryReferenceOfString(); - void GetAndReset(std::string* str); - void GetAndReset(PreallocatedArrayBufferData* data); + void GetAndResetDataAndDownloadProgress(std::string* str); + void GetAndResetData(PreallocatedArrayBufferData* data); void MaybePreallocate(int64_t capacity); void Write(const void* buffer, int num_bytes);
diff --git a/src/cobalt/xhr/xml_http_request.cc b/src/cobalt/xhr/xml_http_request.cc index 27408e2..0ea3345 100644 --- a/src/cobalt/xhr/xml_http_request.cc +++ b/src/cobalt/xhr/xml_http_request.cc
@@ -717,7 +717,7 @@ if (fetch_callback_) { std::string downloaded_data; - response_body_->GetAndReset(&downloaded_data); + response_body_->GetAndResetDataAndDownloadProgress(&downloaded_data); script::Handle<script::Uint8Array> data = script::Uint8Array::New(settings_->global_environment(), downloaded_data.data(), downloaded_data.size()); @@ -729,9 +729,13 @@ const base::TimeDelta elapsed(now - last_progress_time_); if (elapsed > base::TimeDelta::FromMilliseconds(kProgressPeriodMs)) { last_progress_time_ = now; - // TODO: Investigate if we have to fire progress event with 0 loaded bytes - // when used as Fetch API. - UpdateProgress(response_body_->GetAndResetDownloadProgress()); + if (fetch_callback_) { + // TODO: Investigate if we have to fire progress event with 0 loaded bytes + // when used as Fetch API. + UpdateProgress(0); + } else { + UpdateProgress(response_body_->GetAndResetDownloadProgress()); + } } } @@ -1025,7 +1029,7 @@ // request is re-opened. std::unique_ptr<script::PreallocatedArrayBufferData> downloaded_data( new script::PreallocatedArrayBufferData()); - response_body_->GetAndReset(downloaded_data.get()); + response_body_->GetAndResetData(downloaded_data.get()); auto array_buffer = script::ArrayBuffer::New( settings_->global_environment(), std::move(downloaded_data)); response_array_buffer_reference_.reset(
diff --git a/src/components/update_client/component.cc b/src/components/update_client/component.cc index df190d0..50ec274 100644 --- a/src/components/update_client/component.cc +++ b/src/components/update_client/component.cc
@@ -195,6 +195,14 @@ #endif if (result.error != UnpackerError::kNone) { +#if defined(OS_STARBOARD) + // When there is an error unpacking the downloaded CRX, such as a failure to + // verify the package, we should remember to clear out any drain files. + if (base::DirectoryExists(crx_path.DirName())) { + CobaltSlotManagement cobalt_slot_management; + cobalt_slot_management.CleanupAllDrainFiles(crx_path.DirName()); + } +#endif main_task_runner->PostTask( FROM_HERE, base::BindOnce(std::move(callback), ErrorCategory::kUnpack,
diff --git a/src/components/update_client/configurator.h b/src/components/update_client/configurator.h index 5baa3cc..ab7e01e 100644 --- a/src/components/update_client/configurator.h +++ b/src/components/update_client/configurator.h
@@ -171,7 +171,9 @@ // parameters. virtual void SetChannel(const std::string& channel) = 0; - virtual bool IsChannelChanged() const = 0; + // Compare and swap the is_channel_changed flag. + virtual void CompareAndSwapChannelChanged(int old_value, int new_value) = 0; + #endif protected:
diff --git a/src/components/update_client/test_configurator.h b/src/components/update_client/test_configurator.h index f6ede80..c3fbda1 100644 --- a/src/components/update_client/test_configurator.h +++ b/src/components/update_client/test_configurator.h
@@ -128,7 +128,7 @@ #if defined(STARBOARD) void SetChannel(const std::string& channel) override {} - bool IsChannelChanged() const override { return false; } + void CompareAndSwapChannelChanged(int old_value, int new_value) override {} #else network::TestURLLoaderFactory* test_url_loader_factory() { return &test_url_loader_factory_;
diff --git a/src/components/update_client/update_checker.cc b/src/components/update_client/update_checker.cc index c4045f0..3cfa2d5 100644 --- a/src/components/update_client/update_checker.cc +++ b/src/components/update_client/update_checker.cc
@@ -44,14 +44,6 @@ namespace { -#if defined(COBALT_BUILD_TYPE_DEBUG) || defined(COBALT_BUILD_TYPE_DEVEL) -const std::string kDefaultUpdaterChannel = "dev"; -#elif defined(COBALT_BUILD_TYPE_QA) -const std::string kDefaultUpdaterChannel = "qa"; -#elif defined(COBALT_BUILD_TYPE_GOLD) -const std::string kDefaultUpdaterChannel = "prod"; -#endif - // Returns a sanitized version of the brand or an empty string otherwise. std::string SanitizeBrand(const std::string& brand) { return IsValidBrand(brand) ? brand : std::string(""); @@ -249,22 +241,6 @@ MakeProtocolPing(app_id, metadata_))); } std::string updater_channel = config_->GetChannel(); -#if defined(OS_STARBOARD) - // If the updater channel is not set, read from pref store instead. - if (updater_channel.empty()) { - // All apps of the update use the same channel. - updater_channel = GetPersistedData()->GetUpdaterChannel(ids_checked_[0]); - if (updater_channel.empty()) { - updater_channel = kDefaultUpdaterChannel; - } - // Set the updater channel from the persistent store or to default channel, - // if it's not set already. - config_->SetChannel(updater_channel); - } else { - // Update the record of updater channel in pref store. - GetPersistedData()->SetUpdaterChannel(ids_checked_[0], updater_channel); - } -#endif const auto request = MakeProtocolRequest( session_id, config_->GetProdId(), @@ -284,6 +260,10 @@ config_->EnabledCupSigning(), base::BindOnce(&UpdateCheckerImpl::OnRequestSenderComplete, base::Unretained(this))); +#if defined(OS_STARBOARD) + // Reset is_channel_changed flag to false if it is true + config_->CompareAndSwapChannelChanged(1, 0); +#endif } void UpdateCheckerImpl::OnRequestSenderComplete(int error,
diff --git a/src/content/browser/speech/endpointer/endpointer.cc b/src/content/browser/speech/endpointer/endpointer.cc index 5c19c4a..96d8e6c 100644 --- a/src/content/browser/speech/endpointer/endpointer.cc +++ b/src/content/browser/speech/endpointer/endpointer.cc
@@ -89,7 +89,7 @@ } #if defined(STARBOARD) -EpStatus Endpointer::ProcessAudio(const ShellAudioBus& audio_bus, float* rms_out) { +EpStatus Endpointer::ProcessAudio(const AudioBus& audio_bus, float* rms_out) { // TODO[Cobalt]: replace ShellAudioData with AudioChunk and deprecate // ShellAudioData. DCHECK_EQ(audio_bus.channels(), 1); @@ -97,16 +97,16 @@ const size_t num_samples = audio_bus.frames(); const int16_t* audio_data = NULL; - ShellAudioBus int16_audio_bus(1, num_samples, ShellAudioBus::kInt16, - ShellAudioBus::kInterleaved); + AudioBus int16_audio_bus(1, num_samples, AudioBus::kInt16, + AudioBus::kInterleaved); - if (audio_bus.sample_type() == ShellAudioBus::kFloat32) { + if (audio_bus.sample_type() == AudioBus::kFloat32) { int16_audio_bus.Assign(audio_bus); - DCHECK_EQ(int16_audio_bus.sample_type(), ShellAudioBus::kInt16); + DCHECK_EQ(int16_audio_bus.sample_type(), AudioBus::kInt16); audio_data = reinterpret_cast<const int16_t*>(int16_audio_bus.interleaved_data()); } else { - DCHECK_EQ(audio_bus.sample_type(), ShellAudioBus::kInt16); + DCHECK_EQ(audio_bus.sample_type(), AudioBus::kInt16); audio_data = reinterpret_cast<const int16_t*>(audio_bus.interleaved_data()); }
diff --git a/src/content/browser/speech/endpointer/endpointer.h b/src/content/browser/speech/endpointer/endpointer.h index 16bfed6..2264842 100644 --- a/src/content/browser/speech/endpointer/endpointer.h +++ b/src/content/browser/speech/endpointer/endpointer.h
@@ -7,7 +7,7 @@ #include <stdint.h> -#include "cobalt/media/base/shell_audio_bus.h" +#include "cobalt/media/base/audio_bus.h" #include "content/browser/speech/endpointer/energy_endpointer.h" #include "content/common/content_export.h" @@ -47,7 +47,7 @@ // long_speech_input_complete_silence_length. class CONTENT_EXPORT Endpointer { public: - typedef cobalt::media::ShellAudioBus ShellAudioBus; + typedef cobalt::media::AudioBus AudioBus; explicit Endpointer(int sample_rate); @@ -68,7 +68,7 @@ // Process a segment of audio, which may be more than one frame. // The status of the last frame will be returned. #if defined(STARBOARD) - EpStatus ProcessAudio(const ShellAudioBus& audio_bus, float* rms_out); + EpStatus ProcessAudio(const AudioBus& audio_bus, float* rms_out); #else EpStatus ProcessAudio(const AudioChunk& raw_audio, float* rms_out); #endif
diff --git a/src/content/browser/speech/endpointer/endpointer_unittest.cc b/src/content/browser/speech/endpointer/endpointer_unittest.cc index 632cc37..4b3cbb5 100644 --- a/src/content/browser/speech/endpointer/endpointer_unittest.cc +++ b/src/content/browser/speech/endpointer/endpointer_unittest.cc
@@ -120,7 +120,7 @@ class EndpointerFrameProcessor : public FrameProcessor { public: #if defined(STARBOARD) - typedef Endpointer::ShellAudioBus ShellAudioBus; + typedef Endpointer::AudioBus AudioBus; #endif explicit EndpointerFrameProcessor(Endpointer* endpointer) : endpointer_(endpointer) {} @@ -129,7 +129,7 @@ int16_t* samples, int frame_size) override { #if defined(STARBOARD) - auto frame = std::make_unique<ShellAudioBus>(1, kFrameSize, samples); + auto frame = std::make_unique<AudioBus>(1, kFrameSize, samples); endpointer_->ProcessAudio(*frame.get(), NULL); #else scoped_refptr<AudioChunk> frame(
diff --git a/src/docker-compose.yml b/src/docker-compose.yml index 30d600f..749a24a 100644 --- a/src/docker-compose.yml +++ b/src/docker-compose.yml
@@ -31,6 +31,15 @@ dockerfile: base/Dockerfile image: cobalt-base + base-xenial: + build: + args: + - BASE_OS=ubuntu + - BASE_OS_TAG=xenial + context: ./docker/linux + dockerfile: base/Dockerfile + image: base-xenial + # Define common build container for Linux build-base: build: @@ -40,6 +49,16 @@ depends_on: - base + build-base-xenial: + build: + context: ./docker/linux + dockerfile: base/build/Dockerfile + args: + - FROM_IMAGE=base-xenial + image: build-base-xenial + depends_on: + - base-xenial + stub: <<: *build-common-definitions build: @@ -56,10 +75,36 @@ context: ./docker/linux dockerfile: linux-x64x11/Dockerfile image: cobalt-build-linux + depends_on: [ build-base ] environment: - PLATFORM=linux-x64x11 - CONFIG=${CONFIG:-debug} + linux-x64x11-xenial: + <<: *common-definitions + <<: *build-volumes + build: + context: ./docker/linux + dockerfile: linux-x64x11/Dockerfile + args: + - FROM_IMAGE=build-base-xenial + image: linux-x64x11-xenial + depends_on: + - build-base-xenial + + linux-x64x11-clang-3-6: + <<: *common-definitions + <<: *build-volumes + build: + context: ./docker/linux/ + dockerfile: clang-3-6/Dockerfile + image: cobalt-build-linux-clang-3-6 + environment: + - PLATFORM=linux-x64x11-clang-3-6 + - CONFIG=${CONFIG:-debug} + depends_on: + - linux-x64x11-xenial + # Define common build container for Android build-android: <<: *build-common-definitions @@ -71,7 +116,7 @@ android-x86: <<: *build-common-definitions image: cobalt-build-android - depends_on: [ build-evergreen ] + depends_on: [ build-android ] environment: - IS_DOCKER=1 - PLATFORM=android-x86 @@ -80,7 +125,7 @@ android-arm: <<: *build-common-definitions image: cobalt-build-android - depends_on: [ build-evergreen ] + depends_on: [ build-android ] environment: - IS_DOCKER=1 - PLATFORM=android-arm @@ -89,7 +134,7 @@ android-arm64: <<: *build-common-definitions image: cobalt-build-android - depends_on: [ build-evergreen ] + depends_on: [ build-android ] environment: - IS_DOCKER=1 - PLATFORM=android-arm64 @@ -160,8 +205,8 @@ environment: - PLATFORM=${PLATFORM:-linux-x64x11} - CONFIG=${CONFIG:-debug} - - TEST_TARGET=${TEST_TARGET:-eztime_test} volumes: - ${COBALT_SRC:-.}/out/${PLATFORM:-linux-x64x11}_${CONFIG:-debug}:/out # TODO: Get NPLB unittests to run with IPv6 without using the host network. network_mode: "host" + depends_on: [ base ]
diff --git a/src/docker/linux/android/Dockerfile b/src/docker/linux/android/Dockerfile index d76e0ce..ad34732 100644 --- a/src/docker/linux/android/Dockerfile +++ b/src/docker/linux/android/Dockerfile
@@ -16,6 +16,8 @@ && rm -rf /var/lib/{apt,dpkg,cache,log} \ && echo "Done" +RUN mkdir -p /root/.android + CMD (test -f /root/.android/debug.keystore \ && echo "Android debug keystore exists." \ || (keytool -genkey -v \
diff --git a/src/docker/linux/base/Dockerfile b/src/docker/linux/base/Dockerfile index 4f21c76..2746def 100644 --- a/src/docker/linux/base/Dockerfile +++ b/src/docker/linux/base/Dockerfile
@@ -1,5 +1,6 @@ ARG BASE_OS -FROM ${BASE_OS:-gcr.io/cloud-marketplace-containers/google/debian9} +ARG BASE_OS_TAG +FROM ${BASE_OS:-gcr.io/cloud-marketplace-containers/google/debian9}:${BASE_OS_TAG:-latest} ENV PYTHONUNBUFFERED 1
diff --git a/src/docker/linux/base/build/Dockerfile b/src/docker/linux/base/build/Dockerfile index 416b5ee..545908d 100644 --- a/src/docker/linux/base/build/Dockerfile +++ b/src/docker/linux/base/build/Dockerfile
@@ -1,4 +1,5 @@ -FROM cobalt-base +ARG FROM_IMAGE +FROM ${FROM_IMAGE:-cobalt-base} # === Get Nodejs pinned LTS version via NVM ENV NVM_DIR /root/.nvm @@ -18,17 +19,15 @@ RUN git clone https://cobalt.googlesource.com/depot_tools /depot_tools # === Configure common env vars -ENV PATH="${PATH}:/depot_tools:/root/fake_goma" \ +ENV PATH="${PATH}:/depot_tools" \ OUTDIR=out \ DEPOT_TOOLS_UPDATE=0 \ NINJA_STATUS="[%f/%t %c/sec] " \ CCACHE_DIR=/root/ccache \ CCACHE_MAXSIZE=30G -# == Set up gclient and fake Goma with ccache -COPY ./files/fake_goma /root/fake_goma +# == Set up gclient and ccache RUN cd /tmp && gclient verify || true \ - && chmod +x /root/fake_goma/gomacc /root/fake_goma/goma_ctl.py \ && mkdir /root/ccache WORKDIR /code
diff --git a/src/docker/linux/clang-3-6/Dockerfile b/src/docker/linux/clang-3-6/Dockerfile new file mode 100644 index 0000000..0bf3926 --- /dev/null +++ b/src/docker/linux/clang-3-6/Dockerfile
@@ -0,0 +1,14 @@ +FROM linux-x64x11-xenial + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt update -qqy \ + && apt install -qqy --no-install-recommends clang-3.6 \ + && apt-get clean autoclean \ + && apt-get autoremove -y --purge \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ + && rm -rf /var/lib/{apt,dpkg,cache,log} \ + && echo "Done" + +CMD /code/cobalt/build/gyp_cobalt -v -C ${CONFIG} ${PLATFORM} && \ + ninja -C ${OUTDIR}/${PLATFORM}_${CONFIG} ${TARGET:-cobalt_deploy}
diff --git a/src/docker/linux/files/fake_goma/goma_ctl.py b/src/docker/linux/files/fake_goma/goma_ctl.py deleted file mode 100755 index 2f2ceb9..0000000 --- a/src/docker/linux/files/fake_goma/goma_ctl.py +++ /dev/null
@@ -1,3 +0,0 @@ -#!/usr/bin/env python - -print("Faking Goma via ccache")
diff --git a/src/docker/linux/files/fake_goma/gomacc b/src/docker/linux/files/fake_goma/gomacc deleted file mode 100755 index d64f812..0000000 --- a/src/docker/linux/files/fake_goma/gomacc +++ /dev/null
@@ -1,2 +0,0 @@ -#!/bin/sh -ccache "$@"
diff --git a/src/docker/linux/linux-x64x11/Dockerfile b/src/docker/linux/linux-x64x11/Dockerfile index 524f320..29f7d8d 100644 --- a/src/docker/linux/linux-x64x11/Dockerfile +++ b/src/docker/linux/linux-x64x11/Dockerfile
@@ -1,4 +1,5 @@ -FROM cobalt-build-base +ARG FROM_IMAGE +FROM ${FROM_IMAGE:-cobalt-build-base} RUN apt update -qqy \ && apt install -qqy --no-install-recommends \
diff --git a/src/docker/linux/unittest/Dockerfile b/src/docker/linux/unittest/Dockerfile index 32a35a5..e876c8d 100644 --- a/src/docker/linux/unittest/Dockerfile +++ b/src/docker/linux/unittest/Dockerfile
@@ -7,7 +7,9 @@ libavformat57 \ libavresample3 \ libavutil55 \ + libegl1-mesa \ libgl1-mesa-dri \ + libgles2-mesa \ libx11-6 \ libxcomposite1 \ libxrender1 \ @@ -27,7 +29,7 @@ RUN mkdir -p /app_launcher_out -CMD unzip /out/app_launcher -d /app_launcher_out && \ +CMD unzip -q /out/app_launcher -d /app_launcher_out && \ xvfb-run --server-args="-screen 0 1920x1080x24 +render +extension GLX -noreset" \ python /app_launcher_out/starboard/tools/testing/test_runner.py --run \ - -o /out --platform $PLATFORM --config $CONFIG -t $TEST_TARGET + -o /out --platform $PLATFORM --config $CONFIG
diff --git a/src/net/dial/dial_system_config_starboard.cc b/src/net/dial/dial_system_config_starboard.cc index 316d889..7ec70d0 100644 --- a/src/net/dial/dial_system_config_starboard.cc +++ b/src/net/dial/dial_system_config_starboard.cc
@@ -14,8 +14,8 @@ #include "net/dial/dial_system_config.h" +#include "starboard/common/file.h" #include "starboard/configuration_constants.h" -#include "starboard/file.h" #include "starboard/system.h" namespace {
diff --git a/src/net/ssl/ssl_key_logger_impl.cc b/src/net/ssl/ssl_key_logger_impl.cc index 550d372..2bad355 100644 --- a/src/net/ssl/ssl_key_logger_impl.cc +++ b/src/net/ssl/ssl_key_logger_impl.cc
@@ -16,7 +16,10 @@ #include "base/sequenced_task_runner.h" #include "base/task/post_task.h" #include "base/task/task_traits.h" +#if defined(STARBOARD) +#include "starboard/common/file.h" #include "starboard/types.h" +#endif namespace net {
diff --git a/src/requirements.txt b/src/requirements.txt new file mode 100644 index 0000000..e9215ea --- /dev/null +++ b/src/requirements.txt
@@ -0,0 +1,4 @@ +cpplint==1.5.4 +pre-commit==2.6.0 +pylint==2.6.0 +yapf==0.30.0
diff --git a/src/starboard/CHANGELOG.md b/src/starboard/CHANGELOG.md index cdd706c..40aab86 100644 --- a/src/starboard/CHANGELOG.md +++ b/src/starboard/CHANGELOG.md
@@ -261,6 +261,23 @@ when those settings change. For older starboard versions, use kSbEventTypeAccessiblitySettingsChanged instead. +### Add extension to SbMediaCanPlayMimeAndKeySystem() for encryptionScheme. + +Now the Starboard implementation may choose to support |key_system| with extra +attributes, in order to selectively support encryption schemes on particular +containers or codecs. +The Starboard implementation needn't support |key_system| with extra attributes +if it meets the requirements for the default implementation of +`Navigator.requestMediaKeySystemAccess()`, which assumes that: +1. When the Widevine DRM system is used, all the encryption schemes ('cenc', + 'cbcs', 'cbcs-1-9') should be supported across all containers and codecs + supported by the platform. +2. When the PlayReady DRM system is used, only 'cenc' is supported across all + containers and codecs supported by the platform. + +Please see the comment of `SbMediaCanPlayMimeAndKeySystem()` in `media.h` for +more details. + ## Version 11 ### Add arguments to `SbMediaIsVideoSupported`.
diff --git a/src/starboard/android/apk/app/build.gradle b/src/starboard/android/apk/app/build.gradle index fdf3b29..5ab0feb 100644 --- a/src/starboard/android/apk/app/build.gradle +++ b/src/starboard/android/apk/app/build.gradle
@@ -66,7 +66,7 @@ defaultConfig { applicationId "dev.cobalt.coat" minSdkVersion 21 - targetSdkVersion 30 + targetSdkVersion 29 versionCode 1 versionName "${buildId}" manifestPlaceholders = [applicationName: "CoAT: ${cobaltTarget}"]
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 fe988bb..9cee635 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
@@ -30,7 +30,7 @@ import android.os.Build; import android.util.Size; import android.util.SizeF; -import android.view.Display; +import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.CaptioningManager; import androidx.annotation.RequiresApi; @@ -155,13 +155,17 @@ @SuppressWarnings("unused") @UsedByNative 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 - // can take their time suspending after that. - cobaltMediaSession.suspend(); - for (CobaltService service : cobaltServices.values()) { - service.beforeSuspend(); + try { + 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 + // can take their time suspending after that. + cobaltMediaSession.suspend(); + for (CobaltService service : cobaltServices.values()) { + service.beforeSuspend(); + } + } catch (Throwable e) { + Log.i(TAG, "Caught exception in beforeSuspend: " + e.getMessage()); } } @@ -521,12 +525,18 @@ return false; } - Display defaultDisplay = DisplayUtil.getDefaultDisplay(activityHolder.get()); - if (defaultDisplay == null) { + Activity activity = activityHolder.get(); + if (activity == null) { return false; } - int[] supportedHdrTypes = defaultDisplay.getHdrCapabilities().getSupportedHdrTypes(); + WindowManager windowManager = activity.getWindowManager(); + if (windowManager == null) { + return false; + } + + int[] supportedHdrTypes = + windowManager.getDefaultDisplay().getHdrCapabilities().getSupportedHdrTypes(); for (int supportedType : supportedHdrTypes) { if (supportedType == hdrType) { return true;
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 42c4e98..faa8742 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
@@ -69,7 +69,6 @@ private static final String KEY_CROP_TOP = "crop-top"; private static final int BITRATE_ADJUSTMENT_FPS = 30; - private static final int MAXIMUM_INITIAL_FPS = 30; private long mNativeMediaCodecBridge; private MediaCodec mMediaCodec; @@ -78,6 +77,8 @@ private long mLastPresentationTimeUs; private final String mMime; private boolean mAdaptivePlaybackSupported; + private double mPlaybackRate = 1.0; + private int mFps = 30; // Functions that require this will be called frequently in a tight loop. // Only create one of these and reuse it to avoid excessive allocations, @@ -104,6 +105,45 @@ public static final String VIDEO_AV1 = "video/av01"; } + private class FrameRateEstimator { + private static final int INVALID_FRAME_RATE = -1; + private static final long INVALID_FRAME_TIMESTAMP = -1; + private static final int MINIMUN_REQUIRED_FRAMES = 4; + private long mLastFrameTimestampUs = INVALID_FRAME_TIMESTAMP; + private long mNumberOfFrames = 0; + private long mTotalDurationUs = 0; + + public int getEstimatedFrameRate() { + if (mTotalDurationUs <= 0 || mNumberOfFrames < MINIMUN_REQUIRED_FRAMES) { + return INVALID_FRAME_RATE; + } + return Math.round((mNumberOfFrames - 1) * 1000000.0f / mTotalDurationUs); + } + + public void reset() { + mLastFrameTimestampUs = INVALID_FRAME_TIMESTAMP; + mNumberOfFrames = 0; + mTotalDurationUs = 0; + } + + public void onNewFrame(long presentationTimeUs) { + mNumberOfFrames++; + + if (mLastFrameTimestampUs == INVALID_FRAME_TIMESTAMP) { + mLastFrameTimestampUs = presentationTimeUs; + return; + } + if (presentationTimeUs <= mLastFrameTimestampUs) { + Log.v(TAG, String.format("Invalid output presentation timestamp.")); + return; + } + + mTotalDurationUs += presentationTimeUs - mLastFrameTimestampUs; + mLastFrameTimestampUs = presentationTimeUs; + } + } + + private FrameRateEstimator mFrameRateEstimator = null; private BitrateAdjustmentTypes mBitrateAdjustmentType = BitrateAdjustmentTypes.NO_ADJUSTMENT; @SuppressWarnings("unused") @@ -415,6 +455,14 @@ info.offset, info.presentationTimeUs, info.size); + if (mFrameRateEstimator != null) { + mFrameRateEstimator.onNewFrame(info.presentationTimeUs); + int fps = mFrameRateEstimator.getEstimatedFrameRate(); + if (fps != FrameRateEstimator.INVALID_FRAME_RATE && mFps != fps) { + mFps = fps; + updateOperatingRate(); + } + } } } @@ -599,6 +647,40 @@ @SuppressWarnings("unused") @UsedByNative + private void setPlaybackRate(double playbackRate) { + if (mPlaybackRate == playbackRate) { + return; + } + mPlaybackRate = playbackRate; + if (mFrameRateEstimator != null) { + updateOperatingRate(); + } + } + + private void updateOperatingRate() { + // We needn't set operation rate if playback rate is 0 or less. + if (Double.compare(mPlaybackRate, 0.0) <= 0) { + return; + } + if (mFps == FrameRateEstimator.INVALID_FRAME_RATE) { + return; + } + if (mFps <= 0) { + Log.e(TAG, "Failed to set operating rate with invalid fps " + mFps); + return; + } + double operatingRate = mPlaybackRate * mFps; + Bundle b = new Bundle(); + b.putFloat(MediaFormat.KEY_OPERATING_RATE, (float) operatingRate); + try { + mMediaCodec.setParameters(b); + } catch (IllegalStateException e) { + Log.e(TAG, "Failed to set MediaCodec operating rate", e); + } + } + + @SuppressWarnings("unused") + @UsedByNative private int flush() { try { mFlushed = true; @@ -830,17 +912,23 @@ if (mAdaptivePlaybackSupported) { // Since we haven't passed the properties of the stream we're playing // down to this level, from our perspective, we could potentially - // adapt up to 8k at any point. We thus request 8k buffers up front, + // adapt up to 8k at any point. We thus request 8k buffers up front, // unless the decoder claims to not be able to do 8k, in which case // we're ok, since we would've rejected a 8k stream when canPlayType // was called, and then use those decoder values instead. - int maxWidth = Math.min(7680, maxSupportedWidth); - int maxHeight = Math.min(4320, maxSupportedHeight); - format.setInteger(MediaFormat.KEY_MAX_WIDTH, maxWidth); - format.setInteger(MediaFormat.KEY_MAX_HEIGHT, maxHeight); + if (Build.VERSION.SDK_INT > 22) { + format.setInteger(MediaFormat.KEY_MAX_WIDTH, Math.min(7680, maxSupportedWidth)); + format.setInteger(MediaFormat.KEY_MAX_HEIGHT, Math.min(4320, maxSupportedHeight)); + } else { + // Android 5.0/5.1 seems not support 8K. Fallback to 4K until we get a + // better way to get maximum supported resolution. + format.setInteger(MediaFormat.KEY_MAX_WIDTH, Math.min(3840, maxSupportedWidth)); + format.setInteger(MediaFormat.KEY_MAX_HEIGHT, Math.min(2160, maxSupportedHeight)); + } } maybeSetMaxInputSize(format); mMediaCodec.configure(format, surface, crypto, flags); + mFrameRateEstimator = new FrameRateEstimator(); return true; } catch (IllegalArgumentException e) { Log.e(TAG, "Cannot configure the video codec with IllegalArgumentException: ", e);
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 1e39d63..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
@@ -35,9 +35,8 @@ import android.os.Message; import android.view.Choreographer; import android.view.Choreographer.FrameCallback; -import android.view.Display; +import android.view.WindowManager; import androidx.annotation.RequiresApi; -import dev.cobalt.util.DisplayUtil; import dev.cobalt.util.UsedByNative; /** Makes a best effort to adjust frame release timestamps for a smoother visual result. */ @@ -222,9 +221,9 @@ } private static double getDefaultDisplayRefreshRate(Context context) { - Display defaultDisplay = DisplayUtil.getDefaultDisplay(context); - return defaultDisplay != null - ? defaultDisplay.getRefreshRate() + WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + return manager.getDefaultDisplay() != null + ? manager.getDefaultDisplay().getRefreshRate() : DISPLAY_REFRESH_RATE_UNKNOWN; }
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/DisplayUtil.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/DisplayUtil.java index c7c2208..4b23394 100644 --- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/DisplayUtil.java +++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/DisplayUtil.java
@@ -15,14 +15,10 @@ package dev.cobalt.util; import android.content.Context; -import android.content.res.Resources; import android.util.DisplayMetrics; import android.util.Size; import android.util.SizeF; -import android.view.Display; import android.view.WindowManager; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; /** Utility functions for querying display attributes. */ public class DisplayUtil { @@ -30,34 +26,6 @@ private DisplayUtil() {} /** - * Returns the default display associated with a context. - */ - @Nullable - public static Display getDefaultDisplay(Context context) { - if (context == null) { - return null; - } - if (android.os.Build.VERSION.SDK_INT >= 30) { - return getDefaultDisplayV30(context); - } else { - return getDefaultDisplayDeprecated(context); - } - } - - @Nullable - @SuppressWarnings("deprecation") - private static Display getDefaultDisplayDeprecated(Context context) { - WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - return (wm == null) ? null : wm.getDefaultDisplay(); - } - - @Nullable - @RequiresApi(30) - private static Display getDefaultDisplayV30(Context context) { - return context.getDisplay(); - } - - /** * Returns the physical pixels per inch of the screen in the X and Y * dimensions. */ @@ -114,10 +82,10 @@ private static DisplayMetrics cachedDisplayMetrics = null; private static DisplayMetrics getDisplayMetrics(Context context) { - Resources.getSystem().getDisplayMetrics(); if (cachedDisplayMetrics == null) { cachedDisplayMetrics = new DisplayMetrics(); - getDefaultDisplay(context).getRealMetrics(cachedDisplayMetrics); + ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay().getRealMetrics(cachedDisplayMetrics); } return cachedDisplayMetrics; }
diff --git a/src/starboard/android/apk/build.id b/src/starboard/android/apk/build.id new file mode 100644 index 0000000..a485246 --- /dev/null +++ b/src/starboard/android/apk/build.id
@@ -0,0 +1 @@ +282262 \ No newline at end of file
diff --git a/src/starboard/android/shared/android_main.cc b/src/starboard/android/shared/android_main.cc index 1f6513d..a44497e 100644 --- a/src/starboard/android/shared/android_main.cc +++ b/src/starboard/android/shared/android_main.cc
@@ -67,6 +67,7 @@ if (j_url) { start_url = env->GetStringStandardUTFOrAbort(j_url.Get()); } + SB_LOG(INFO) << "GetStartDeepLink: " << start_url; return start_url; }
diff --git a/src/starboard/android/shared/android_media_session_client.cc b/src/starboard/android/shared/android_media_session_client.cc new file mode 100644 index 0000000..b822ec1 --- /dev/null +++ b/src/starboard/android/shared/android_media_session_client.cc
@@ -0,0 +1,297 @@ +// Copyright 2017 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/android/shared/android_media_session_client.h" + +#include "base/time/time.h" +#include "starboard/android/shared/jni_env_ext.h" +#include "starboard/android/shared/jni_utils.h" +#include "starboard/common/log.h" +#include "starboard/common/mutex.h" +#include "starboard/once.h" + +namespace starboard { +namespace android { +namespace shared { + +using ::starboard::android::shared::JniEnvExt; +using ::starboard::android::shared::ScopedLocalJavaRef; + +// These constants are from android.media.session.PlaybackState +const jlong kPlaybackStateActionStop = 1 << 0; +const jlong kPlaybackStateActionPause = 1 << 1; +const jlong kPlaybackStateActionPlay = 1 << 2; +const jlong kPlaybackStateActionRewind = 1 << 3; +const jlong kPlaybackStateActionSkipToPrevious = 1 << 4; +const jlong kPlaybackStateActionSkipToNext = 1 << 5; +const jlong kPlaybackStateActionFastForward = 1 << 6; +const jlong kPlaybackStateActionSetRating = 1 << 7; // not supported +const jlong kPlaybackStateActionSeekTo = 1 << 8; + +// Converts a MediaSessionClient::AvailableActions bitset into +// a android.media.session.PlaybackState jlong bitset. +jlong MediaSessionActionsToPlaybackStateActions(const bool* actions) { + jlong result = 0; + if (actions[kCobaltExtensionMediaSessionActionPause]) { + result |= kPlaybackStateActionPause; + } + if (actions[kCobaltExtensionMediaSessionActionPlay]) { + result |= kPlaybackStateActionPlay; + } + if (actions[kCobaltExtensionMediaSessionActionSeekbackward]) { + result |= kPlaybackStateActionRewind; + } + if (actions[kCobaltExtensionMediaSessionActionPrevioustrack]) { + result |= kPlaybackStateActionSkipToPrevious; + } + if (actions[kCobaltExtensionMediaSessionActionNexttrack]) { + result |= kPlaybackStateActionSkipToNext; + } + if (actions[kCobaltExtensionMediaSessionActionSeekforward]) { + result |= kPlaybackStateActionFastForward; + } + if (actions[kCobaltExtensionMediaSessionActionSeekto]) { + result |= kPlaybackStateActionSeekTo; + } + if (actions[kCobaltExtensionMediaSessionActionStop]) { + result |= kPlaybackStateActionStop; + } + return result; +} + +PlaybackState CobaltExtensionPlaybackStateToPlaybackState( + CobaltExtensionMediaSessionPlaybackState in_state) { + switch (in_state) { + case kCobaltExtensionMediaSessionPlaying: + return kPlaying; + case kCobaltExtensionMediaSessionPaused: + return kPaused; + case kCobaltExtensionMediaSessionNone: + return kNone; + } +} + +CobaltExtensionMediaSessionAction PlaybackStateActionToMediaSessionAction( + jlong action) { + CobaltExtensionMediaSessionAction result; + switch (action) { + case kPlaybackStateActionPause: + result = kCobaltExtensionMediaSessionActionPause; + break; + case kPlaybackStateActionPlay: + result = kCobaltExtensionMediaSessionActionPlay; + break; + case kPlaybackStateActionRewind: + result = kCobaltExtensionMediaSessionActionSeekbackward; + break; + case kPlaybackStateActionSkipToPrevious: + result = kCobaltExtensionMediaSessionActionPrevioustrack; + break; + case kPlaybackStateActionSkipToNext: + result = kCobaltExtensionMediaSessionActionNexttrack; + break; + case kPlaybackStateActionFastForward: + result = kCobaltExtensionMediaSessionActionSeekforward; + break; + case kPlaybackStateActionSeekTo: + result = kCobaltExtensionMediaSessionActionSeekto; + break; + case kPlaybackStateActionStop: + result = kCobaltExtensionMediaSessionActionStop; + break; + default: + SB_NOTREACHED() << "Unsupported MediaSessionAction 0x" << std::hex + << action; + result = static_cast<CobaltExtensionMediaSessionAction>(-1); + } + return result; +} + +CobaltExtensionMediaSessionPlaybackState +PlaybackStateToCobaltExtensionPlaybackState(PlaybackState state) { + CobaltExtensionMediaSessionPlaybackState result; + switch (state) { + case kPlaying: + result = kCobaltExtensionMediaSessionPlaying; + break; + case kPaused: + result = kCobaltExtensionMediaSessionPaused; + break; + case kNone: + result = kCobaltExtensionMediaSessionNone; + break; + default: + SB_NOTREACHED() << "Unsupported PlaybackState " << state; + result = static_cast<CobaltExtensionMediaSessionPlaybackState>(-1); + } + return result; +} + +SbOnceControl once_flag = SB_ONCE_INITIALIZER; +SbMutex mutex; + +// Callbacks to the last MediaSessionClient to become active, or null. +// Used to route Java callbacks. +// In practice, only one MediaSessionClient will become active at a time. +// Protected by "mutex" +CobaltExtensionMediaSessionUpdatePlatformPlaybackStateCallback + update_platform_playback_state_callback; +CobaltExtensionMediaSessionInvokeActionCallback invoke_action_callback; +void* callback_context; + +void OnceInit() { + SbMutexCreate(&mutex); +} + +void NativeInvokeAction(jlong action, jlong seek_ms) { + SbOnce(&once_flag, OnceInit); + SbMutexAcquire(&mutex); + + if (invoke_action_callback != NULL && callback_context != NULL) { + CobaltExtensionMediaSessionActionDetails details = {}; + CobaltExtensionMediaSessionActionDetailsInit( + &details, PlaybackStateActionToMediaSessionAction(action)); + // CobaltMediaSession.java only sets seek_ms for SeekTo (not ff/rew). + if (details.action == kCobaltExtensionMediaSessionActionSeekto) { + details.seek_time = seek_ms / 1000.0; + } + invoke_action_callback(details, callback_context); + } + + SbMutexRelease(&mutex); +} + +void UpdateActiveSessionPlatformPlaybackState(PlaybackState state) { + SbOnce(&once_flag, OnceInit); + SbMutexAcquire(&mutex); + + CobaltExtensionMediaSessionPlaybackState media_session_state = + PlaybackStateToCobaltExtensionPlaybackState(state); + + if (update_platform_playback_state_callback != NULL && + callback_context != NULL) { + update_platform_playback_state_callback(media_session_state, + callback_context); + } + + SbMutexRelease(&mutex); +} + +void OnMediaSessionStateChanged( + const CobaltExtensionMediaSessionState session_state) { + JniEnvExt* env = JniEnvExt::Get(); + + jint playback_state = CobaltExtensionPlaybackStateToPlaybackState( + session_state.actual_playback_state); + void* media_session_client = session_state.callback_context; + + SbOnce(&once_flag, OnceInit); + SbMutexAcquire(&mutex); + if (playback_state != kNone) { + callback_context = media_session_client; + update_platform_playback_state_callback = + session_state.update_platform_playback_state_callback; + invoke_action_callback = session_state.invoke_action_callback; + } else if (callback_context == media_session_client) { + callback_context = NULL; + } + SbMutexRelease(&mutex); + + jlong playback_state_actions = MediaSessionActionsToPlaybackStateActions( + session_state.available_actions); + + ScopedLocalJavaRef<jstring> j_title; + ScopedLocalJavaRef<jstring> j_artist; + ScopedLocalJavaRef<jstring> j_album; + ScopedLocalJavaRef<jobjectArray> j_artwork; + + if (session_state.metadata != NULL) { + CobaltExtensionMediaMetadata* media_metadata(session_state.metadata); + + j_title.Reset(env->NewStringStandardUTFOrAbort(media_metadata->title)); + j_artist.Reset(env->NewStringStandardUTFOrAbort(media_metadata->artist)); + j_album.Reset(env->NewStringStandardUTFOrAbort(media_metadata->album)); + + size_t artwork_count = media_metadata->artwork_count; + if (artwork_count > 0) { + CobaltExtensionMediaImage* artwork(media_metadata->artwork); + ScopedLocalJavaRef<jclass> media_image_class( + env->FindClassExtOrAbort("dev/cobalt/media/MediaImage")); + jmethodID media_image_constructor = env->GetMethodID( + media_image_class.Get(), "<init>", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + env->AbortOnException(); + + j_artwork.Reset(static_cast<jobjectArray>( + env->NewObjectArray(artwork_count, media_image_class.Get(), NULL))); + env->AbortOnException(); + + ScopedLocalJavaRef<jstring> j_src; + ScopedLocalJavaRef<jstring> j_sizes; + ScopedLocalJavaRef<jstring> j_type; + for (size_t i = 0; i < artwork_count; i++) { + const CobaltExtensionMediaImage& media_image(artwork[i]); + j_src.Reset(env->NewStringStandardUTFOrAbort(media_image.src)); + j_sizes.Reset(env->NewStringStandardUTFOrAbort(media_image.size)); + j_type.Reset(env->NewStringStandardUTFOrAbort(media_image.type)); + + ScopedLocalJavaRef<jobject> j_media_image( + env->NewObject(media_image_class.Get(), media_image_constructor, + j_src.Get(), j_sizes.Get(), j_type.Get())); + + env->SetObjectArrayElement(j_artwork.Get(), i, j_media_image.Get()); + } + } + } + + 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( + "updateMediaSession", + "(IJJFLjava/lang/String;Ljava/lang/String;Ljava/lang/String;" + "[Ldev/cobalt/media/MediaImage;J)V", + playback_state, playback_state_actions, + 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(), durationInMilliseconds); +} + +const CobaltExtensionMediaSessionApi kMediaSessionApi = { + kCobaltExtensionMediaSessionName, 1, &OnMediaSessionStateChanged}; + +const void* GetMediaSessionApi() { + return &kMediaSessionApi; +} + +} // namespace shared +} // namespace android +} // namespace starboard + +extern "C" SB_EXPORT_PLATFORM void +Java_dev_cobalt_media_CobaltMediaSession_nativeInvokeAction(JNIEnv* env, + jclass unused_clazz, + jlong action, + jlong seek_ms) { + starboard::android::shared::NativeInvokeAction(action, seek_ms); +}
diff --git a/src/starboard/android/shared/cobalt/android_media_session_client.h b/src/starboard/android/shared/android_media_session_client.h similarity index 86% rename from src/starboard/android/shared/cobalt/android_media_session_client.h rename to src/starboard/android/shared/android_media_session_client.h index 5fc3f41..83fd0cc 100644 --- a/src/starboard/android/shared/cobalt/android_media_session_client.h +++ b/src/starboard/android/shared/android_media_session_client.h
@@ -15,17 +15,21 @@ #ifndef STARBOARD_ANDROID_SHARED_COBALT_ANDROID_MEDIA_SESSION_CLIENT_H_ #define STARBOARD_ANDROID_SHARED_COBALT_ANDROID_MEDIA_SESSION_CLIENT_H_ +#include "cobalt/extension/media_session.h" + namespace starboard { namespace android { namespace shared { -namespace cobalt { // Duplicated in CobaltMediaSession.java enum PlaybackState { kPlaying = 0, kPaused = 1, kNone = 2 }; void UpdateActiveSessionPlatformPlaybackState(PlaybackState state); -} // namespace cobalt +void OnMediaSessionStateChanged( + const CobaltExtensionMediaSessionState session_state); + +const void* GetMediaSessionApi(); } // namespace shared } // namespace android } // namespace starboard
diff --git a/src/starboard/android/shared/application_android.cc b/src/starboard/android/shared/application_android.cc index e8fab42..1352a26 100644 --- a/src/starboard/android/shared/application_android.cc +++ b/src/starboard/android/shared/application_android.cc
@@ -69,6 +69,8 @@ return "WindowFocusGained"; case ApplicationAndroid::AndroidCommand::kWindowFocusLost: return "WindowFocusLost"; + case ApplicationAndroid::AndroidCommand::kDeepLink: + return "DeepLink"; default: return "unknown"; } @@ -298,6 +300,21 @@ case AndroidCommand::kStop: sync_state = activity_state_ = cmd.type; break; + case AndroidCommand::kDeepLink: + char* deep_link = static_cast<char*>(cmd.data); + SB_LOG(INFO) << "AndroidCommand::kDeepLink: deep_link=" << deep_link + << " state=" << state(); + if (deep_link != NULL) { + if (state() == kStateUnstarted) { + SetStartLink(deep_link); + SB_LOG(INFO) << "ApplicationAndroid SetStartLink"; + SbMemoryDeallocate(static_cast<void*>(deep_link)); + } else { + SB_LOG(INFO) << "ApplicationAndroid Inject: kSbEventTypeLink"; + Inject(new Event(kSbEventTypeLink, deep_link, SbMemoryDeallocate)); + } + } + break; } // If there's a window, sync the app state to the Activity lifecycle, letting @@ -337,7 +354,7 @@ // Android main thread. This lets the MediaSession get released now without // having to wait to bounce between threads. JniEnvExt* env = JniEnvExt::Get(); - env->CallStarboardVoidMethodOrAbort("beforeSuspend", "()V"); + env->CallStarboardVoidMethod("beforeSuspend", "()V"); } AndroidCommand cmd {type, data}; ScopedLock lock(android_command_mutex_); @@ -538,12 +555,14 @@ } void ApplicationAndroid::HandleDeepLink(const char* link_url) { + SB_LOG(INFO) << "ApplicationAndroid::HandleDeepLink link_url=" << link_url; if (link_url == NULL || link_url[0] == '\0') { return; } char* deep_link = SbStringDuplicate(link_url); SB_DCHECK(deep_link); - Inject(new Event(kSbEventTypeLink, deep_link, SbMemoryDeallocate)); + + SendAndroidCommand(AndroidCommand::kDeepLink, deep_link); } extern "C" SB_EXPORT_PLATFORM
diff --git a/src/starboard/android/shared/application_android.h b/src/starboard/android/shared/application_android.h index 3ad4820..6dad099 100644 --- a/src/starboard/android/shared/application_android.h +++ b/src/starboard/android/shared/application_android.h
@@ -51,6 +51,7 @@ kNativeWindowDestroyed, kWindowFocusGained, kWindowFocusLost, + kDeepLink, } CommandType; CommandType type;
diff --git a/src/starboard/android/shared/audio_track_audio_sink_type.h b/src/starboard/android/shared/audio_track_audio_sink_type.h index 1a8cb37..43b0c86 100644 --- a/src/starboard/android/shared/audio_track_audio_sink_type.h +++ b/src/starboard/android/shared/audio_track_audio_sink_type.h
@@ -74,10 +74,10 @@ SbMediaAudioSampleType sample_type, int sampling_frequency_hz); - MinRequiredFramesTester min_required_frames_tester_; Mutex min_required_frames_map_mutex_; // The minimum frames required to avoid underruns of different frequencies. std::map<int, int> min_required_frames_map_; + MinRequiredFramesTester min_required_frames_tester_; }; class AudioTrackAudioSink : public SbAudioSinkPrivate {
diff --git a/src/starboard/android/shared/cobalt/android_media_session_client.cc b/src/starboard/android/shared/cobalt/android_media_session_client.cc deleted file mode 100644 index 30ec630..0000000 --- a/src/starboard/android/shared/cobalt/android_media_session_client.cc +++ /dev/null
@@ -1,353 +0,0 @@ -// Copyright 2017 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/android/shared/cobalt/android_media_session_client.h" - -#include "base/time/time.h" -#include "cobalt/media_session/media_session_action_details.h" -#include "cobalt/media_session/media_session_client.h" -#include "cobalt/script/sequence.h" -#include "starboard/android/shared/jni_env_ext.h" -#include "starboard/android/shared/jni_utils.h" -#include "starboard/common/log.h" -#include "starboard/common/mutex.h" -#include "starboard/once.h" - -namespace starboard { -namespace android { -namespace shared { -namespace cobalt { - -using ::cobalt::media_session::MediaImage; -using ::cobalt::media_session::MediaMetadataInit; -using ::cobalt::media_session::MediaSession; -using ::cobalt::media_session::MediaSessionAction; -using ::cobalt::media_session::MediaSessionActionDetails; -using ::cobalt::media_session::MediaSessionClient; -using ::cobalt::media_session::MediaSessionPlaybackState; -using ::cobalt::media_session::MediaSessionState; -using ::cobalt::media_session::kMediaSessionActionPause; -using ::cobalt::media_session::kMediaSessionActionPlay; -using ::cobalt::media_session::kMediaSessionActionSeekto; -using ::cobalt::media_session::kMediaSessionActionSeekbackward; -using ::cobalt::media_session::kMediaSessionActionSeekforward; -using ::cobalt::media_session::kMediaSessionActionStop; -using ::cobalt::media_session::kMediaSessionActionPrevioustrack; -using ::cobalt::media_session::kMediaSessionActionNexttrack; -using ::cobalt::media_session::kMediaSessionPlaybackStateNone; -using ::cobalt::media_session::kMediaSessionPlaybackStatePaused; -using ::cobalt::media_session::kMediaSessionPlaybackStatePlaying; - -using MediaImageSequence = ::cobalt::script::Sequence<MediaImage>; - -using ::starboard::android::shared::JniEnvExt; -using ::starboard::android::shared::ScopedLocalJavaRef; - -namespace { - -// These constants are from android.media.session.PlaybackState -const jlong kPlaybackStateActionStop = 1 << 0; -const jlong kPlaybackStateActionPause = 1 << 1; -const jlong kPlaybackStateActionPlay = 1 << 2; -const jlong kPlaybackStateActionRewind = 1 << 3; -const jlong kPlaybackStateActionSkipToPrevious = 1 << 4; -const jlong kPlaybackStateActionSkipToNext = 1 << 5; -const jlong kPlaybackStateActionFastForward = 1 << 6; -const jlong kPlaybackStateActionSetRating = 1 << 7; // not supported -const jlong kPlaybackStateActionSeekTo = 1 << 8; - -// Converts a MediaSessionClient::AvailableActions bitset into -// a android.media.session.PlaybackState jlong bitset. -jlong MediaSessionActionsToPlaybackStateActions( - const MediaSessionState::AvailableActionsSet& actions) { - jlong result = 0; - if (actions[kMediaSessionActionPause]) { - result |= kPlaybackStateActionPause; - } - if (actions[kMediaSessionActionPlay]) { - result |= kPlaybackStateActionPlay; - } - if (actions[kMediaSessionActionSeekbackward]) { - result |= kPlaybackStateActionRewind; - } - if (actions[kMediaSessionActionPrevioustrack]) { - result |= kPlaybackStateActionSkipToPrevious; - } - if (actions[kMediaSessionActionNexttrack]) { - result |= kPlaybackStateActionSkipToNext; - } - if (actions[kMediaSessionActionSeekforward]) { - result |= kPlaybackStateActionFastForward; - } - if (actions[kMediaSessionActionSeekto]) { - result |= kPlaybackStateActionSeekTo; - } - if (actions[kMediaSessionActionStop]) { - result |= kPlaybackStateActionStop; - } - return result; -} - -PlaybackState MediaSessionPlaybackStateToPlaybackState( - MediaSessionPlaybackState in_state) { - switch (in_state) { - case kMediaSessionPlaybackStatePlaying: - return kPlaying; - case kMediaSessionPlaybackStatePaused: - return kPaused; - case kMediaSessionPlaybackStateNone: - return kNone; - } -} - -MediaSessionAction PlaybackStateActionToMediaSessionAction(jlong action) { - MediaSessionAction result; - switch (action) { - case kPlaybackStateActionPause: - result = kMediaSessionActionPause; - break; - case kPlaybackStateActionPlay: - result = kMediaSessionActionPlay; - break; - case kPlaybackStateActionRewind: - result = kMediaSessionActionSeekbackward; - break; - case kPlaybackStateActionSkipToPrevious: - result = kMediaSessionActionPrevioustrack; - break; - case kPlaybackStateActionSkipToNext: - result = kMediaSessionActionNexttrack; - break; - case kPlaybackStateActionFastForward: - result = kMediaSessionActionSeekforward; - break; - case kPlaybackStateActionSeekTo: - result = kMediaSessionActionSeekto; - break; - case kPlaybackStateActionStop: - result = kMediaSessionActionStop; - break; - default: - SB_NOTREACHED() << "Unsupported MediaSessionAction 0x" - << std::hex << action; - result = static_cast<MediaSessionAction>(-1); - } - return result; -} - -MediaSessionPlaybackState PlaybackStateToMediaSessionPlaybackState( - PlaybackState state) { - MediaSessionPlaybackState result; - switch (state) { - case kPlaying: - result = kMediaSessionPlaybackStatePlaying; - break; - case kPaused: - result = kMediaSessionPlaybackStatePaused; - break; - case kNone: - result = kMediaSessionPlaybackStateNone; - break; - default: - SB_NOTREACHED() << "Unsupported PlaybackState " << state; - result = static_cast<MediaSessionPlaybackState>(-1); - } - return result; -} - -} // namespace - -class AndroidMediaSessionClient : public MediaSessionClient { - static SbOnceControl once_flag; - static SbMutex mutex; - // The last MediaSessionClient to become active, or null. - // Used to route Java callbacks. - // In practice, only one MediaSessionClient will become active at a time. - // Protected by "mutex" - static AndroidMediaSessionClient* active_client; - - static void OnceInit() { SbMutexCreate(&mutex); } - - public: - static void NativeInvokeAction(jlong action, jlong seek_ms) { - SbOnce(&once_flag, OnceInit); - SbMutexAcquire(&mutex); - - if (active_client != NULL) { - std::unique_ptr<MediaSessionActionDetails> details( - new MediaSessionActionDetails()); - details->set_action(PlaybackStateActionToMediaSessionAction(action)); - // CobaltMediaSession.java only sets seek_ms for SeekTo (not ff/rew). - if (details->action() == kMediaSessionActionSeekto) { - details->set_seek_time(seek_ms / 1000.0); - } - active_client->InvokeAction(std::move(details)); - } - - SbMutexRelease(&mutex); - } - - static void UpdateActiveSessionPlatformPlaybackState( - MediaSessionPlaybackState state) { - SbOnce(&once_flag, OnceInit); - SbMutexAcquire(&mutex); - - if (active_client != NULL) { - active_client->UpdatePlatformPlaybackState(state); - } - - SbMutexRelease(&mutex); - } - - AndroidMediaSessionClient() {} - - virtual ~AndroidMediaSessionClient() { - SbOnce(&once_flag, OnceInit); - SbMutexAcquire(&mutex); - if (active_client == this) { - active_client = NULL; - } - SbMutexRelease(&mutex); - } - - void OnMediaSessionStateChanged( - const MediaSessionState& session_state) override { - JniEnvExt* env = JniEnvExt::Get(); - - jint playback_state = MediaSessionPlaybackStateToPlaybackState( - session_state.actual_playback_state()); - - SbOnce(&once_flag, OnceInit); - SbMutexAcquire(&mutex); - if (playback_state != kNone) { - active_client = this; - } else if (active_client == this) { - active_client = NULL; - } - SbMutexRelease(&mutex); - - jlong playback_state_actions = MediaSessionActionsToPlaybackStateActions( - session_state.available_actions()); - - ScopedLocalJavaRef<jstring> j_title; - ScopedLocalJavaRef<jstring> j_artist; - ScopedLocalJavaRef<jstring> j_album; - ScopedLocalJavaRef<jobjectArray> j_artwork; - - if (session_state.has_metadata()) { - const MediaMetadataInit& media_metadata(session_state.metadata().value()); - - j_title.Reset( - env->NewStringStandardUTFOrAbort(media_metadata.title().c_str())); - j_artist.Reset( - env->NewStringStandardUTFOrAbort(media_metadata.artist().c_str())); - j_album.Reset( - env->NewStringStandardUTFOrAbort(media_metadata.album().c_str())); - - if (media_metadata.has_artwork()) { - const MediaImageSequence& artwork(media_metadata.artwork()); - ScopedLocalJavaRef<jclass> media_image_class( - env->FindClassExtOrAbort("dev/cobalt/media/MediaImage")); - jmethodID media_image_constructor = env->GetMethodID( - media_image_class.Get(), "<init>", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - env->AbortOnException(); - - j_artwork.Reset(static_cast<jobjectArray>(env->NewObjectArray( - artwork.size(), media_image_class.Get(), NULL))); - env->AbortOnException(); - - ScopedLocalJavaRef<jstring> j_src; - ScopedLocalJavaRef<jstring> j_sizes; - ScopedLocalJavaRef<jstring> j_type; - for (MediaImageSequence::size_type i = 0; i < artwork.size(); i++) { - const MediaImage& media_image(artwork.at(i)); - j_src.Reset( - env->NewStringStandardUTFOrAbort(media_image.src().c_str())); - j_sizes.Reset( - env->NewStringStandardUTFOrAbort(media_image.sizes().c_str())); - j_type.Reset( - env->NewStringStandardUTFOrAbort(media_image.type().c_str())); - - ScopedLocalJavaRef<jobject> j_media_image( - env->NewObject(media_image_class.Get(), media_image_constructor, - j_src.Get(), j_sizes.Get(), j_type.Get())); - - env->SetObjectArrayElement(j_artwork.Get(), i, j_media_image.Get()); - } - } - } - - 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( - "updateMediaSession", - "(IJJFLjava/lang/String;Ljava/lang/String;Ljava/lang/String;" - "[Ldev/cobalt/media/MediaImage;J)V", - playback_state, playback_state_actions, - 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(), - durationInMilliseconds); - } -}; - -SbOnceControl AndroidMediaSessionClient::once_flag = SB_ONCE_INITIALIZER; -SbMutex AndroidMediaSessionClient::mutex; -AndroidMediaSessionClient* AndroidMediaSessionClient::active_client = NULL; - -void UpdateActiveSessionPlatformPlaybackState(PlaybackState state) { - MediaSessionPlaybackState media_session_state = - PlaybackStateToMediaSessionPlaybackState(state); - - AndroidMediaSessionClient::UpdateActiveSessionPlatformPlaybackState( - media_session_state); -} - -} // namespace cobalt -} // namespace shared -} // namespace android -} // namespace starboard - -using starboard::android::shared::cobalt::AndroidMediaSessionClient; - -extern "C" SB_EXPORT_PLATFORM -void Java_dev_cobalt_media_CobaltMediaSession_nativeInvokeAction( - JNIEnv* env, - jclass unused_clazz, - jlong action, - jlong seek_ms) { - AndroidMediaSessionClient::NativeInvokeAction(action, seek_ms); -} - -namespace cobalt { -namespace media_session { - -// static -std::unique_ptr<MediaSessionClient> MediaSessionClient::Create() { - return std::unique_ptr<MediaSessionClient>(new AndroidMediaSessionClient()); -} - -} // namespace media_session -} // namespace cobalt
diff --git a/src/starboard/android/shared/cobalt/cobalt_platform.gyp b/src/starboard/android/shared/cobalt/cobalt_platform.gyp index 6f6379a..2d4ba5b 100644 --- a/src/starboard/android/shared/cobalt/cobalt_platform.gyp +++ b/src/starboard/android/shared/cobalt/cobalt_platform.gyp
@@ -20,11 +20,10 @@ 'sources': [ 'android_user_authorizer.h', 'android_user_authorizer.cc', - 'android_media_session_client.cc', ], 'dependencies': [ - '<(DEPTH)/cobalt/media_session/media_session.gyp:media_session' + '<(DEPTH)/cobalt/base/base.gyp:base', ], - }, + } ], }
diff --git a/src/starboard/android/shared/cobalt/configuration.gypi b/src/starboard/android/shared/cobalt/configuration.gypi index c374599..c9cdba0 100644 --- a/src/starboard/android/shared/cobalt/configuration.gypi +++ b/src/starboard/android/shared/cobalt/configuration.gypi
@@ -18,7 +18,6 @@ 'variables': { 'in_app_dial': 0, - 'custom_media_session_client': 1, 'enable_account_manager': 1, # The 'android_system' font package installs only minimal fonts, with a
diff --git a/src/starboard/android/shared/cobalt/configuration.py b/src/starboard/android/shared/cobalt/configuration.py index 96c11fe..f9cf7d7 100644 --- a/src/starboard/android/shared/cobalt/configuration.py +++ b/src/starboard/android/shared/cobalt/configuration.py
@@ -66,6 +66,11 @@ # A map of failing or crashing tests per target. __FILTERED_TESTS = { + 'layout_tests': [ + # Android relies of system fonts and some older Android builds do not + # have the update (Emoji 11.0) NotoColorEmoji.ttf installed. + 'CSS3FontsLayoutTests/Layout.Test/color_emojis_should_render_properly' + ], 'renderer_test': [ # Instead of returning an error when allocating too much texture # memory, Android instead just terminates the process. Since this
diff --git a/src/starboard/android/shared/gyp_configuration.py b/src/starboard/android/shared/gyp_configuration.py index f0eba6e..04d5372 100644 --- a/src/starboard/android/shared/gyp_configuration.py +++ b/src/starboard/android/shared/gyp_configuration.py
@@ -327,6 +327,18 @@ 'SbDirectoryGetNextTest.SunnyDayStaticContent', 'SbDirectoryOpenTest.SunnyDayStaticContent', 'SbFileGetPathInfoTest.WorksOnStaticContentDirectories', + # Android doesn't currently support specifying a bitrate under 8000 + 'SbMediaCanPlayMimeAndKeySystem.MinimumSupport', + # There are issues with playback of heeac format files where the input + # |frames_per_channel| is 6912, instead of 12544 (as with other + # formats). + 'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.NoInput/6', + # These tests are disabled due to not receiving the kEndOfStream + # player state update within the specified timeout. + 'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.NoInput/7', + 'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.NoInput/8', + 'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.NoInput/9', + 'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.NoInput/10', ], }
diff --git a/src/starboard/android/shared/media_codec_bridge.cc b/src/starboard/android/shared/media_codec_bridge.cc index b39a61d..f78c347 100644 --- a/src/starboard/android/shared/media_codec_bridge.cc +++ b/src/starboard/android/shared/media_codec_bridge.cc
@@ -344,6 +344,11 @@ render_timestamp_ns); } +void MediaCodecBridge::SetPlaybackRate(double playback_rate) { + JniEnvExt::Get()->CallVoidMethodOrAbort( + j_media_codec_bridge_, "setPlaybackRate", "(D)V", playback_rate); +} + jint MediaCodecBridge::Flush() { return JniEnvExt::Get()->CallIntMethodOrAbort(j_media_codec_bridge_, "flush", "()I");
diff --git a/src/starboard/android/shared/media_codec_bridge.h b/src/starboard/android/shared/media_codec_bridge.h index 1fc6618..77452c1 100644 --- a/src/starboard/android/shared/media_codec_bridge.h +++ b/src/starboard/android/shared/media_codec_bridge.h
@@ -131,6 +131,7 @@ void ReleaseOutputBuffer(jint index, jboolean render); void ReleaseOutputBufferAtTimestamp(jint index, jlong render_timestamp_ns); + void SetPlaybackRate(double playback_rate); jint Flush(); SurfaceDimensions GetOutputDimensions(); AudioOutputFormatResult GetAudioOutputFormat();
diff --git a/src/starboard/android/shared/media_decoder.cc b/src/starboard/android/shared/media_decoder.cc index d5668d0..fc5fa0d 100644 --- a/src/starboard/android/shared/media_decoder.cc +++ b/src/starboard/android/shared/media_decoder.cc
@@ -177,6 +177,12 @@ } } +void MediaDecoder::SetPlaybackRate(double playback_rate) { + SB_DCHECK(media_type_ == kSbMediaTypeVideo); + SB_DCHECK(media_codec_bridge_); + media_codec_bridge_->SetPlaybackRate(playback_rate); +} + // static void* MediaDecoder::DecoderThreadEntryPoint(void* context) { SB_DCHECK(context);
diff --git a/src/starboard/android/shared/media_decoder.h b/src/starboard/android/shared/media_decoder.h index 41a7a11..80d0b7e 100644 --- a/src/starboard/android/shared/media_decoder.h +++ b/src/starboard/android/shared/media_decoder.h
@@ -86,6 +86,8 @@ void WriteInputBuffer(const scoped_refptr<InputBuffer>& input_buffer); void WriteEndOfStream(); + void SetPlaybackRate(double playback_rate); + size_t GetNumberOfPendingTasks() const { return number_of_pending_tasks_.load(); }
diff --git a/src/starboard/android/shared/media_is_supported.cc b/src/starboard/android/shared/media_is_supported.cc index 26d1e19..42aa227 100644 --- a/src/starboard/android/shared/media_is_supported.cc +++ b/src/starboard/android/shared/media_is_supported.cc
@@ -16,12 +16,19 @@ #include "starboard/android/shared/jni_env_ext.h" #include "starboard/android/shared/media_common.h" +#include "starboard/string.h" bool SbMediaIsSupported(SbMediaVideoCodec video_codec, SbMediaAudioCodec audio_codec, const char* key_system) { using starboard::android::shared::IsWidevineL1; using starboard::android::shared::JniEnvExt; + + if (SbStringFindCharacter(key_system, ';')) { + // TODO: Remove this check and enable key system with attributes support. + return false; + } + // Filter anything other then aac as we only support paid content on aac. // TODO: Add support of Opus if we are going to support software based drm // systems.
diff --git a/src/starboard/android/shared/player_components_factory.cc b/src/starboard/android/shared/player_components_factory.cc index 948b85a..6ac984a 100644 --- a/src/starboard/android/shared/player_components_factory.cc +++ b/src/starboard/android/shared/player_components_factory.cc
@@ -38,6 +38,15 @@ namespace { +const int kAudioSinkFramesAlignment = 256; +const int kDefaultAudioSinkMinFramesPerAppend = 1024; +const int kDefaultAudioSinkMaxCachedFrames = + 8 * kDefaultAudioSinkMinFramesPerAppend; + +int AlignUp(int value, int alignment) { + return (value + alignment - 1) / alignment * alignment; +} + class PlayerComponentsFactory : public PlayerComponents::Factory { bool CreateSubComponents( const CreationParameters& creation_parameters, @@ -94,6 +103,8 @@ creation_parameters.decode_target_graphics_context_provider(), creation_parameters.max_video_capabilities(), error_message)); if (video_decoder_impl->is_valid()) { + video_render_algorithm->reset(new android::shared::VideoRenderAlgorithm( + video_decoder_impl.get())); *video_renderer_sink = video_decoder_impl->GetSink(); video_decoder->reset(video_decoder_impl.release()); } else { @@ -103,12 +114,35 @@ "Failed to create video decoder with error: " + *error_message; return false; } - - video_render_algorithm->reset(new android::shared::VideoRenderAlgorithm); } return true; } + + void GetAudioRendererParams(const CreationParameters& creation_parameters, + int* max_cached_frames, + int* min_frames_per_append) const override { + SB_DCHECK(max_cached_frames); + SB_DCHECK(min_frames_per_append); + SB_DCHECK(kDefaultAudioSinkMinFramesPerAppend % kAudioSinkFramesAlignment == + 0); + *min_frames_per_append = kDefaultAudioSinkMinFramesPerAppend; + + // AudioRenderer prefers to use kSbMediaAudioSampleTypeFloat32 and only uses + // kSbMediaAudioSampleTypeInt16Deprecated when float32 is not supported. + int min_frames_required = SbAudioSinkGetMinBufferSizeInFrames( + creation_parameters.audio_sample_info().number_of_channels, + SbAudioSinkIsAudioSampleTypeSupported(kSbMediaAudioSampleTypeFloat32) + ? kSbMediaAudioSampleTypeFloat32 + : kSbMediaAudioSampleTypeInt16Deprecated, + creation_parameters.audio_sample_info().samples_per_second); + // On Android 5.0, the size of audio renderer sink buffer need to be two + // times larger than AudioTrack minBufferSize. Otherwise, AudioTrack may + // stop working after pause. + *max_cached_frames = + min_frames_required * 2 + kDefaultAudioSinkMinFramesPerAppend; + *max_cached_frames = AlignUp(*max_cached_frames, kAudioSinkFramesAlignment); + } }; } // namespace
diff --git a/src/starboard/android/shared/player_create.cc b/src/starboard/android/shared/player_create.cc index e2cfb48..a3a9a2a 100644 --- a/src/starboard/android/shared/player_create.cc +++ b/src/starboard/android/shared/player_create.cc
@@ -14,7 +14,7 @@ #include "starboard/player.h" -#include "starboard/android/shared/cobalt/android_media_session_client.h" +#include "starboard/android/shared/android_media_session_client.h" #include "starboard/android/shared/video_decoder.h" #include "starboard/android/shared/video_window.h" #include "starboard/common/log.h" @@ -28,9 +28,8 @@ using starboard::shared::starboard::player::filter:: FilterBasedPlayerWorkerHandler; using starboard::shared::starboard::player::PlayerWorker; -using starboard::android::shared::cobalt::kPlaying; -using starboard::android::shared::cobalt:: - UpdateActiveSessionPlatformPlaybackState; +using starboard::android::shared::kPlaying; +using starboard::android::shared::UpdateActiveSessionPlatformPlaybackState; using starboard::android::shared::VideoDecoder; SbPlayer SbPlayerCreate(SbWindow window, @@ -130,7 +129,10 @@ UpdateActiveSessionPlatformPlaybackState(kPlaying); } - if (creation_param->output_mode != kSbPlayerOutputModeDecodeToTexture) { + if (creation_param->output_mode != kSbPlayerOutputModeDecodeToTexture && + // TODO: This is temporary for supporting background media playback. + // Need to be removed with media refactor. + video_codec != kSbMediaVideoCodecNone) { // Check the availability of the video window. As we only support one main // player, and sub players are in decode to texture mode on Android, a // single video window should be enough.
diff --git a/src/starboard/android/shared/player_destroy.cc b/src/starboard/android/shared/player_destroy.cc index b790729..bdfbba3 100644 --- a/src/starboard/android/shared/player_destroy.cc +++ b/src/starboard/android/shared/player_destroy.cc
@@ -14,12 +14,11 @@ #include "starboard/player.h" -#include "starboard/android/shared/cobalt/android_media_session_client.h" +#include "starboard/android/shared/android_media_session_client.h" #include "starboard/shared/starboard/player/player_internal.h" -using starboard::android::shared::cobalt::kNone; -using starboard::android::shared::cobalt:: - UpdateActiveSessionPlatformPlaybackState; +using starboard::android::shared::kNone; +using starboard::android::shared::UpdateActiveSessionPlatformPlaybackState; void SbPlayerDestroy(SbPlayer player) { if (!SbPlayerIsValid(player)) {
diff --git a/src/starboard/android/shared/player_set_playback_rate.cc b/src/starboard/android/shared/player_set_playback_rate.cc index 2a01fcd..233cd92 100644 --- a/src/starboard/android/shared/player_set_playback_rate.cc +++ b/src/starboard/android/shared/player_set_playback_rate.cc
@@ -14,14 +14,13 @@ #include "starboard/player.h" -#include "starboard/android/shared/cobalt/android_media_session_client.h" +#include "starboard/android/shared/android_media_session_client.h" #include "starboard/common/log.h" #include "starboard/shared/starboard/player/player_internal.h" -using starboard::android::shared::cobalt::kPaused; -using starboard::android::shared::cobalt::kPlaying; -using starboard::android::shared::cobalt:: - UpdateActiveSessionPlatformPlaybackState; +using starboard::android::shared::kPaused; +using starboard::android::shared::kPlaying; +using starboard::android::shared::UpdateActiveSessionPlatformPlaybackState; bool SbPlayerSetPlaybackRate(SbPlayer player, double playback_rate) { if (!SbPlayerIsValid(player)) {
diff --git a/src/starboard/android/shared/starboard_platform.gypi b/src/starboard/android/shared/starboard_platform.gypi index 2621ee4..65c5044 100644 --- a/src/starboard/android/shared/starboard_platform.gypi +++ b/src/starboard/android/shared/starboard_platform.gypi
@@ -55,6 +55,7 @@ 'accessibility_get_text_to_speech_settings.cc', 'accessibility_set_captions_enabled.cc', 'android_main.cc', + 'android_media_session_client.cc', 'application_android.cc', 'application_android.h', 'atomic_public.h',
diff --git a/src/starboard/android/shared/system_get_extensions.cc b/src/starboard/android/shared/system_get_extensions.cc index 869446b..1ffca16 100644 --- a/src/starboard/android/shared/system_get_extensions.cc +++ b/src/starboard/android/shared/system_get_extensions.cc
@@ -15,7 +15,9 @@ #include "starboard/system.h" #include "cobalt/extension/configuration.h" +#include "cobalt/extension/media_session.h" #include "cobalt/extension/platform_service.h" +#include "starboard/android/shared/android_media_session_client.h" #include "starboard/android/shared/configuration.h" #include "starboard/android/shared/platform_service.h" #include "starboard/common/log.h" @@ -28,5 +30,8 @@ if (SbStringCompareAll(name, kCobaltExtensionConfigurationName) == 0) { return starboard::android::shared::GetConfigurationApi(); } + if (SbStringCompareAll(name, kCobaltExtensionMediaSessionName) == 0) { + return starboard::android::shared::GetMediaSessionApi(); + } return NULL; }
diff --git a/src/starboard/android/shared/video_decoder.cc b/src/starboard/android/shared/video_decoder.cc index 5a5030e..96a490a 100644 --- a/src/starboard/android/shared/video_decoder.cc +++ b/src/starboard/android/shared/video_decoder.cc
@@ -377,6 +377,7 @@ media_decoder_->Initialize( std::bind(&VideoDecoder::ReportError, this, _1, _2)); } + media_decoder_->SetPlaybackRate(playback_rate_); return true; } media_decoder_.reset(); @@ -577,6 +578,13 @@ return kSbDecodeTargetInvalid; } +void VideoDecoder::SetPlaybackRate(double playback_rate) { + playback_rate_ = playback_rate; + if (media_decoder_) { + media_decoder_->SetPlaybackRate(playback_rate); + } +} + void VideoDecoder::OnNewTextureAvailable() { has_new_texture_available_.store(true); }
diff --git a/src/starboard/android/shared/video_decoder.h b/src/starboard/android/shared/video_decoder.h index 8202f57..508817f 100644 --- a/src/starboard/android/shared/video_decoder.h +++ b/src/starboard/android/shared/video_decoder.h
@@ -83,6 +83,8 @@ void Reset() override; SbDecodeTarget GetCurrentDecodeTarget() override; + void SetPlaybackRate(double playback_rate); + bool is_valid() const { return media_decoder_ != NULL; } void OnNewTextureAvailable(); @@ -133,6 +135,8 @@ int32_t frame_width_ = 0; int32_t frame_height_ = 0; + double playback_rate_ = 1.0; + // The last enqueued |SbMediaColorMetadata|. optional<SbMediaColorMetadata> color_metadata_;
diff --git a/src/starboard/android/shared/video_render_algorithm.cc b/src/starboard/android/shared/video_render_algorithm.cc index 1b7e9aa..b234937 100644 --- a/src/starboard/android/shared/video_render_algorithm.cc +++ b/src/starboard/android/shared/video_render_algorithm.cc
@@ -18,6 +18,7 @@ #include "starboard/android/shared/jni_utils.h" #include "starboard/android/shared/media_common.h" +#include "starboard/common/log.h" namespace starboard { namespace android { @@ -36,6 +37,12 @@ } // namespace +VideoRenderAlgorithm::VideoRenderAlgorithm(VideoDecoder* video_decoder) + : video_decoder_(video_decoder) { + SB_DCHECK(video_decoder_); + video_decoder_->SetPlaybackRate(playback_rate_); +} + void VideoRenderAlgorithm::Render( MediaTimeProvider* media_time_provider, std::list<scoped_refptr<VideoFrame>>* frames, @@ -61,6 +68,10 @@ if (!is_audio_playing) { break; } + if (playback_rate != playback_rate_) { + playback_rate_ = playback_rate; + video_decoder_->SetPlaybackRate(playback_rate); + } jlong early_us = frames->front()->timestamp() - playback_time;
diff --git a/src/starboard/android/shared/video_render_algorithm.h b/src/starboard/android/shared/video_render_algorithm.h index 187a1ca..132e871 100644 --- a/src/starboard/android/shared/video_render_algorithm.h +++ b/src/starboard/android/shared/video_render_algorithm.h
@@ -18,6 +18,7 @@ #include <list> #include "starboard/android/shared/jni_env_ext.h" +#include "starboard/android/shared/video_decoder.h" #include "starboard/shared/starboard/player/filter/video_render_algorithm.h" namespace starboard { @@ -27,6 +28,8 @@ class VideoRenderAlgorithm : public ::starboard::shared::starboard::player:: filter::VideoRenderAlgorithm { public: + explicit VideoRenderAlgorithm(VideoDecoder* video_decoder); + void Render(MediaTimeProvider* media_time_provider, std::list<scoped_refptr<VideoFrame>>* frames, VideoRendererSink::DrawFrameCB draw_frame_cb) override; @@ -45,6 +48,8 @@ jobject j_video_frame_release_time_helper_ = nullptr; }; + VideoDecoder* video_decoder_ = nullptr; + double playback_rate_ = 1.0; VideoFrameReleaseTimeHelper video_frame_release_time_helper_; int dropped_frames_ = 0; };
diff --git a/src/starboard/android/shared/video_window.cc b/src/starboard/android/shared/video_window.cc index 8329a85..88b7037 100644 --- a/src/starboard/android/shared/video_window.cc +++ b/src/starboard/android/shared/video_window.cc
@@ -123,6 +123,11 @@ // during painting. ScopedLock lock(*GetViewSurfaceMutex()); + if (!g_native_video_window) { + SB_LOG(INFO) << "Tried to clear video window when it was null."; + return; + } + if (g_reset_surface_on_clear_window) { int width = ANativeWindow_getWidth(g_native_video_window); int height = ANativeWindow_getHeight(g_native_video_window); @@ -133,11 +138,6 @@ } } - if (!g_native_video_window) { - SB_LOG(INFO) << "Tried to clear video window when it was null."; - return; - } - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(display, NULL, NULL); if (display == EGL_NO_DISPLAY) {
diff --git a/src/starboard/build/platform_configuration.py b/src/starboard/build/platform_configuration.py index 77d8e2e..ebb054e 100644 --- a/src/starboard/build/platform_configuration.py +++ b/src/starboard/build/platform_configuration.py
@@ -24,7 +24,6 @@ from starboard.sabi import sabi from starboard.tools import ccache from starboard.tools import environment -from starboard.tools import goma from starboard.tools import paths from starboard.tools import platform from starboard.tools.config import Config @@ -72,12 +71,8 @@ self._application_configuration = None self._application_configuration_search_path = [self._directory] - # Specifies the build accelerator to be used. Default is ccache. Goma can - # be used but will be deprecated. - if 'FORCE_GOMA' in os.environ and os.environ['FORCE_GOMA'] == 1: - build_accelerator = goma.Goma() - else: - build_accelerator = ccache.Ccache() + # Specifies the build accelerator to be used. Default is ccache. + build_accelerator = ccache.Ccache() if build_accelerator.Use(): self.build_accelerator = build_accelerator.GetName() logging.info('Using %sbuild accelerator.', self.build_accelerator)
diff --git a/src/starboard/build/toolchain/gcc_toolchain.gni b/src/starboard/build/toolchain/gcc_toolchain.gni index ef3d025..6fab1ae 100644 --- a/src/starboard/build/toolchain/gcc_toolchain.gni +++ b/src/starboard/build/toolchain/gcc_toolchain.gni
@@ -17,7 +17,6 @@ # limitations under the License. import("//starboard/build/toolchain/clang.gni") -import("//starboard/build/toolchain/goma.gni") # This template defines a toolchain for something that works like gcc # (including clang). @@ -111,29 +110,8 @@ forward_variables_from(invoker_toolchain_args, "*") } - # When the invoker has explicitly overridden use_goma or cc_wrapper in the - # toolchain args, use those values, otherwise default to the global one. - # This works because the only reasonable override that toolchains might - # supply for these values are to force-disable them. - if (defined(toolchain_args.use_goma)) { - toolchain_uses_goma = toolchain_args.use_goma - } else { - toolchain_uses_goma = use_goma - } - - # When the invoker has explicitly overridden use_goma in the - # toolchain args, use those values, otherwise default to the global one. - # This works because the only reasonable override that toolchains might - # supply for these values are to force-disable them. - if (toolchain_uses_goma) { - goma_path = "$goma_dir/gomacc" - compiler_prefix = "${goma_path} " - } else { - compiler_prefix = "" - } - - cc = compiler_prefix + invoker.cc - cxx = compiler_prefix + invoker.cxx + cc = invoker.cc + cxx = invoker.cxx ar = invoker.ar ld = invoker.ld if (!defined(asm)) {
diff --git a/src/starboard/build/toolchain/goma.gni b/src/starboard/build/toolchain/goma.gni deleted file mode 100644 index 84914b2..0000000 --- a/src/starboard/build/toolchain/goma.gni +++ /dev/null
@@ -1,40 +0,0 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Modifications Copyright 2017 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. - -# Defines the configuration of Goma. - -# Allow ports to set an alternate default for use_goma -import("//$starboard_path/configuration.gni") - -declare_args() { - if (!defined(use_goma)) { - # Set to true to enable distributed compilation using Goma. By default we - # use Goma for stub and linux. - use_goma = false - } - - # Set the default value based on the platform. - if (host_os == "win" || host_os == "winrt_81" || - host_os == "winrt_81_phone" || host_os == "winrt_10") { - # Absolute directory containing the gomacc.exe binary. - goma_dir = "C:\goma\goma-win64" - } else { - # Absolute directory containing the gomacc binary. - goma_dir = getenv("HOME") + "/goma" - } -}
diff --git a/src/starboard/common/file.h b/src/starboard/common/file.h index a91c2fa..c24cdfe 100644 --- a/src/starboard/common/file.h +++ b/src/starboard/common/file.h
@@ -36,6 +36,74 @@ // |preserve_root|: Whether or not the root directory should be preserved. bool SbFileDeleteRecursive(const char* path, bool preserve_root); +// A class that opens an SbFile in its constructor and closes it in its +// destructor, so the file is open for the lifetime of the object. Member +// functions call the corresponding SbFile function. +class ScopedFile { + public: + ScopedFile(const char* path, + int flags, + bool* out_created, + SbFileError* out_error) + : file_(kSbFileInvalid) { + file_ = SbFileOpen(path, flags, out_created, out_error); + } + + ScopedFile(const char* path, int flags, bool* out_created) + : file_(kSbFileInvalid) { + file_ = SbFileOpen(path, flags, out_created, NULL); + } + + ScopedFile(const char* path, int flags) : file_(kSbFileInvalid) { + file_ = SbFileOpen(path, flags, NULL, NULL); + } + + ~ScopedFile() { SbFileClose(file_); } + + SbFile file() const { return file_; } + + bool IsValid() const { return SbFileIsValid(file_); } + + int64_t Seek(SbFileWhence whence, int64_t offset) const { + return SbFileSeek(file_, whence, offset); + } + + int Read(char* data, int size) const { return SbFileRead(file_, data, size); } + + int ReadAll(char* data, int size) const { + return SbFileReadAll(file_, data, size); + } + + int Write(const char* data, int size) const { + return SbFileWrite(file_, data, size); + } + + int WriteAll(const char* data, int size) const { + return SbFileWriteAll(file_, data, size); + } + + bool Truncate(int64_t length) const { return SbFileTruncate(file_, length); } + + bool Flush() const { return SbFileFlush(file_); } + + bool GetInfo(SbFileInfo* out_info) const { + return SbFileGetInfo(file_, out_info); + } + + int64_t GetSize() const { + SbFileInfo file_info; + bool success = GetInfo(&file_info); + return (success ? file_info.size : -1); + } + + // disallow copy and move operations + ScopedFile(const ScopedFile&) = delete; + ScopedFile& operator=(const ScopedFile&) = delete; + + private: + SbFile file_; +}; + } // namespace starboard #endif // STARBOARD_COMMON_FILE_H_
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h index 98a80c9..e6ba5e4 100644 --- a/src/starboard/configuration.h +++ b/src/starboard/configuration.h
@@ -71,6 +71,9 @@ // Add Concealed state support. #define SB_ADD_CONCEALED_STATE_SUPPORT_VERSION 14 +// Iteration on UI navigation API. +#define SB_UI_NAVIGATION2_VERSION SB_EXPERIMENTAL_API_VERSION + // --- Release Candidate Feature Defines ------------------------------------- // --- Common Detected Features ----------------------------------------------
diff --git a/src/starboard/doc/evergreen/symbolizing_minidumps.md b/src/starboard/doc/evergreen/symbolizing_minidumps.md new file mode 100644 index 0000000..4931300 --- /dev/null +++ b/src/starboard/doc/evergreen/symbolizing_minidumps.md
@@ -0,0 +1,129 @@ +# How to Symbolize Dumps + +Evergreen will store the minidumps (`.dmp` files) from the 2 most recent +crashes on the disk. They are stored under `kSbSystemPathCacheDirectory` in the +subdirectory `crashpad_database/`. These files can be used along with +Breakpad's tools to get a full stacktrace of the past crashes. This can help in +debugging, as these minidumps have the information for the dynamic +`libcobalt.so` module correctly mapped, which a out-of-the-box dumper could not +manage. + +## Obtaining the Tools to Symbolize Minidumps + +Tools for symbolizing these dumps are available through +[Breakpad](https://chromium.googlesource.com/breakpad/breakpad/). Breakpad is +an open source crash reporting library that we use to obtain symbol files +(`.sym`) from unstripped binaries, and to process the symbol files with the +minidumps to produce human-readable stacktraces. + + +### Building Breakpad + +[Breakpad](https://chromium.googlesource.com/breakpad/breakpad/) provides +instructions for building these tools yourself. The +[Getting Started with Breakpad](https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/getting_started_with_breakpad.md) +guide is a good place to start if you want to go through the docs yourself, but +below is a brief overview of how to get and build the tools. + +Download depot_tools: +``` +$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git +$ export PATH=/path/to/depot_tools:$PATH +``` + +Get breakpad: +``` +$ mkdir breakpad && cd breakpad +$ fetch breakpad +$ cd src +``` + +Build breakpad: +``` +$ ./configure && make +``` + +This will build the processor (`src/processor/minidump_stackwalk`), and when +building on Linux it will also build the `dump_syms` tool +(`src/tools/linux/dump_syms/dump_syms`). + +**IMPORTANT:** Once you have fetched Breakpad, you should remove the path to +depot_tools from your `$PATH` environment variable, as it can conflict with +Cobalt's depot_tools. + +## Symbolizing Minidumps + +Now that you have all the tools you need, we can symbolize the dumps. To be +able to symbolize Cobalt using Evergreen, you need to be get the unstripped +`libcobalt.so` binary. These will be available as assets in GitHub releases +[on Cobalt's public GitHub repo](https://github.com/youtube/cobalt/releases). + +libcobalt releases will be labeled by the Evergreen version, the architecture, +the config, and the ELF build id, for example +"libcobalt_1.0.10_unstripped_armeabi_softfp_qa_ac3132014007df0e.tgz". Here, we +have: +* Evergreen Version: 1.0.10 +* Architecture: armeabi_softfp +* Config: qa +* ELF Build Id: ac3132014007df0e + +Knowing the architecture and config you want, you'll just have to know which +version of Evergreen you're on or obtain the build id of the library. If you +need to obtain the ELF build id, you can do so easily by running +`readelf -n /path/to/libcobalt.so` and look at the hash displayed after "Build +ID:". + +Now you can get the debug symbols from the library using the tools we +downloaded previously. Unpack libcobalt and dump its symbols into a file: + +``` +$ tar xzf /path/to/libcobalt.tgz +$ /path/to/dump_syms /path/to/unzipped/libcobalt > libcobalt.so.sym +$ head -n1 libcobalt.so.sym +MODULE Linux x86_64 6462A5D44C0843D100000000000000000 libcobalt.so +``` + +We run `head` on the symbol file to get the debug identifier, the hash +displayed above (in this case, it's `6462A5D44C0843D100000000000000000`). Now +we can create the file structure that `minidump_stackwalker` expects and run +the stackwalker against the minidump: + +``` +$ mkdir -p symbols/libcobalt.so/<debug identifier>/ +$ mv libcobalt.so.sym symbols/libcobalt.so/<debug identifier>/ +$ /path/to/minidump_stackwalk /path/to/your/minidump.dmp symbols/ +``` + +`minidump_stackwalk` produces verbose output on stderr, and the stacktrace on +stdout, so you may want to redirect stderr. + +### Addendum: Adding Other Symbols + +We can use the process above to add symbols for any library or executable you +use, not just `libcobalt.so`. To do this, all you have to do is run the +`dump_syms` tools on the binary you want symbolized and put that in the +"symbols/" folder. + +``` +$ /path/to/dump_syms /path/to/<your-binary> > <your-binary>.sym +$ head -n1 <your-binary.sym> +MODULE Linux x86_64 <debug-identifier> <your-binary> +$ mkdir -p symbols/<your-binary>/<debug-identifier> +$ mv <your-binary>.sym symbols/<your-binary>/<debug-identifier>/ +``` + +Now, `minidump_stackwalk` should symbolize sections within `<your-binary>`. For +example, if you decided to symbolize the `loader_app`, it would transform the +stacktrace output from `minidump_stackwalk` from: + +``` +9 loader_app + 0x3a31130 +``` + +to: + +``` +9 loader_app!SbEventHandle [sandbox.cc : 44 + 0x8] +``` + +Note that the addresses will vary.
diff --git a/src/starboard/elf_loader/elf_loader_impl.cc b/src/starboard/elf_loader/elf_loader_impl.cc index 3bfc632..cd7a03e 100644 --- a/src/starboard/elf_loader/elf_loader_impl.cc +++ b/src/starboard/elf_loader/elf_loader_impl.cc
@@ -40,7 +40,7 @@ elf_header_loader_.reset(new ElfHeader()); if (!elf_header_loader_->LoadElfHeader(elf_file_.get())) { - SB_LOG(ERROR) << "Failed to loaded ELF header"; + SB_LOG(ERROR) << "Failed to load ELF header"; return false; }
diff --git a/src/starboard/elf_loader/evergreen_info.h b/src/starboard/elf_loader/evergreen_info.h index fecd079..2adfe29 100644 --- a/src/starboard/elf_loader/evergreen_info.h +++ b/src/starboard/elf_loader/evergreen_info.h
@@ -26,6 +26,7 @@ // the starboard implementation. #define EVERGREEN_FILE_PATH_MAX_SIZE 4096 #define EVERGREEN_BUILD_ID_MAX_SIZE 128 +#define EVERGREEN_USER_AGENT_MAX_SIZE 2048 #define IS_EVERGREEN_ADDRESS(address, evergreen_info) \ (evergreen_info.base_address != 0 && \ @@ -62,6 +63,12 @@ size_t build_id_length; } EvergreenInfo; +// Annotations that Evergreen will add to Crashpad for more detailed crash +// reports. +typedef struct EvergreenAnnotations { + char user_agent_string[EVERGREEN_USER_AGENT_MAX_SIZE]; +} EvergreenAnnotations; + // Set the Evergreen information. Should be called only from the // elf_loader module. Passing NULL clears the currently stored // information.
diff --git a/src/starboard/elf_loader/sandbox.cc b/src/starboard/elf_loader/sandbox.cc index 857ab89..9dd2f73 100644 --- a/src/starboard/elf_loader/sandbox.cc +++ b/src/starboard/elf_loader/sandbox.cc
@@ -21,6 +21,7 @@ #include "starboard/event.h" #include "starboard/mutex.h" #include "starboard/shared/starboard/command_line.h" +#include "starboard/string.h" #include "starboard/thread_types.h" #include "third_party/crashpad/wrapper/wrapper.h" @@ -63,6 +64,20 @@ g_sb_event_func = reinterpret_cast<void (*)(const SbEvent*)>( g_elf_loader.LookupSymbol("SbEventHandle")); + auto get_user_agent_func = reinterpret_cast<const char* (*)()>( + g_elf_loader.LookupSymbol("GetCobaltUserAgentString")); + if (!get_user_agent_func) { + SB_LOG(ERROR) << "Failed to get user agent string"; + } else { + EvergreenAnnotations cobalt_version_info; + SbMemorySet(&cobalt_version_info, sizeof(EvergreenAnnotations), 0); + SbStringCopy(cobalt_version_info.user_agent_string, get_user_agent_func(), + EVERGREEN_USER_AGENT_MAX_SIZE); + third_party::crashpad::wrapper::AddAnnotationsToCrashpad( + cobalt_version_info); + SB_DLOG(INFO) << "Added user agent string to Crashpad."; + } + if (!g_sb_event_func) { SB_LOG(ERROR) << "Failed to find SbEventHandle."; return;
diff --git a/src/starboard/evergreen/arm/shared/gyp_configuration.gypi b/src/starboard/evergreen/arm/shared/gyp_configuration.gypi index 404d3a3..4192b6c 100644 --- a/src/starboard/evergreen/arm/shared/gyp_configuration.gypi +++ b/src/starboard/evergreen/arm/shared/gyp_configuration.gypi
@@ -24,6 +24,8 @@ # Force char to be signed. '-fsigned-char', + '-ffunction-sections', + '-fdata-sections', ], 'linker_flags': [
diff --git a/src/starboard/evergreen/arm64/gyp_configuration.gypi b/src/starboard/evergreen/arm64/gyp_configuration.gypi index b2a0525..f8843b2 100644 --- a/src/starboard/evergreen/arm64/gyp_configuration.gypi +++ b/src/starboard/evergreen/arm64/gyp_configuration.gypi
@@ -22,6 +22,8 @@ 'compiler_flags': [ '-isystem<(cobalt_repo_root)/third_party/musl/arch/aarch64', + '-ffunction-sections', + '-fdata-sections', ], },
diff --git a/src/starboard/evergreen/shared/launcher.py b/src/starboard/evergreen/shared/launcher.py index 5cfcd55..c8a2787 100644 --- a/src/starboard/evergreen/shared/launcher.py +++ b/src/starboard/evergreen/shared/launcher.py
@@ -24,7 +24,7 @@ _BASE_STAGING_DIRECTORY = 'evergreen_staging' _CRASHPAD_TARGET = 'crashpad_handler' -_LOADER_TARGET = 'elf_loader_sandbox' +_DEFAULT_LOADER_TARGET = 'elf_loader_sandbox' class Launcher(abstract_launcher.AbstractLauncher): @@ -66,6 +66,10 @@ if not self.loader_config: raise ValueError('|loader_config| cannot be |None|.') + self.loader_target = kwargs.get('loader_target') + if not self.loader_target: + self.loader_target = _DEFAULT_LOADER_TARGET + self.loader_out_directory = kwargs.get('loader_out_directory') if not self.loader_out_directory: self.loader_out_directory = paths.BuildOutputDirectory( @@ -99,7 +103,7 @@ self.launcher = abstract_launcher.LauncherFactory( self.loader_platform, - _LOADER_TARGET, + self.loader_target, self.loader_config, device_id, target_params=target_command_line_params, @@ -150,7 +154,7 @@ # out/evergreen_staging/linux-x64x11_devel__evergreen-x64_devel/deploy/elf_loader_sandbox staging_directory_loader = os.path.join(self.staging_directory, 'deploy', - _LOADER_TARGET) + self.loader_target) # out/evergreen_staging/linux-x64x11_devel__evergreen-x64_devel/deploy/elf_loader_sandbox/content/app/nplb/ staging_directory_evergreen = os.path.join(staging_directory_loader, @@ -161,7 +165,7 @@ # specified by |staging_directory_loader|. A symbolic link here would cause # future symbolic links to fall through to the original out-directories. shutil.copytree( - os.path.join(self.loader_out_directory, 'deploy', _LOADER_TARGET), + os.path.join(self.loader_out_directory, 'deploy', self.loader_target), staging_directory_loader) shutil.copy( os.path.join(self.loader_out_directory, 'deploy', _CRASHPAD_TARGET, @@ -174,8 +178,8 @@ # TODO: Make the Linux launcher run from the deploy directory, no longer # create these symlinks, and remove the NOTE from the docstring. port_symlink.MakeSymLink( - os.path.join(staging_directory_loader, _LOADER_TARGET), - os.path.join(self.staging_directory, _LOADER_TARGET)) + os.path.join(staging_directory_loader, self.loader_target), + os.path.join(self.staging_directory, self.loader_target)) port_symlink.MakeSymLink( os.path.join(staging_directory_loader, _CRASHPAD_TARGET), os.path.join(self.staging_directory, _CRASHPAD_TARGET))
diff --git a/src/starboard/evergreen/testing/linux/clean_up.sh b/src/starboard/evergreen/testing/linux/clean_up.sh new file mode 100755 index 0000000..d454e2f --- /dev/null +++ b/src/starboard/evergreen/testing/linux/clean_up.sh
@@ -0,0 +1,20 @@ +#!/bin/bash +# +# 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. + +function clean_up() { + clear_storage +} +
diff --git a/src/starboard/evergreen/testing/linux/clear_storage.sh b/src/starboard/evergreen/testing/linux/clear_storage.sh new file mode 100755 index 0000000..6f14bde --- /dev/null +++ b/src/starboard/evergreen/testing/linux/clear_storage.sh
@@ -0,0 +1,21 @@ +#!/bin/bash +# +# 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. + +function clear_storage() { + echo " Clearing Cobalt storage" + eval "find ${STORAGE_DIR}/ -mindepth 1 -maxdepth 1 ! -name 'icu' -exec rm -rf {} +" 1> /dev/null +} +
diff --git a/src/starboard/evergreen/testing/linux/create_file.sh b/src/starboard/evergreen/testing/linux/create_file.sh new file mode 100755 index 0000000..0841fb1 --- /dev/null +++ b/src/starboard/evergreen/testing/linux/create_file.sh
@@ -0,0 +1,29 @@ +#!/bin/bash +# +# 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. + +function create_file() { + if [[ $# -ne 1 ]]; then + error " create_file only accepts a single argument" + return 1 + fi + + echo " Creating file '${1}'" + + eval "mkdir -p \"\"$(dirname "${1}")\"\"" 1> /dev/null + eval "touch \"\"${1}\"\"" 1> /dev/null + return 0 +} +
diff --git a/src/starboard/evergreen/testing/linux/delete_file.sh b/src/starboard/evergreen/testing/linux/delete_file.sh new file mode 100755 index 0000000..8e8b376 --- /dev/null +++ b/src/starboard/evergreen/testing/linux/delete_file.sh
@@ -0,0 +1,28 @@ +#!/bin/bash +# +# 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. + +function delete_file() { + if [[ $# -ne 1 ]]; then + error " delete_file only accepts a single argument" + return 1 + fi + + echo " Deleting file '${1}'" + + eval "rm -f \"\"${1}\"\"" 1> /dev/null + return 0 +} +
diff --git a/src/starboard/evergreen/testing/linux/deploy_cobalt.sh b/src/starboard/evergreen/testing/linux/deploy_cobalt.sh new file mode 100755 index 0000000..7f5bb9c --- /dev/null +++ b/src/starboard/evergreen/testing/linux/deploy_cobalt.sh
@@ -0,0 +1,50 @@ +#!/bin/bash +# +# 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. + +function deploy_cobalt() { + if [[ -z "${OUT}" ]]; then + info "Please set the environment variable 'OUT'" + exit 1 + fi + + echo " Checking '${OUT}'" + + PATHS=("${OUT}/deploy/loader_app/loader_app" \ + "${OUT}/deploy/loader_app/content/app/cobalt/lib/libcobalt.so" \ + "${OUT}/deploy/loader_app/content/app/cobalt/content/") + + for file in "${PATHS[@]}"; do + if [[ ! -e "${file}" ]]; then + echo " Failed to find '${file}'" + exit 1 + fi + done + + echo " Required files were found within '${OUT}'" + + echo " Deploying Cobalt on local device" + + echo " Generating HTML test directory" + eval "mkdir -p ${OUT}/deploy/loader_app/content/app/cobalt/content/web/tests/" 1> /dev/null + + echo " Copying HTML test files to HTML test directory" + eval "cp ${1}/../tests/*.html ${OUT}/deploy/loader_app/content/app/cobalt/content/web/tests/" 1> /dev/null + + clear_storage + + echo " Successfully deployed!" +} +
diff --git a/src/starboard/evergreen/testing/linux/run_command.sh b/src/starboard/evergreen/testing/linux/run_command.sh new file mode 100755 index 0000000..c299282 --- /dev/null +++ b/src/starboard/evergreen/testing/linux/run_command.sh
@@ -0,0 +1,26 @@ +#!/bin/bash +# +# 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. + +function run_command() { + if [[ $# -ne 1 ]]; then + error " run_command only accepts a single argument" + return 1 + fi + + # We want to capture the standard output from the command. + echo "$(eval "${1}")" +} +
diff --git a/src/starboard/evergreen/testing/linux/setup.sh b/src/starboard/evergreen/testing/linux/setup.sh new file mode 100755 index 0000000..6701ea2 --- /dev/null +++ b/src/starboard/evergreen/testing/linux/setup.sh
@@ -0,0 +1,44 @@ +#!/bin/bash +# +# 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. + +CONTENT="${OUT}/content/app/cobalt/content" +STORAGE_DIR="${HOME}/.cobalt_storage" +STORAGE_DIR_TMPFS="${STORAGE_DIR}.tmpfs" + +ID="id" +TAIL="tail" + +# Mounting a temporary filesystem cannot be done on buildbot since it requires +# sudo. When run locally, check for the temporary filesystem and create and +# mount it if it does not exist. +if [[ -z "${IS_BUILDBOT}" ]] || [[ "${IS_BUILDBOT}" -eq 0 ]]; then + if ! grep -qs "${STORAGE_DIR_TMPFS}" "/proc/mounts"; then + echo " Missing tmpfs mount at ${STORAGE_DIR_TMPFS}" + + if [[ ! -e "${STORAGE_DIR_TMPFS}" ]]; then + mkdir -p "${STORAGE_DIR_TMPFS}" 1> /dev/null + fi + + if [[ "$(${ID} -u)" -ne 0 ]]; then + echo " Not root, trying to mount tmpfs with sudo at ${STORAGE_DIR_TMPFS}" + sudo mount -F -t tmpfs -o size=10m "cobalt_storage.tmpfs" "${STORAGE_DIR_TMPFS}" 1> /dev/null + else + echo " Mounting tmpfs as root at ${STORAGE_DIR_TMPFS}" + mount -F -t tmpfs -o size=10m "cobalt_storage.tmpfs" "${STORAGE_DIR_TMPFS}" 1> /dev/null + fi + fi +fi +
diff --git a/src/starboard/evergreen/testing/linux/start_cobalt.sh b/src/starboard/evergreen/testing/linux/start_cobalt.sh new file mode 100755 index 0000000..99e6e1c --- /dev/null +++ b/src/starboard/evergreen/testing/linux/start_cobalt.sh
@@ -0,0 +1,80 @@ +#!/bin/bash +# +# 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. + +TIMEOUT=150 + +# Runs Cobalt on the desired platform. +# +# Globals: +# CONTENT +# LOG_PATH +# TIMEOUT +# +# Args: +# URL, path for logging, pattern to search logs for, extra arguments. +# +# Returns: +# 0 if the provided pattern was found in the logs, otherwise 1. +function start_cobalt() { + if [[ $# -lt 3 ]]; then + error " start_cobalt missing args" + return 1 + fi + + URL="${1}" + LOG="${2}" + PAT="${3}" + ARGS="${4}" + + stop_cobalt + + echo " Starting Cobalt with:" + echo " --url=${URL}" + echo " --content=${CONTENT}" + + for arg in $ARGS; do + echo " ${arg}" + done + + echo " Logs will be output to '${LOG_PATH}/${LOG}'" + + eval "${OUT}/loader_app --url=\"\"${URL}\"\" --content=${CONTENT} ${ARGS} 2>&1 | tee \"${LOG_PATH}/${LOG}\"" & + + LOADER=$! + + echo " Cobalt process ID is ${LOADER}" + + echo " Waiting up to ${TIMEOUT} seconds for \"${PAT}\" to be logged" + + wait_and_watch "${PAT}" "${LOG_PATH}/${LOG}" + + FOUND=$? + + echo " Finished after ${WAITED} seconds" + + echo " Stopping with 'kill -9 ${LOADER}'" + + kill -9 "${LOADER}" 1> /dev/null + + sleep 1 + + if [[ "${FOUND}" -eq 1 ]]; then + return 0 + fi + + return 1 +} +
diff --git a/src/starboard/evergreen/testing/linux/stop_cobalt.sh b/src/starboard/evergreen/testing/linux/stop_cobalt.sh new file mode 100755 index 0000000..0028883 --- /dev/null +++ b/src/starboard/evergreen/testing/linux/stop_cobalt.sh
@@ -0,0 +1,22 @@ +#!/bin/bash +# +# 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. + +function stop_cobalt() { + echo " Stopping Cobalt" + eval "kill -9 $(pidof "${OUT}/loader_app")" 1> /dev/null + sleep 1 +} +
diff --git a/src/starboard/evergreen/testing/pprint.sh b/src/starboard/evergreen/testing/pprint.sh new file mode 100755 index 0000000..c44ce31 --- /dev/null +++ b/src/starboard/evergreen/testing/pprint.sh
@@ -0,0 +1,40 @@ +#!/bin/bash +# +# 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. +# +# A set of helper functions to output colored text using ANSI escape codes. + +function pprint() { + local arg="-e" + if [[ "${OSTYPE}" = "*darwin*" ]]; then + arg="" + fi + # This command uses ANSI escape codes to attempt to output colored text. For + # more information see https://en.wikipedia.org/wiki/ANSI_escape_code. + echo "$arg" "\033[0;${1}m${2}\033[0m" >&2 +} + +function info() { + pprint 32 "${1}" +} + +function warn() { + pprint 33 "${1}" +} + +function error() { + pprint 31 "${1}" +} +
diff --git a/src/starboard/evergreen/testing/raspi/clean_up.sh b/src/starboard/evergreen/testing/raspi/clean_up.sh new file mode 100755 index 0000000..50d3792 --- /dev/null +++ b/src/starboard/evergreen/testing/raspi/clean_up.sh
@@ -0,0 +1,18 @@ +#!/bin/bash +# +# 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. + +source $1/../linux/clean_up.sh +
diff --git a/src/starboard/evergreen/testing/raspi/clear_storage.sh b/src/starboard/evergreen/testing/raspi/clear_storage.sh new file mode 100755 index 0000000..4ddaa4f --- /dev/null +++ b/src/starboard/evergreen/testing/raspi/clear_storage.sh
@@ -0,0 +1,21 @@ +#!/bin/bash +# +# 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. + +function clear_storage() { + echo " Clearing Cobalt storage" + eval "${SSH}\"find ${STORAGE_DIR}/ -mindepth 1 -maxdepth 1 ! -name 'icu' -exec rm -rf {} +\"" 1> /dev/null +} +
diff --git a/src/starboard/evergreen/testing/raspi/create_file.sh b/src/starboard/evergreen/testing/raspi/create_file.sh new file mode 100755 index 0000000..ec054a7 --- /dev/null +++ b/src/starboard/evergreen/testing/raspi/create_file.sh
@@ -0,0 +1,29 @@ +#!/bin/bash +# +# 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. + +function create_file() { + if [[ $# -ne 1 ]]; then + error " create_file only accepts a single argument" + return 1 + fi + + echo " Creating file '${1}'" + + eval "${SSH}\"mkdir -p \"$(dirname "${1}")\"\"" 1> /dev/null + eval "${SSH}\"touch \"${1}\"\"" 1> /dev/null + return 0 +} +
diff --git a/src/starboard/evergreen/testing/raspi/delete_file.sh b/src/starboard/evergreen/testing/raspi/delete_file.sh new file mode 100755 index 0000000..017d5b0 --- /dev/null +++ b/src/starboard/evergreen/testing/raspi/delete_file.sh
@@ -0,0 +1,28 @@ +#!/bin/bash +# +# 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. + +function delete_file() { + if [[ $# -ne 1 ]]; then + error " delete_file only accepts a single argument" + return 1 + fi + + echo " Deleting file '${1}'" + + eval "${SSH}\"rm -f \"${1}\"\"" 1> /dev/null + return 0 +} +
diff --git a/src/starboard/evergreen/testing/raspi/deploy_cobalt.sh b/src/starboard/evergreen/testing/raspi/deploy_cobalt.sh new file mode 100755 index 0000000..36da43e --- /dev/null +++ b/src/starboard/evergreen/testing/raspi/deploy_cobalt.sh
@@ -0,0 +1,64 @@ +#!/bin/bash +# +# 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. + +function deploy_cobalt() { + if [[ -z "${OUT}" ]]; then + info "Please set the environment variable 'OUT'" + exit 1 + fi + + echo " Checking '${OUT}'" + + PATHS=("${OUT}/deploy/loader_app/loader_app" \ + "${OUT}/deploy/loader_app/content/app/cobalt/lib/libcobalt.so" \ + "${OUT}/deploy/loader_app/content/app/cobalt/content/") + + for file in "${PATHS[@]}"; do + if [[ ! -e "${file}" ]]; then + echo " Failed to find '${file}'" + exit 1 + fi + done + + echo " Required files were found within '${OUT}'" + + echo " Deploying to the Raspberry Pi 2 at ${RASPI_ADDR}" + + echo " Regenerating Cobalt-on-Evergreen directory" + eval "${SSH} rm -rf /home/pi/coeg/" 1> /dev/null + eval "${SSH} mkdir /home/pi/coeg/" 1> /dev/null + + echo " Copying loader_app to Cobalt-on-Evergreen directory" + eval "${SCP} ${OUT}/deploy/loader_app/loader_app pi@${RASPI_ADDR}:/home/pi/coeg/" 1> /dev/null + + echo " Regenerating system image directory" + eval "${SSH} mkdir -p /home/pi/coeg/content/app/cobalt/lib" 1> /dev/null + + echo " Copying cobalt to system image directory" + eval "${SCP} ${OUT}/deploy/loader_app/content/app/cobalt/lib/libcobalt.so pi@${RASPI_ADDR}:/home/pi/coeg/content/app/cobalt/lib/" 1> /dev/null + + echo " Copying content to system image directory" + eval "${SCP} -r ${OUT}/deploy/loader_app/content/app/cobalt/content/ pi@${RASPI_ADDR}:/home/pi/coeg/content/app/cobalt/" 1> /dev/null + + echo " Generating HTML test directory" + eval "${SSH} mkdir -p /home/pi/coeg/content/app/cobalt/content/web/tests/" 1> /dev/null + + echo " Copying HTML test files to HTML test directory" + eval "${SCP} ${1}/../tests/*.html pi@${RASPI_ADDR}:/home/pi/coeg/content/app/cobalt/content/web/tests/" 1> /dev/null + + echo " Successfully deployed!" +} +
diff --git a/src/starboard/evergreen/testing/raspi/run_command.sh b/src/starboard/evergreen/testing/raspi/run_command.sh new file mode 100755 index 0000000..7a92b7e --- /dev/null +++ b/src/starboard/evergreen/testing/raspi/run_command.sh
@@ -0,0 +1,26 @@ +#!/bin/bash +# +# 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. + +function run_command() { + if [[ $# -ne 1 ]]; then + error " run_command only accepts a single argument" + return 1 + fi + + # We want to capture the standard output from the command. + echo "$(eval "${SSH}\"${1}\"")" +} +
diff --git a/src/starboard/evergreen/testing/raspi/setup.sh b/src/starboard/evergreen/testing/raspi/setup.sh new file mode 100755 index 0000000..ab815ef --- /dev/null +++ b/src/starboard/evergreen/testing/raspi/setup.sh
@@ -0,0 +1,67 @@ +#!/bin/bash +# +# 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. + +source $1/../pprint.sh +source $1/run_command.sh + +CONTENT="/home/pi/coeg/content/app/cobalt/content" +STORAGE_DIR="/home/pi/.cobalt_storage" +STORAGE_DIR_TMPFS="${STORAGE_DIR}.tmpfs" + +ID="id" +TAIL="tail" + +if [[ -z "${RASPI_ADDR}" ]]; then + info " Please set the environment variable 'RASPI_ADDR'" + exit 1 +fi + +KEYPATH="${HOME}/.ssh/raspi" + +if [[ ! -f "${KEYPATH}" ]]; then + ssh-keygen -t rsa -q -f "${KEYPATH}" -N "" 1> /dev/null + ssh-copy-id -i "${KEYPATH}.pub" pi@"${RASPI_ADDR}" 1> /dev/null + echo " Generated SSH key-pair for Raspberry Pi 2 at ${KEYPATH}" +else + echo " Re-using existing SSH key-pair for Raspberry Pi 2 at ${KEYPATH}" +fi + +SSH="ssh -i ${KEYPATH} pi@${RASPI_ADDR} " +SCP="scp -i ${KEYPATH} " + +echo " Targeting the Raspberry Pi 2 at ${RASPI_ADDR}" + +# Mounting a temporary filesystem cannot be done on buildbot since it requires +# sudo. When run locally, check for the temporary filesystem and create and +# mount it if it does not exist. +if [[ -z "${IS_BUILDBOT}" ]] || [[ "${IS_BUILDBOT}" -eq 0 ]]; then + eval "${SSH}\"grep -qs \"${STORAGE_DIR_TMPFS}\" \"/proc/mounts\"\"" 1> /dev/null + + if [[ $? -ne 0 ]]; then + if [[ ! -e "${STORAGE_DIR_TMPFS}" ]]; then + run_command "mkdir -p \"${STORAGE_DIR_TMPFS}\"" 1> /dev/null + fi + + if [[ "$(${SSH} "${ID} -u")" -ne 0 ]]; then + echo " Not root, trying to mount tmpfs with sudo at ${STORAGE_DIR_TMPFS}" + run_command "sudo mount -F -t tmpfs -o size=10m \"cobalt_storage.tmpfs\" \"${STORAGE_DIR_TMPFS}\"" 1> /dev/null + else + echo " Mounting tmpfs as root at ${STORAGE_DIR_TMPFS}" + run_command "mount -F -t tmpfs -o size=10m \"cobalt_storage.tmpfs\" \"${STORAGE_DIR_TMPFS}\"" 1> /dev/null + fi + fi +fi +
diff --git a/src/starboard/evergreen/testing/raspi/start_cobalt.sh b/src/starboard/evergreen/testing/raspi/start_cobalt.sh new file mode 100755 index 0000000..d1b879c --- /dev/null +++ b/src/starboard/evergreen/testing/raspi/start_cobalt.sh
@@ -0,0 +1,78 @@ +#!/bin/bash +# +# 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. + +TIMEOUT=150 + +# Runs Cobalt on the desired platform. +# +# Globals: +# CONTENT +# LOG_PATH +# TIMEOUT +# +# Args: +# URL, path for logging, pattern to search logs for, extra arguments. +# +# Returns: +# 0 if the provided pattern was found in the logs, otherwise 1. +function start_cobalt() { + if [[ $# -lt 3 ]]; then + error " start_cobalt missing args" + return 1 + fi + + URL="${1}" + LOG="${2}" + PAT="${3}" + ARGS="${4}" + + stop_cobalt + + echo " Starting Cobalt with:" + echo " --url=${URL}" + echo " --content=${CONTENT}" + + for arg in $ARGS; do + echo " ${arg}" + done + + echo " Logs will be output to '${LOG_PATH}/${LOG}'" + + eval "${SSH}\"/home/pi/coeg/loader_app --url=\"\"${URL}\"\" --content=${CONTENT} ${ARGS} \" 2>&1 | tee \"${LOG_PATH}/${LOG}\"" & + + LOADER=$! + + echo " Cobalt process ID is ${LOADER}" + echo " Waiting up to ${TIMEOUT} seconds for \"${PAT}\" to be logged" + + wait_and_watch "${PAT}" "${LOG_PATH}/${LOG}" + + FOUND=$? + + echo " Finished after ${WAITED} seconds" + echo " Stopping with 'kill -9 ${LOADER}'" + + kill -9 "${LOADER}" &> /dev/null + + sleep 1 + + if [[ "${FOUND}" -eq 1 ]]; then + return 0 + fi + + return 1 +} +
diff --git a/src/starboard/evergreen/testing/raspi/stop_cobalt.sh b/src/starboard/evergreen/testing/raspi/stop_cobalt.sh new file mode 100755 index 0000000..ffd5bac --- /dev/null +++ b/src/starboard/evergreen/testing/raspi/stop_cobalt.sh
@@ -0,0 +1,22 @@ +#!/bin/bash +# +# 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. + +function stop_cobalt() { + echo " Stopping Cobalt" + eval "${SSH}\"pidof /home/pi/coeg/loader_app | xargs kill -9\"" 1> /dev/null + sleep 1 +} +
diff --git a/src/starboard/evergreen/testing/run_all_tests.sh b/src/starboard/evergreen/testing/run_all_tests.sh new file mode 100755 index 0000000..d0602fc --- /dev/null +++ b/src/starboard/evergreen/testing/run_all_tests.sh
@@ -0,0 +1,112 @@ +#!/bin/bash +# +# 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. +# +# Driver script that sets up the testing environment, collects all of the tests +# to run, runs them, and outputs the results. + +DIR="$(dirname "${0}")" + +if [[ ! -f "${DIR}/setup.sh" ]]; then + echo "The script 'setup.sh' is required" + exit 1 +fi + +source $DIR/setup.sh + +# Find all of the test files within the 'test' subdirectory. +TESTS=($(eval "find ${DIR}/tests -maxdepth 1 -name '*_test.sh'")) + +COUNT=0 +FAILED=() +PASSED=() +SKIPPED=() + +info " [==========] Deploying Cobalt." + +deploy_cobalt "${DIR}/${1}" + +info " [==========] Running ${#TESTS[@]} tests." + +# Loop over all of the tests found in the current directory and run them. +for test in "${TESTS[@]}"; do + source $test "${DIR}/${1}" + + info " [ RUN ] ${TEST_NAME}" + + run_test + + RESULT=$? + + if [[ "${RESULT}" -eq 0 ]]; then + info " [ PASSED ] ${TEST_NAME}" + PASSED+=("${TEST_NAME}") + elif [[ "${RESULT}" -eq 1 ]]; then + error " [ FAILED ] ${TEST_NAME}" + FAILED+=("$TEST_NAME") + elif [[ "${RESULT}" -eq 2 ]]; then + warn " [ SKIPPED ] ${TEST_NAME}" + SKIPPED+=("$TEST_NAME") + fi + + stop_cobalt &> /dev/null + + COUNT=$((COUNT + 1)) +done + +info " [==========] ${COUNT} tests ran." + +# Output the number of passed tests. +if [[ "${#PASSED[@]}" -eq 1 ]]; then + info " [ PASSED ] 1 test." +elif [[ "${#PASSED[@]}" -gt 1 ]]; then + info " [ PASSED ] ${#PASSED[@]} tests." +fi + +# Output the number of skipped tests. +if [[ "${#SKIPPED[@]}" -eq 1 ]]; then + warn " [ SKIPPED ] 1 test, listed below:" +elif [[ "${#SKIPPED[@]}" -gt 1 ]]; then + warn " [ SKIPPED ] ${#SKIPPED[@]} tests, listed below:" +fi + +# Output each of the skipped tests. +for test in "${SKIPPED[@]}"; do + warn " [ SKIPPED ] ${test}" +done + +# Output the number of failed tests. +if [[ "${#FAILED[@]}" -eq 1 ]]; then + error " [ FAILED ] 1 test, listed below:" +elif [[ "${#FAILED[@]}" -gt 1 ]]; then + error " [ FAILED ] ${#FAILED[@]} tests, listed below:" +fi + +# Output each of the failed tests. +for test in "${FAILED[@]}"; do + error " [ FAILED ] ${test}" +done + +info " [==========] Cleaning up." + +clean_up + +info " [==========] Finished." + +if [[ "${#FAILED[@]}" -eq 0 ]]; then + exit 0 +fi + +exit 1
diff --git a/src/starboard/evergreen/testing/setup.sh b/src/starboard/evergreen/testing/setup.sh new file mode 100755 index 0000000..1546b28 --- /dev/null +++ b/src/starboard/evergreen/testing/setup.sh
@@ -0,0 +1,80 @@ +#!/bin/bash +# +# 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. + +if [[ ! -f "${DIR}/pprint.sh" ]]; then + echo "The script 'pprint.sh' is required" + exit 1 +fi + +source $DIR/pprint.sh + +info " [==========] Preparing Cobalt." + +if [[ $# -ne 1 ]]; then + error "A platform must be provided" + exit 1 +fi + +PLATFORMS=("linux" "raspi") + +if [[ ! "${PLATFORMS[@]}" =~ "${1}" ]] && [[ ! -d "${DIR}/${1}" ]]; then + error "The platform provided must be one of the following: " "${PLATFORMS[@]}" + exit 1 +fi + +# List of all required scripts. +SCRIPTS=("${DIR}/shared/app_key.sh" \ + "${DIR}/shared/drain_file.sh" \ + "${DIR}/shared/installation_slot.sh" \ + "${DIR}/shared/wait_and_watch.sh" \ + + # Each of the following scripts must be provided for the targeted + # platform. The script 'setup.sh' must be source'd first. + "${DIR}/${1}/setup.sh" \ + + "${DIR}/${1}/clean_up.sh" \ + "${DIR}/${1}/clear_storage.sh" \ + "${DIR}/${1}/create_file.sh" \ + "${DIR}/${1}/delete_file.sh" \ + "${DIR}/${1}/deploy_cobalt.sh" \ + "${DIR}/${1}/run_command.sh" \ + "${DIR}/${1}/start_cobalt.sh" \ + "${DIR}/${1}/stop_cobalt.sh") + +for script in "${SCRIPTS[@]}"; do + if [[ ! -f "${script}" ]]; then + error "The script '${script}' is required" + exit 1 + fi + + source $script "${DIR}/${1}" +done + +if [[ ! -d "/tmp/" ]]; then + error "The '/tmp/' directory is missing" + exit 1 +fi + +# A path in the temporary directory to write test log files to. +LOG_PATH="/tmp/youtube_test_logs/$(date +%s%3N)" + +mkdir -p "${LOG_PATH}" &> /dev/null + +if [[ ! -d "${LOG_PATH}" ]]; then + error "Failed to create directory at '${LOG_PATH}'" + exit 1 +fi +
diff --git a/src/starboard/evergreen/testing/shared/app_key.sh b/src/starboard/evergreen/testing/shared/app_key.sh new file mode 100755 index 0000000..506fe5d --- /dev/null +++ b/src/starboard/evergreen/testing/shared/app_key.sh
@@ -0,0 +1,29 @@ +#!/bin/bash +# +# 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. + +function get_bad_app_key_file_path() { + if [[ $# -ne 1 ]]; then + error " get_bad_app_key_file_path only accepts a single argument" + return 1 + fi + + # Warning: do not wrap '$TAIL' with double quotes or else it will not actually + # resolve to the correct command. + echo "$( \ + sed -n "s/.*bad_app_key_file_path: \(.*app_key_[A-Za-z0-9+/=]\{32,\}\.bad\).*/\1/p" \ + "${LOG_PATH}/${1}" | ${TAIL} -1)" +} +
diff --git a/src/starboard/evergreen/testing/shared/drain_file.sh b/src/starboard/evergreen/testing/shared/drain_file.sh new file mode 100755 index 0000000..2e66aa1 --- /dev/null +++ b/src/starboard/evergreen/testing/shared/drain_file.sh
@@ -0,0 +1,29 @@ +#!/bin/bash +# +# 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. + +function get_temporary_drain_file_path() { + if [[ $# -ne 1 ]]; then + error " get_temporary_drain_file_path only accepts a single argument" + return 1 + fi + + # Warning: do not wrap '$TAIL' with double quotes or else it will not actually + # resolve to the correct command. + echo "$( \ + sed -n "s/.*Created drain file at '\(.*d_\)[A-Za-z0-9+/=]\{32,\}\(_[0-9]\{8,\}\).*/\1TEST\2/p" \ + "${LOG_PATH}/${1}" | ${TAIL} -1)" +} +
diff --git a/src/starboard/evergreen/testing/shared/installation_slot.sh b/src/starboard/evergreen/testing/shared/installation_slot.sh new file mode 100755 index 0000000..0258be3 --- /dev/null +++ b/src/starboard/evergreen/testing/shared/installation_slot.sh
@@ -0,0 +1,29 @@ +#!/bin/bash +# +# 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. + +function get_current_installation_slot() { + if [[ $# -ne 1 ]]; then + error " get_current_installation_slot only accepts a single argument" + return 1 + fi + + # Warning: do not wrap '$TAIL' with double quotes or else it will not actually + # resolve to the correct command. + echo "$( \ + sed -n "s/.*current_installation=\([0-9]\+\).*/\1/p" \ + "${LOG_PATH}/${1}" | ${TAIL} -1)" +} +
diff --git a/src/starboard/evergreen/testing/shared/wait_and_watch.sh b/src/starboard/evergreen/testing/shared/wait_and_watch.sh new file mode 100644 index 0000000..f7c39da --- /dev/null +++ b/src/starboard/evergreen/testing/shared/wait_and_watch.sh
@@ -0,0 +1,36 @@ +#!/bin/bash +# +# 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. + +function wait_and_watch() { + if [[ $# -ne 2 ]]; then + error " wait_and_watch requires a pattern and a path" + return 1 + fi + + WAITED=0 + + while [[ "${WAITED}" -lt "${TIMEOUT}" ]]; do + if grep -Eq "${1}" "${2}"; then + return 1 + fi + + WAITED=$((WAITED + 1)) + sleep 1 + done + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/abort_update_if_already_updating_test.sh b/src/starboard/evergreen/testing/tests/abort_update_if_already_updating_test.sh new file mode 100755 index 0000000..90f8c1f --- /dev/null +++ b/src/starboard/evergreen/testing/tests/abort_update_if_already_updating_test.sh
@@ -0,0 +1,50 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="AbortUpdateIfAlreadyUpdating" +TEST_FILE="test.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "Created drain file" + + if [[ $? -ne 0 ]]; then + error "Failed to create a drain file for the test package" + return 1 + fi + + FILENAME="$(get_temporary_drain_file_path "${TEST_NAME}.0.log")" + + clear_storage + + create_file "${FILENAME}" + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.1.log" "bailing out" + + if [[ $? -ne 0 ]]; then + error "Failed to find 'bailing out' in logs" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/alternative_content_test.sh b/src/starboard/evergreen/testing/tests/alternative_content_test.sh new file mode 100755 index 0000000..00d6eca --- /dev/null +++ b/src/starboard/evergreen/testing/tests/alternative_content_test.sh
@@ -0,0 +1,44 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="AlternativeContent" +TEST_FILE="test.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "update from test channel installed" + + if [[ $? -ne 0 ]]; then + error "Failed to download and install the test package" + return 1 + fi + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.1.log" "App is up to date" "--content=${CONTENT}" + + if [[ $? -ne 0 ]]; then + error "Failed to find 'App is up to date' indicating failure" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/continuous_updates_test.sh b/src/starboard/evergreen/testing/tests/continuous_updates_test.sh new file mode 100755 index 0000000..f82d212 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/continuous_updates_test.sh
@@ -0,0 +1,42 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="ContinuousUpdates" +TEST_FILE="tseries.html" + +function run_test() { + clear_storage + + OLD_TIMEOUT="${TIMEOUT}" + TIMEOUT=300 + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "continuous updates without restart working" + + TIMEOUT="${OLD_TIMEOUT}" + + if [[ $? -ne 0 ]]; then + error "Failed to validate alternating channels" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/crashing_binary_test.sh b/src/starboard/evergreen/testing/tests/crashing_binary_test.sh new file mode 100755 index 0000000..040538d --- /dev/null +++ b/src/starboard/evergreen/testing/tests/crashing_binary_test.sh
@@ -0,0 +1,53 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="CrashingBinary" +TEST_FILE="tcrash.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "update from tcrash channel installed" + + if [[ $? -ne 0 ]]; then + error "Failed to download and install the tcrash package" + return 1 + fi + + for i in {1..3}; do + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.${i}.log" "Caught signal: SIG[A-Z]{4}" + + if [[ $? -ne 0 ]]; then + error "Binary did not crash on attempt #${i}" + return 1 + fi + done + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.4.log" "App is up to date" + + if [[ $? -ne 0 ]]; then + error "Failed to revert to working installation after crashing 3 times" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/disabled_updater_test.sh b/src/starboard/evergreen/testing/tests/disabled_updater_test.sh new file mode 100755 index 0000000..985f110 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/disabled_updater_test.sh
@@ -0,0 +1,51 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="DisabledUpdater" +TEST_FILE="test.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "update from test channel installed" + + if [[ $? -ne 0 ]]; then + error "Failed to download and install the test package" + return 1 + fi + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.1.log" "App is up to date" + + if [[ $? -ne 0 ]]; then + error "Failed to run downloaded installation" + return 1 + fi + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.2.log" "disable_updates=1" "--disable_updates" + + if [[ $? -ne 0 ]]; then + error "Failed to run system installation" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/empty.html b/src/starboard/evergreen/testing/tests/empty.html new file mode 100644 index 0000000..b8dd5a8 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/empty.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<!-- +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. +--> +<html> +<meta charset="utf-8"> +<title>empty</title> +</html>
diff --git a/src/starboard/evergreen/testing/tests/load_slot_being_updated_test.sh b/src/starboard/evergreen/testing/tests/load_slot_being_updated_test.sh new file mode 100755 index 0000000..f61736e --- /dev/null +++ b/src/starboard/evergreen/testing/tests/load_slot_being_updated_test.sh
@@ -0,0 +1,48 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="LoadSlotBeingUpdated" +TEST_FILE="test.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "update from test channel installed" + + if [[ $? -ne 0 ]]; then + error "Failed to download and install the test package" + return 1 + fi + + FILENAME=$(get_temporary_drain_file_path "${TEST_NAME}.0.log") + + create_file "${FILENAME}" + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.1.log" "Active slot draining" + + if [[ $? -ne 0 ]]; then + error "Failed to abort loading a slot being drained" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/mismatched_architecture_test.sh b/src/starboard/evergreen/testing/tests/mismatched_architecture_test.sh new file mode 100755 index 0000000..0f8a427 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/mismatched_architecture_test.sh
@@ -0,0 +1,49 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="MismatchedArchitecture" +TEST_FILE="tmsabi.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "update from tmsabi channel installed" + + if [[ $? -ne 0 ]]; then + error "Failed to download and install the tmsabi package" + return 1 + fi + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.1.log" "Failed to load ELF header" + + if [[ $? -ne 0 ]]; then + error "Failed to recognize architecture mismatch" + return 1 + fi + + if ! grep -Eq "RevertBack current_installation=[0-9]+" "${LOG_PATH}/${TEST_NAME}.1.log"; then + error "Failed to revert after mismatched download" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/noop_binary_test.sh b/src/starboard/evergreen/testing/tests/noop_binary_test.sh new file mode 100755 index 0000000..30835a6 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/noop_binary_test.sh
@@ -0,0 +1,58 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="NoOpBinary" +TEST_FILE="tnoop.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "update from tnoop channel installed" + + if [[ $? -ne 0 ]]; then + error "Failed to download and install the tnoop package" + return 1 + fi + + for i in {1..3}; do + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.${i}.log" "Load start=0x[a-f0-9]{8,} base_memory_address=0x[a-f0-9]{8,}" + + if [[ $? -ne 0 ]]; then + error "Failed to load binary" + return 1 + fi + + if grep -Eq "Starting application." "${LOG_PATH}/${TEST_NAME}.${i}.log"; then + error "Failed to run no-op binary" + return 1 + fi + done + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.4.log" "App is up to date" + + if [[ $? -ne 0 ]]; then + error "Failed to revert to working installation after no-oping 3 times" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/out_of_storage_test.sh b/src/starboard/evergreen/testing/tests/out_of_storage_test.sh new file mode 100755 index 0000000..a970be8 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/out_of_storage_test.sh
@@ -0,0 +1,53 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="OutOfStorage" +TEST_FILE="test.html" + +function run_test() { + if [[ ! -z "${IS_BUILDBOT}" ]] && [[ "${IS_BUILDBOT}" -eq 1 ]]; then + echo " Cannot mount temporary filesystems on builbot, skipping" + return 2 + fi + + clear_storage + + run_command "ln -s \"${STORAGE_DIR_TMPFS}\" \"${STORAGE_DIR}\"" 1> /dev/null + + # We need to explicitly clear the "storage", i.e. the temporary filesystem, + # since previous runs might have artifacts leftover. + run_command "rm -rf ${STORAGE_DIR}/*" 1> /dev/null + + OLD_TIMEOUT="${TIMEOUT}" + TIMEOUT=300 + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "Failed to update, error code is 12" + + if [[ $? -ne 0 ]]; then + error "Failed to run out of storage" + return 1 + fi + + TIMEOUT="${OLD_TIMEOUT}" + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/quick_roll_forward_test.sh b/src/starboard/evergreen/testing/tests/quick_roll_forward_test.sh new file mode 100755 index 0000000..4e15e72 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/quick_roll_forward_test.sh
@@ -0,0 +1,51 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="QuickRollForward" +TEST_FILE="test.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "update from test channel installed" + + if [[ $? -ne 0 ]]; then + error "Failed to download and install the test package" + return 1 + fi + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.1.log" "App is up to date" + + if [[ $? -ne 0 ]]; then + error "Failed to run downloaded installation" + return 1 + fi + + start_cobalt "file:///tests/empty.html" "${TEST_NAME}.2.log" "quick update succeeded" + + if [[ $? -ne 0 ]]; then + error "Failed to adopt downloaded installation on different app" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/racing_updaters_test.sh b/src/starboard/evergreen/testing/tests/racing_updaters_test.sh new file mode 100755 index 0000000..087b5cd --- /dev/null +++ b/src/starboard/evergreen/testing/tests/racing_updaters_test.sh
@@ -0,0 +1,69 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="RacingUpdaters" +TEST_FILE="test.html" + +function wait_and_force_race_condition() { + if [[ $# -ne 3 ]]; then + error " wait_and_force_race_condition requires a pattern, a path and a filename" + return 1 + fi + + # The previous logs are available when this is invoked. Wait before beginning + # to check the logs. + sleep 15 + + wait_and_watch "${1}" "${2}" + + FOUND=$? + + if [[ "${FOUND}" -eq 1 ]]; then + create_file "${3}" + fi +} + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "Created drain file" + + if [[ $? -ne 0 ]]; then + error "Failed to create a drain file for the test package" + return 1 + fi + + FILENAME="$(get_temporary_drain_file_path "${TEST_NAME}.0.log")" + + clear_storage + + wait_and_force_race_condition "Created drain file" "${LOG_PATH}/${TEST_NAME}.1.log" "${FILENAME}" & + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.1.log" "failed to lock slot" + + if [[ $? -ne 0 ]]; then + error "Failed to recognize another update is updating slot" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/tcrash.html b/src/starboard/evergreen/testing/tests/tcrash.html new file mode 100644 index 0000000..e05af63 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/tcrash.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<!-- +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. +--> +<html> +<meta charset="utf-8"> +<title>tcrash</title> +<script> + var changeChannel = setInterval(tryChangeChannel, 500); + + function tryChangeChannel() { + const channel = window.h5vcc.updater.getUpdaterChannel(); + const status = window.h5vcc.updater.getUpdateStatus(); + + if (channel == "") { + return; + } + + if (channel == "qa") { + if ((status == "App is up to date") || (status == "Update installed, pending restart")) { + window.h5vcc.updater.setUpdaterChannel("tcrash"); + console.log("channel was changed to tcrash"); + return; + } + } + + if ((channel == "tcrash") && (status == "Update installed, pending restart")) { + console.log("update from tcrash channel installed"); + clearInterval(changeChannel); + } + } +</script> +</html>
diff --git a/src/starboard/evergreen/testing/tests/test.html b/src/starboard/evergreen/testing/tests/test.html new file mode 100644 index 0000000..f404546 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/test.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<!-- +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. +--> +<html> +<meta charset="utf-8"> +<title>test</title> +<script> + var changeChannel = setInterval(tryChangeChannel, 500); + + function tryChangeChannel() { + const channel = window.h5vcc.updater.getUpdaterChannel(); + const status = window.h5vcc.updater.getUpdateStatus(); + + if (channel == "") { + return; + } + + if (channel == "qa") { + if ((status == "App is up to date") || (status == "Update installed, pending restart")) { + window.h5vcc.updater.setUpdaterChannel("test"); + console.log("channel was changed to test"); + return; + } + } + + if ((channel == "test") && (status == "Update installed, pending restart")) { + console.log("update from test channel installed"); + clearInterval(changeChannel); + } + } +</script> +</html>
diff --git a/src/starboard/evergreen/testing/tests/tfailv.html b/src/starboard/evergreen/testing/tests/tfailv.html new file mode 100644 index 0000000..c039830 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/tfailv.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<!-- +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. +--> +<html> +<meta charset="utf-8"> +<title>tfailv</title> +<script> + var changeChannel = setInterval(tryChangeChannel, 500); + + function tryChangeChannel() { + const channel = window.h5vcc.updater.getUpdaterChannel(); + const status = window.h5vcc.updater.getUpdateStatus(); + + if (channel == "") { + return; + } + + if (channel == "qa") { + if ((status == "App is up to date") || (status == "Update installed, pending restart")) { + window.h5vcc.updater.setUpdaterChannel("tfailv"); + console.log("channel was changed to tfailv"); + return; + } + } + + if ((channel == "tfailv") && (status == "Update installed, pending restart")) { + console.log("update from tfailv channel installed"); + clearInterval(changeChannel); + } + } +</script> +</html>
diff --git a/src/starboard/evergreen/testing/tests/tmsabi.html b/src/starboard/evergreen/testing/tests/tmsabi.html new file mode 100644 index 0000000..ae70b57 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/tmsabi.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<!-- +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. +--> +<html> +<meta charset="utf-8"> +<title>tmsabi</title> +<script> + var changeChannel = setInterval(tryChangeChannel, 500); + + function tryChangeChannel() { + const channel = window.h5vcc.updater.getUpdaterChannel(); + const status = window.h5vcc.updater.getUpdateStatus(); + + if (channel == "") { + return; + } + + if (channel == "qa") { + if ((status == "App is up to date") || (status == "Update installed, pending restart")) { + window.h5vcc.updater.setUpdaterChannel("tmsabi"); + console.log("channel was changed to tmsabi"); + return; + } + } + + if ((channel == "tmsabi") && (status == "Update installed, pending restart")) { + console.log("update from tmsabi channel installed"); + clearInterval(changeChannel); + } + } +</script> +</html>
diff --git a/src/starboard/evergreen/testing/tests/tnoop.html b/src/starboard/evergreen/testing/tests/tnoop.html new file mode 100644 index 0000000..ecfa328 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/tnoop.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<!-- +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. +--> +<html> +<meta charset="utf-8"> +<title>tnoop</title> +<script> + var changeChannel = setInterval(tryChangeChannel, 500); + + function tryChangeChannel() { + const channel = window.h5vcc.updater.getUpdaterChannel(); + const status = window.h5vcc.updater.getUpdateStatus(); + + if (channel == "") { + return; + } + + if (channel == "qa") { + if ((status == "App is up to date") || (status == "Update installed, pending restart")) { + window.h5vcc.updater.setUpdaterChannel("tnoop"); + console.log("channel was changed to tnoop"); + return; + } + } + + if ((channel == "tnoop") && (status == "Update installed, pending restart")) { + console.log("update from tnoop channel installed"); + clearInterval(changeChannel); + } + } +</script> +</html>
diff --git a/src/starboard/evergreen/testing/tests/tseries.html b/src/starboard/evergreen/testing/tests/tseries.html new file mode 100644 index 0000000..0d3aeff --- /dev/null +++ b/src/starboard/evergreen/testing/tests/tseries.html
@@ -0,0 +1,56 @@ +<!DOCTYPE html> +<!-- +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. +--> +<html> +<meta charset="utf-8"> +<title>ttseries</title> +<script> + var alternatedCount = 0; + var alternatingChannels = setInterval(alternateChannels, 500); + + function alternateChannels() { + const channel = window.h5vcc.updater.getUpdaterChannel(); + const status = window.h5vcc.updater.getUpdateStatus(); + + if (channel == "qa") { + console.log("channel changed from qa to tseries1"); + window.h5vcc.updater.setUpdaterChannel("tseries1"); + return; + } + + if (alternatedCount < 5) { + if (status != "Update installed, pending restart") { + return; + } + + if (channel == "tseries1") { + console.log("channel changed from tseries1 to tseries2"); + window.h5vcc.updater.setUpdaterChannel("tseries2"); + } else { + console.log("channel changed from " + channel + " to tseries1"); + window.h5vcc.updater.setUpdaterChannel("tseries1"); + } + + alternatedCount++; + return; + } + + console.log("continuous updates without restart working"); + + clearInterval(alternatingChannels); + } +</script> +</html>
diff --git a/src/starboard/evergreen/testing/tests/update_fails_verification_test.sh b/src/starboard/evergreen/testing/tests/update_fails_verification_test.sh new file mode 100755 index 0000000..bfcbbc9 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/update_fails_verification_test.sh
@@ -0,0 +1,44 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="UpdateFailsVerification" +TEST_FILE="tfailv.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "Verification failed. Verifier error = [0-9]+" + + if [[ $? -ne 0 ]]; then + error "Failed to fail verifying the downloaded installation" + return 1 + fi + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.1.log" "App is up to date" + + if [[ $? -ne 0 ]]; then + error "Failed to revert back to the system image" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/update_works_for_only_one_app_test.sh b/src/starboard/evergreen/testing/tests/update_works_for_only_one_app_test.sh new file mode 100755 index 0000000..2574654 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/update_works_for_only_one_app_test.sh
@@ -0,0 +1,62 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="UpdateOnlyWorksForOneApp" +TEST_FILE="test.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "update from test channel installed" + + if [[ $? -ne 0 ]]; then + error "Failed to download and install the test package" + return 1 + fi + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.1.log" "App is up to date" + + if [[ $? -ne 0 ]]; then + error "Failed to run the downloaded installation" + return 1 + fi + + start_cobalt "file:///tests/empty.html" "${TEST_NAME}.2.log" "quick update succeeded" + + if [[ $? -ne 0 ]]; then + error "Failed to perform a quick update on different app" + return 1 + fi + + FILENAME="$(get_bad_app_key_file_path "${TEST_NAME}.2.log")" + + create_file "${FILENAME}" + + start_cobalt "file:///tests/empty.html" "${TEST_NAME}.3.log" "RevertBack current_installation=" + + if [[ $? -ne 0 ]]; then + error "Failed to revert when the app's bad file exists" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/valid_slot_overwritten_test.sh b/src/starboard/evergreen/testing/tests/valid_slot_overwritten_test.sh new file mode 100755 index 0000000..6fc33b0 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/valid_slot_overwritten_test.sh
@@ -0,0 +1,59 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="ValidSlotOverwritten" +TEST_FILE="test.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "update from test channel installed" + + if [[ $? -ne 0 ]]; then + error "Failed to download and install the test package" + return 1 + fi + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.1.log" "App is up to date" + + if [[ $? -ne 0 ]]; then + error "Failed to run the downloaded installation" + return 1 + fi + + SLOT="$(get_current_installation_slot "${TEST_NAME}.1.log")" + + # Warning: do not wrap '$TAIL' with double quotes or else it will not actually + # resolve to the correct command. + delete_file "$(run_command "find ${STORAGE_DIR}/installation_${SLOT} -name app_key_*.good | ${TAIL} -1")" + + create_file "${STORAGE_DIR}/installation_${SLOT}/app_key_TEST.good" + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.2.log" "AdoptInstallation: current_installation=${SLOT}" + + if [[ $? -ne 0 ]]; then + error "Failed to adopt installation" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/testing/tests/verify_qa_channel_update_test.sh b/src/starboard/evergreen/testing/tests/verify_qa_channel_update_test.sh new file mode 100755 index 0000000..66c4632 --- /dev/null +++ b/src/starboard/evergreen/testing/tests/verify_qa_channel_update_test.sh
@@ -0,0 +1,44 @@ +#!/bin/bash +# +# 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. + +# Unset the previous test's name and runner function. +unset TEST_NAME +unset TEST_FILE +unset -f run_test + +TEST_NAME="VerifyQaChannelUpdate" +TEST_FILE="test.html" + +function run_test() { + clear_storage + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.0.log" "update from test channel installed" + + if [[ $? -ne 0 ]]; then + error "Failed to download and install the test package" + return 1 + fi + + start_cobalt "file:///tests/${TEST_FILE}" "${TEST_NAME}.1.log" "App is up to date" + + if [[ $? -ne 0 ]]; then + error "Failed to run the downloaded installation" + return 1 + fi + + return 0 +} +
diff --git a/src/starboard/evergreen/x64/gyp_configuration.gypi b/src/starboard/evergreen/x64/gyp_configuration.gypi index dcb689e..a9f3eaa 100644 --- a/src/starboard/evergreen/x64/gyp_configuration.gypi +++ b/src/starboard/evergreen/x64/gyp_configuration.gypi
@@ -22,6 +22,8 @@ 'compiler_flags': [ '-isystem<(cobalt_repo_root)/third_party/musl/arch/x86_64', + '-ffunction-sections', + '-fdata-sections', ], },
diff --git a/src/starboard/evergreen/x86/gyp_configuration.gypi b/src/starboard/evergreen/x86/gyp_configuration.gypi index f8a868f..58ebaca 100644 --- a/src/starboard/evergreen/x86/gyp_configuration.gypi +++ b/src/starboard/evergreen/x86/gyp_configuration.gypi
@@ -22,6 +22,8 @@ 'compiler_flags': [ '-isystem<(cobalt_repo_root)/third_party/musl/arch/i386', + '-ffunction-sections', + '-fdata-sections', ], },
diff --git a/src/starboard/file.h b/src/starboard/file.h index 5f90802..1d69e49 100644 --- a/src/starboard/file.h +++ b/src/starboard/file.h
@@ -330,78 +330,10 @@ } // extern "C" #endif -#ifdef __cplusplus -namespace starboard { - -// A class that opens an SbFile in its constructor and closes it in its -// destructor, so the file is open for the lifetime of the object. Member -// functions call the corresponding SbFile function. -class ScopedFile { - public: - ScopedFile(const char* path, - int flags, - bool* out_created, - SbFileError* out_error) - : file_(kSbFileInvalid) { - file_ = SbFileOpen(path, flags, out_created, out_error); - } - - ScopedFile(const char* path, int flags, bool* out_created) - : file_(kSbFileInvalid) { - file_ = SbFileOpen(path, flags, out_created, NULL); - } - - ScopedFile(const char* path, int flags) : file_(kSbFileInvalid) { - file_ = SbFileOpen(path, flags, NULL, NULL); - } - - ~ScopedFile() { SbFileClose(file_); } - - SbFile file() const { return file_; } - - bool IsValid() const { return SbFileIsValid(file_); } - - int64_t Seek(SbFileWhence whence, int64_t offset) const { - return SbFileSeek(file_, whence, offset); - } - - int Read(char* data, int size) const { return SbFileRead(file_, data, size); } - - int ReadAll(char* data, int size) const { - return SbFileReadAll(file_, data, size); - } - - int Write(const char* data, int size) const { - return SbFileWrite(file_, data, size); - } - - int WriteAll(const char* data, int size) const { - return SbFileWriteAll(file_, data, size); - } - - bool Truncate(int64_t length) const { return SbFileTruncate(file_, length); } - - bool Flush() const { return SbFileFlush(file_); } - - bool GetInfo(SbFileInfo* out_info) const { - return SbFileGetInfo(file_, out_info); - } - - int64_t GetSize() const { - SbFileInfo file_info; - bool success = GetInfo(&file_info); - return (success ? file_info.size : -1); - } - - // disallow copy and move operations - ScopedFile(const ScopedFile&) = delete; - ScopedFile& operator=(const ScopedFile&) = delete; - - private: - SbFile file_; -}; - -} // namespace starboard -#endif // ifdef __cplusplus +#if SB_API_VERSION < 13 && defined(__cplusplus) +extern "C++" { +#include "starboard/common/file.h" +} // extern "C++" +#endif // SB_API_VERSION < 13 && defined(__cplusplus) #endif // STARBOARD_FILE_H_
diff --git a/src/starboard/linux/shared/compiler_flags.gypi b/src/starboard/linux/shared/compiler_flags.gypi index 53b3229..af40c10 100644 --- a/src/starboard/linux/shared/compiler_flags.gypi +++ b/src/starboard/linux/shared/compiler_flags.gypi
@@ -36,9 +36,15 @@ ], 'compiler_flags_qa_size': [ '-Os', + # Compile symbols in separate sections + '-ffunction-sections', + '-fdata-sections', ], 'compiler_flags_qa_speed': [ '-O2', + # Compile symbols in separate sections + '-ffunction-sections', + '-fdata-sections', ], 'compiler_flags_gold': [ '-fno-rtti', @@ -46,9 +52,15 @@ ], 'compiler_flags_gold_size': [ '-Os', + # Compile symbols in separate sections + '-ffunction-sections', + '-fdata-sections', ], 'compiler_flags_gold_speed': [ '-O2', + # Compile symbols in separate sections + '-ffunction-sections', + '-fdata-sections', ], 'conditions': [ ['clang==1', { @@ -135,6 +147,8 @@ ], 'ldflags': [ '-Wl,-rpath=$ORIGIN/lib', + # Cleanup unused sections + '-Wl,-gc-sections', ], 'target_conditions': [ ['sb_pedantic_warnings==1', {
diff --git a/src/starboard/linux/shared/configuration.gni b/src/starboard/linux/shared/configuration.gni index c4562c3..49d1b21 100644 --- a/src/starboard/linux/shared/configuration.gni +++ b/src/starboard/linux/shared/configuration.gni
@@ -39,9 +39,3 @@ # Use ASAN by default when building with Clang. use_asan_by_default = true - -declare_args() { - # Set to true to enable distributed compilation using Goma. By default we - # use Goma for stub and linux. - use_goma = true -}
diff --git a/src/starboard/linux/shared/gyp_configuration.py b/src/starboard/linux/shared/gyp_configuration.py index f96c364..0cb799e 100644 --- a/src/starboard/linux/shared/gyp_configuration.py +++ b/src/starboard/linux/shared/gyp_configuration.py
@@ -18,6 +18,7 @@ from starboard.build import clang from starboard.build import platform_configuration from starboard.tools import build +from starboard.tools import paths from starboard.tools.testing import test_filter @@ -88,13 +89,25 @@ def GetTestFilters(self): filters = super(LinuxConfiguration, self).GetTestFilters() - for target, tests in self.__FILTERED_TESTS.iteritems(): + + has_cdm = os.path.isfile( + os.path.join(paths.REPOSITORY_ROOT, 'third_party', 'ce_cdm', 'cdm', + 'include', 'cdm.h')) + + if has_cdm: + return filters + + # Filter the drm related tests, as ce_cdm is not present. + for target, tests in self.__DRM_RELATED_TESTS.iteritems(): filters.extend(test_filter.TestFilter(target, test) for test in tests) return filters def GetPathToSabiJsonFile(self): return self.sabi_json_path - __FILTERED_TESTS = { # pylint: disable=invalid-name - 'nplb': ['SbDrmTest.AnySupportedKeySystems',], + __DRM_RELATED_TESTS = { # pylint: disable=invalid-name + 'nplb': [ + 'SbDrmTest.AnySupportedKeySystems', + 'SbMediaCanPlayMimeAndKeySystem.AnySupportedKeySystems', + ], }
diff --git a/src/starboard/linux/x64x11/clang/3.6/compiler_flags.gypi b/src/starboard/linux/x64x11/clang/3.6/compiler_flags.gypi index b5368e1..845e1df 100644 --- a/src/starboard/linux/x64x11/clang/3.6/compiler_flags.gypi +++ b/src/starboard/linux/x64x11/clang/3.6/compiler_flags.gypi
@@ -50,8 +50,6 @@ 'common_clang_flags': [ '-Werror', '-fcolor-diagnostics', - # Point to a gcc toolchain that works with this compiler. - '--gcc-toolchain=<(GCC_TOOLCHAIN_FOLDER)', # Default visibility to hidden, to enable dead stripping. '-fvisibility=hidden', # Warn for implicit type conversions that may change a value. @@ -73,18 +71,15 @@ '-Wno-invalid-offsetof', # Suppress 'implicit conversion changes signedness' '-Wno-sign-conversion', - # shifting a negative signed value is undefined '-Wno-shift-sign-overflow', - # Suppress "'&&' within '||'" - '-Wno-logical-op-parentheses', # Suppress "comparison may be assumed to always evaluate to false" '-Wno-tautological-undefined-compare', # Suppress "comparison of unsigned enum expression < 0 is always false" '-Wno-tautological-compare', # Suppress "[type1] has C-linkage specified, but returns user-defined type [type2] which is incompatible with C" '-Wno-return-type-c-linkage', - + '-Wno-array-bounds', # Suppress "template argument uses unnamed type" '-Wno-unnamed-type-template-args', # 'this' pointer cannot be NULL...pointer may be assumed @@ -94,19 +89,19 @@ '-Wno-inconsistent-missing-override', # Triggered by the COMPILE_ASSERT macro. '-Wno-unused-local-typedef', - # shifting a negative signed value is undefined - '-Wno-shift-sign-overflow', # Suppress "'&&' within '||'" '-Wno-logical-op-parentheses', - # Suppress "comparison may be assumed to always evaluate to false" - '-Wno-tautological-undefined-compare', - # Suppress "comparison of unsigned enum expression < 0 is always false" - '-Wno-tautological-compare', - # Suppress "[type1] has C-linkage specified, but returns user-defined type [type2] which is incompatible with C" - '-Wno-return-type-c-linkage', '-Wno-unused-parameter', # Suppress warnings about unknown pragmas. '-Wno-unknown-pragmas', + # Suppress warnings about equality checks within double parentheses. + '-Wno-parentheses-equality', + # Suppress warnings about unreachable code due to constexpr conditions + '-Wno-unreachable-code', + # Suppress warnings about values being written but not read before the next write. + '-Wno-unused-value', + # Suppress warnings related to unused compilation flags in clang. + '-Wno-unused-command-line-argument', ], }], ['cobalt_fastbuild==0', {
diff --git a/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py b/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py index 1506d71..8bb0020 100644 --- a/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py +++ b/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py
@@ -18,7 +18,6 @@ import subprocess from starboard.linux.shared import gyp_configuration as shared_configuration -from starboard.tools import build from starboard.tools.toolchain import ar from starboard.tools.toolchain import bash from starboard.tools.toolchain import clang @@ -34,21 +33,15 @@ platform='linux-x64x11-clang-3-6', asan_enabled_by_default=False, sabi_json_path='starboard/sabi/default/sabi.json'): - super(LinuxX64X11Clang36Configuration, self).__init__( - platform, - asan_enabled_by_default, - sabi_json_path) + super(LinuxX64X11Clang36Configuration, + self).__init__(platform, asan_enabled_by_default, sabi_json_path) - self.toolchain_top_dir = os.path.join(build.GetToolchainsDir(), - 'x86_64-linux-gnu-clang-3.6') - self.toolchain_dir = os.path.join(self.toolchain_top_dir, 'llvm', - 'Release+Asserts') + self.toolchain_dir = '/usr/lib/llvm-3.6' def SetupPlatformTools(self, build_number): - script_path = os.path.dirname(os.path.realpath(__file__)) - # Run the script that ensures clang 3.6 is installed. - subprocess.call( - os.path.join(script_path, 'download_clang.sh'), cwd=script_path) + ret = subprocess.call('/usr/bin/clang-3.6 --version', shell=True) + if ret != 0: + raise Exception('clang-3.6 is not installed.') def GetEnvironmentVariables(self): toolchain_bin_dir = os.path.join(self.toolchain_dir, 'bin') @@ -56,22 +49,18 @@ env_variables = super(LinuxX64X11Clang36Configuration, self).GetEnvironmentVariables() env_variables.update({ - 'CC': self.build_accelerator + ' ' + os.path.join(toolchain_bin_dir, - 'clang'), - 'CXX': self.build_accelerator + ' ' + os.path.join(toolchain_bin_dir, - 'clang++'), + 'CC': + self.build_accelerator + ' ' + + os.path.join(toolchain_bin_dir, 'clang'), + 'CXX': + self.build_accelerator + ' ' + + os.path.join(toolchain_bin_dir, 'clang++'), }) return env_variables def GetVariables(self, config_name): - # A significant amount of code in V8 fails to compile on clang 3.6 using - # the debug config, due to an internal error in clang. variables = super(LinuxX64X11Clang36Configuration, self).GetVariables(config_name) - variables.update({ - 'GCC_TOOLCHAIN_FOLDER': - '\"%s\"' % os.path.join(self.toolchain_top_dir, 'libstdc++-7'), - }) return variables def GetTargetToolchain(self, **kwargs):
diff --git a/src/starboard/linux/x64x11/gyp_configuration.py b/src/starboard/linux/x64x11/gyp_configuration.py index 5bf1c11..5f8069a 100644 --- a/src/starboard/linux/x64x11/gyp_configuration.py +++ b/src/starboard/linux/x64x11/gyp_configuration.py
@@ -13,8 +13,6 @@ # limitations under the License. """Starboard Linux X64 X11 platform configuration.""" -import os.path - from starboard.linux.shared import gyp_configuration as shared_configuration from starboard.tools.toolchain import ar from starboard.tools.toolchain import bash @@ -22,7 +20,6 @@ from starboard.tools.toolchain import clangxx from starboard.tools.toolchain import cp from starboard.tools.toolchain import touch -from starboard.tools import paths class LinuxX64X11Configuration(shared_configuration.LinuxConfiguration): @@ -32,9 +29,8 @@ platform='linux-x64x11', asan_enabled_by_default=True, sabi_json_path='starboard/sabi/default/sabi.json'): - super(LinuxX64X11Configuration, self).__init__(platform, - asan_enabled_by_default, - sabi_json_path) + super(LinuxX64X11Configuration, + self).__init__(platform, asan_enabled_by_default, sabi_json_path) def GetTargetToolchain(self, **kwargs): return self.GetHostToolchain(**kwargs) @@ -57,25 +53,6 @@ bash.Shell(), ] - def GetTestFilters(self): - filters = super(LinuxX64X11Configuration, self).GetTestFilters() - # Remove the exclusion filter on SbDrmTest.AnySupportedKeySystems. - # Generally, children of linux/shared do not support widevine, but children - # of linux/x64x11 do, if the content decryption module is present. - - has_cdm = os.path.isfile( - os.path.join(paths.REPOSITORY_ROOT, 'third_party', 'cdm', 'cdm', - 'include', 'content_decryption_module.h')) - - if not has_cdm: - return filters - - for test_filter in filters: - if (test_filter.target_name == 'nplb' and - test_filter.test_name == 'SbDrmTest.AnySupportedKeySystems'): - filters.remove(test_filter) - return filters - def CreatePlatformConfig(): return LinuxX64X11Configuration(
diff --git a/src/starboard/loader_app/app_key_files.cc b/src/starboard/loader_app/app_key_files.cc index e387987..68631e5 100644 --- a/src/starboard/loader_app/app_key_files.cc +++ b/src/starboard/loader_app/app_key_files.cc
@@ -16,10 +16,10 @@ #include <vector> +#include "starboard/common/file.h" #include "starboard/common/log.h" #include "starboard/configuration_constants.h" #include "starboard/directory.h" -#include "starboard/file.h" #include "starboard/string.h" namespace starboard {
diff --git a/src/starboard/loader_app/drain_file_helper.cc b/src/starboard/loader_app/drain_file_helper.cc index 8c3e0b1..0a61a97 100644 --- a/src/starboard/loader_app/drain_file_helper.cc +++ b/src/starboard/loader_app/drain_file_helper.cc
@@ -14,7 +14,7 @@ #include "starboard/loader_app/drain_file_helper.h" -#include "starboard/file.h" +#include "starboard/common/file.h" #include "starboard/loader_app/drain_file.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/src/starboard/loader_app/drain_file_test.cc b/src/starboard/loader_app/drain_file_test.cc index afbde87..35ae7cd 100644 --- a/src/starboard/loader_app/drain_file_test.cc +++ b/src/starboard/loader_app/drain_file_test.cc
@@ -17,10 +17,10 @@ #include <string> #include <vector> +#include "starboard/common/file.h" #include "starboard/common/log.h" #include "starboard/configuration_constants.h" #include "starboard/directory.h" -#include "starboard/file.h" #include "starboard/loader_app/drain_file_helper.h" #include "starboard/system.h" #include "starboard/types.h"
diff --git a/src/starboard/loader_app/installation_manager_test.cc b/src/starboard/loader_app/installation_manager_test.cc index 168241c..da7e8b0 100644 --- a/src/starboard/loader_app/installation_manager_test.cc +++ b/src/starboard/loader_app/installation_manager_test.cc
@@ -17,6 +17,7 @@ #include <string> #include <vector> +#include "starboard/common/file.h" #include "starboard/configuration_constants.h" #include "starboard/loader_app/installation_store.pb.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/src/starboard/loader_app/loader_app.cc b/src/starboard/loader_app/loader_app.cc index c74437f..1c661af 100644 --- a/src/starboard/loader_app/loader_app.cc +++ b/src/starboard/loader_app/loader_app.cc
@@ -25,6 +25,7 @@ #include "starboard/loader_app/loader_app_switches.h" #include "starboard/loader_app/slot_management.h" #include "starboard/loader_app/system_get_extension_shim.h" +#include "starboard/memory.h" #include "starboard/mutex.h" #include "starboard/shared/starboard/command_line.h" #include "starboard/string.h" @@ -109,6 +110,20 @@ SB_LOG(INFO) << "Loaded Cobalt library information into Crashpad."; } + auto get_user_agent_func = reinterpret_cast<const char* (*)()>( + g_elf_loader.LookupSymbol("GetCobaltUserAgentString")); + if (!get_user_agent_func) { + SB_LOG(ERROR) << "Failed to get user agent string"; + } else { + EvergreenAnnotations cobalt_version_info; + SbMemorySet(&cobalt_version_info, sizeof(EvergreenAnnotations), 0); + SbStringCopy(cobalt_version_info.user_agent_string, get_user_agent_func(), + EVERGREEN_USER_AGENT_MAX_SIZE); + third_party::crashpad::wrapper::AddAnnotationsToCrashpad( + cobalt_version_info); + SB_DLOG(INFO) << "Added user agent string to Crashpad."; + } + g_sb_event_func = reinterpret_cast<void (*)(const SbEvent*)>( g_elf_loader.LookupSymbol("SbEventHandle"));
diff --git a/src/starboard/loader_app/loader_app.gyp b/src/starboard/loader_app/loader_app.gyp index 154cb61..e8f730e 100644 --- a/src/starboard/loader_app/loader_app.gyp +++ b/src/starboard/loader_app/loader_app.gyp
@@ -90,5 +90,17 @@ }, 'includes': [ '<(DEPTH)/starboard/build/deploy.gypi' ], }, + { + 'target_name': 'loader_app_tests_deploy', + 'type': 'none', + 'dependencies': [ + 'loader_app', + '<(DEPTH)/starboard/loader_app/app_key.gyp:app_key_test_deploy', + '<(DEPTH)/starboard/loader_app/app_key_files.gyp:app_key_files_test_deploy', + '<(DEPTH)/starboard/loader_app/drain_file.gyp:drain_file_test_deploy', + '<(DEPTH)/starboard/loader_app/installation_manager.gyp:installation_manager_test_deploy', + '<(DEPTH)/starboard/loader_app/slot_management.gyp:slot_management_test_deploy', + ], + }, ], }
diff --git a/src/starboard/loader_app/slot_management.cc b/src/starboard/loader_app/slot_management.cc index 9e1eadd..5dc1212 100644 --- a/src/starboard/loader_app/slot_management.cc +++ b/src/starboard/loader_app/slot_management.cc
@@ -23,6 +23,7 @@ #include "starboard/loader_app/app_key_files.h" #include "starboard/loader_app/drain_file.h" #include "starboard/loader_app/installation_manager.h" +#include "starboard/memory.h" #include "starboard/string.h" #include "third_party/crashpad/wrapper/wrapper.h" @@ -243,6 +244,20 @@ SB_LOG(INFO) << "Loaded Cobalt library information into Crashpad."; } + auto get_user_agent_func = reinterpret_cast<const char* (*)()>( + library_loader->Resolve("GetCobaltUserAgentString")); + if (!get_user_agent_func) { + SB_LOG(ERROR) << "Failed to get user agent string"; + } else { + EvergreenAnnotations cobalt_version_info; + SbMemorySet(&cobalt_version_info, sizeof(EvergreenAnnotations), 0); + SbStringCopy(cobalt_version_info.user_agent_string, get_user_agent_func(), + EVERGREEN_USER_AGENT_MAX_SIZE); + third_party::crashpad::wrapper::AddAnnotationsToCrashpad( + cobalt_version_info); + SB_DLOG(INFO) << "Added user agent string to Crashpad."; + } + SB_DLOG(INFO) << "Successfully loaded Cobalt!\n"; void* p = library_loader->Resolve("SbEventHandle"); if (p != NULL) {
diff --git a/src/starboard/loader_app/slot_management_test.cc b/src/starboard/loader_app/slot_management_test.cc index 0eeb83c..5ff9e20 100644 --- a/src/starboard/loader_app/slot_management_test.cc +++ b/src/starboard/loader_app/slot_management_test.cc
@@ -37,6 +37,10 @@ void SbEventFake(const SbEvent*) {} +const char* GetCobaltUserAgentStringFake() { + return ""; +} + class MockLibraryLoader : public LibraryLoader { public: MOCK_METHOD2(Load, @@ -132,6 +136,10 @@ Load(testing::EndsWith(lib), testing::EndsWith(content))) .Times(1) .WillOnce(testing::Return(true)); + EXPECT_CALL(library_loader, Resolve("GetCobaltUserAgentString")) + .Times(1) + .WillOnce(testing::Return( + reinterpret_cast<void*>(&GetCobaltUserAgentStringFake))); EXPECT_CALL(library_loader, Resolve("SbEventHandle")) .Times(1) .WillOnce(testing::Return(reinterpret_cast<void*>(&SbEventFake))); @@ -261,6 +269,10 @@ testing::EndsWith("/foo"))) .Times(1) .WillOnce(testing::Return(true)); + EXPECT_CALL(library_loader, Resolve("GetCobaltUserAgentString")) + .Times(1) + .WillOnce(testing::Return( + reinterpret_cast<void*>(&GetCobaltUserAgentStringFake))); EXPECT_CALL(library_loader, Resolve("SbEventHandle")) .Times(1) .WillOnce(testing::Return(reinterpret_cast<void*>(&SbEventFake)));
diff --git a/src/starboard/media.h b/src/starboard/media.h index bdafbe4..05aaf0d 100644 --- a/src/starboard/media.h +++ b/src/starboard/media.h
@@ -544,11 +544,44 @@ // or |video/mp4; codecs="avc1.42001E"|. It may include arbitrary parameters // like "codecs", "channels", etc. Note that the "codecs" parameter may // contain more than one codec, delimited by comma. -// |key_system|: A lowercase value in fhe form of "com.example.somesystem" +// |key_system|: A lowercase value in the form of "com.example.somesystem" // as suggested by https://w3c.github.io/encrypted-media/#key-system // that can be matched exactly with known DRM key systems of the platform. // When |key_system| is an empty string, the return value is an indication for // non-encrypted media. +// +// An implementation may choose to support |key_system| with extra attributes, +// separated by ';', like +// |com.example.somesystem; attribute_name1="value1"; attribute_name2=value1|. +// If |key_system| with attributes is not supported by an implementation, it +// should treat |key_system| as if it contains only the key system, and reject +// any input containing extra attributes, i.e. it can keep using its existing +// implementation. +// When an implementation supports |key_system| with attributes, it has to +// support all attributes defined by the Starboard version the implementation +// uses. +// An implementation should ignore any unknown attributes, and make a decision +// solely based on the key system and the known attributes. For example, if +// an implementation supports "com.widevine.alpha", it should also return +// `kSbMediaSupportTypeProbably` when |key_system| is +// |com.widevine.alpha; invalid_attribute="invalid_value"|. +// Currently the only attribute has to be supported is |encryptionscheme|. It +// reflects the value passed to `encryptionScheme` of +// MediaKeySystemMediaCapability, as defined in +// https://wicg.github.io/encrypted-media-encryption-scheme/, which can take +// value "cenc", "cbcs", or "cbcs-1-9". +// Empty string is not a valid value for |encryptionscheme| and the +// implementation should return `kSbMediaSupportTypeNotSupported` when +// |encryptionscheme| is set to "". +// The implementation should return `kSbMediaSupportTypeNotSupported` for +// unknown values of known attributes. For example, if an implementation +// supports "encryptionscheme" with value "cenc", "cbcs", or "cbcs-1-9", then +// it should return `kSbMediaSupportTypeProbably` when |key_system| is +// |com.widevine.alpha; encryptionscheme="cenc"|, and return +// `kSbMediaSupportTypeNotSupported` when |key_system| is +// |com.widevine.alpha; encryptionscheme="invalid"|. +// If an implementation supports key system with attributes on one key system, +// it has to support key system with attributes on all key systems supported. SB_EXPORT SbMediaSupportType SbMediaCanPlayMimeAndKeySystem(const char* mime, const char* key_system);
diff --git a/src/starboard/nplb/drm_helpers.h b/src/starboard/nplb/drm_helpers.h index c24b696..e6b0972 100644 --- a/src/starboard/nplb/drm_helpers.h +++ b/src/starboard/nplb/drm_helpers.h
@@ -68,6 +68,10 @@ "com.youtube.fairplay", }; +static const char* kEncryptionSchemes[] = { + "cenc", "cbcs", "cbcs-1-9", +}; + } // namespace nplb } // namespace starboard
diff --git a/src/starboard/nplb/file_delete_test.cc b/src/starboard/nplb/file_delete_test.cc index ada20d8..cea7b61 100644 --- a/src/starboard/nplb/file_delete_test.cc +++ b/src/starboard/nplb/file_delete_test.cc
@@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// SbFileDelete is otherwise tested in all the other unit tests. - #include <string> #include "starboard/file.h" @@ -24,12 +22,29 @@ namespace nplb { namespace { -TEST(SbFileDeleteTest, NonExistentFileErrors) { - std::string filename = starboard::nplb::GetRandomFilename(); - EXPECT_FALSE(SbFileExists(filename.c_str())); +TEST(SbFileDeleteTest, SunnyDayDeleteExistingFile) { + ScopedRandomFile file; - bool result = SbFileDelete(filename.c_str()); - EXPECT_FALSE(result); + EXPECT_TRUE(SbFileExists(file.filename().c_str())); + EXPECT_TRUE(SbFileDelete(file.filename().c_str())); +} + +TEST(SbFileDeleteTest, SunnyDayDeleteExistingDirectory) { + ScopedRandomFile file(ScopedRandomFile::kDontCreate); + + const std::string& path = file.filename(); + + EXPECT_FALSE(SbFileExists(path.c_str())); + EXPECT_TRUE(SbDirectoryCreate(path.c_str())); + EXPECT_TRUE(SbDirectoryCanOpen(path.c_str())); + EXPECT_TRUE(SbFileDelete(path.c_str())); +} + +TEST(SbFileDeleteTest, RainyDayNonExistentFileErrors) { + ScopedRandomFile file(ScopedRandomFile::kDontCreate); + + EXPECT_FALSE(SbFileExists(file.filename().c_str())); + EXPECT_TRUE(SbFileDelete(file.filename().c_str())); } } // namespace
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 index 2e38c86..3003a56 100644 --- 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
@@ -14,14 +14,38 @@ #include "starboard/media.h" +#include "starboard/common/string.h" +#include "starboard/nplb/drm_helpers.h" #include "testing/gtest/include/gtest/gtest.h" namespace starboard { -namespace shared { -namespace starboard { -namespace media { +namespace nplb { namespace { +bool IsKeySystemWithAttributesSupported() { + for (auto key_system : kKeySystems) { + if (!SbMediaCanPlayMimeAndKeySystem("video/mp4; codecs=\"avc1.4d4015\"", + key_system)) { + continue; + } + + // The key system is supported, let's check if the implementation supports + // attributes. By definition, when an implementation supports key system + // with attributes, it should make the decision without any unknown + // attributes. So the following |key_system_with_invalid_attribute| should + // be supported on such implementation. + std::string key_system_with_invalid_attribute = key_system; + key_system_with_invalid_attribute += "; invalid_attribute=\"some_value\""; + if (SbMediaCanPlayMimeAndKeySystem( + "video/mp4; codecs=\"avc1.4d4015\"", + key_system_with_invalid_attribute.c_str())) { + return true; + } + } + + return false; +} + TEST(SbMediaCanPlayMimeAndKeySystem, SunnyDay) { // Vp9 SbMediaCanPlayMimeAndKeySystem( @@ -89,14 +113,121 @@ "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"); + // Invalid key system + result = SbMediaCanPlayMimeAndKeySystem("video/mp4; codecs=\"avc1.4d4015\"", + "abc"); + ASSERT_EQ(result, kSbMediaSupportTypeNotSupported); + result = SbMediaCanPlayMimeAndKeySystem("video/mp4; codecs=\"avc1.4d4015\"", + "widevine"); + ASSERT_EQ(result, kSbMediaSupportTypeNotSupported); + result = SbMediaCanPlayMimeAndKeySystem("video/mp4; codecs=\"avc1.4d4015\"", + "com.widevine.alpha.invalid"); + ASSERT_EQ(result, kSbMediaSupportTypeNotSupported); + result = SbMediaCanPlayMimeAndKeySystem("video/mp4; codecs=\"avc1.4d4015\"", + "playready"); + ASSERT_EQ(result, kSbMediaSupportTypeNotSupported); + result = SbMediaCanPlayMimeAndKeySystem("video/mp4; codecs=\"avc1.4d4015\"", + "com.youtube.playready.invalid"); + ASSERT_EQ(result, kSbMediaSupportTypeNotSupported); + result = SbMediaCanPlayMimeAndKeySystem("video/mp4; codecs=\"avc1.4d4015\"", + "fairplay"); + ASSERT_EQ(result, kSbMediaSupportTypeNotSupported); + result = SbMediaCanPlayMimeAndKeySystem("video/mp4; codecs=\"avc1.4d4015\"", + "com.youtube.fairplay.invalid"); ASSERT_EQ(result, kSbMediaSupportTypeNotSupported); } +TEST(SbMediaCanPlayMimeAndKeySystem, MinimumSupport) { + // H.264 Main Profile Level 4.2 + SbMediaSupportType result = SbMediaCanPlayMimeAndKeySystem( + "video/mp4; codecs=\"avc1.4d402a\"; width=1920; height=1080; " + "framerate=30;", + ""); + ASSERT_EQ(result, kSbMediaSupportTypeProbably); + + result = SbMediaCanPlayMimeAndKeySystem( + "video/mp4; codecs=\"avc1.4d402a\"; width=1920; height=1080; " + "framerate=60;", + ""); + ASSERT_EQ(result, kSbMediaSupportTypeProbably); + + // H.264 Main Profile Level 2.1 + result = SbMediaCanPlayMimeAndKeySystem( + "video/mp4; codecs=\"avc1.4d4015\"; width=432; height=240; " + "framerate=15;", + ""); + ASSERT_EQ(result, kSbMediaSupportTypeProbably); + + // AAC-LC + result = SbMediaCanPlayMimeAndKeySystem( + "audio/mp4; codecs=\"mp4a.40.2\"; channels=2; bitrate=256;", ""); + ASSERT_EQ(result, kSbMediaSupportTypeProbably); + + // HE-AAC + result = SbMediaCanPlayMimeAndKeySystem( + "audio/mp4; codecs=\"mp4a.40.5\"; channels=2; bitrate=48;", ""); + ASSERT_EQ(result, kSbMediaSupportTypeProbably); +} + +TEST(SbMediaCanPlayMimeAndKeySystem, AnySupportedKeySystems) { + bool any_supported_key_systems = false; + for (auto key_system : kKeySystems) { + if (SbMediaCanPlayMimeAndKeySystem("video/mp4; codecs=\"avc1.4d4015\"", + key_system)) { + any_supported_key_systems = true; + break; + } + } + ASSERT_TRUE(any_supported_key_systems); +} + +TEST(SbMediaCanPlayMimeAndKeySystem, KeySystemWithAttributes) { + if (!IsKeySystemWithAttributesSupported()) { + SB_LOG(INFO) << "KeySystemWithAttributes test skipped because key system" + << " with attribute is not supported."; + return; + } + + for (auto key_system : kKeySystems) { + if (!SbMediaCanPlayMimeAndKeySystem("video/mp4; codecs=\"avc1.4d4015\"", + key_system)) { + continue; + } + + EXPECT_TRUE(SbMediaCanPlayMimeAndKeySystem( + "video/mp4; codecs=\"avc1.4d4015\"", + FormatString("%s; %s=\"%s\"", key_system, "invalid_attribute", + "some_value") + .c_str())); + + // "" is not a valid value for "encryptionscheme". + EXPECT_FALSE(SbMediaCanPlayMimeAndKeySystem( + "video/mp4; codecs=\"avc1.4d4015\"", + FormatString("%s; %s=\"%s\"", key_system, "encryptionscheme", "") + .c_str())); + + bool has_supported_encryption_scheme = false; + for (auto encryption_scheme : kEncryptionSchemes) { + if (!SbMediaCanPlayMimeAndKeySystem( + "video/mp4; codecs=\"avc1.4d4015\"", + FormatString("%s; %s=\"%s\"", key_system, "encryptionscheme", + encryption_scheme) + .c_str())) { + continue; + } + has_supported_encryption_scheme = true; + EXPECT_TRUE(SbMediaCanPlayMimeAndKeySystem( + "video/mp4; codecs=\"avc1.4d4015\"", + FormatString("%s; %s=\"%s\"; %s=\"%s\"", key_system, + "encryptionscheme", encryption_scheme, + "invalid_attribute", "some_value") + .c_str())); + } + + ASSERT_TRUE(has_supported_encryption_scheme); + } +} + } // namespace -} // namespace media -} // namespace starboard -} // namespace shared +} // namespace nplb } // namespace starboard
diff --git a/src/starboard/nplb/mutex_acquire_test.cc b/src/starboard/nplb/mutex_acquire_test.cc index c37a465..81ad198 100644 --- a/src/starboard/nplb/mutex_acquire_test.cc +++ b/src/starboard/nplb/mutex_acquire_test.cc
@@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" #include "starboard/configuration.h" +#include "starboard/mutex.h" #include "starboard/thread.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/src/starboard/nplb/mutex_acquire_try_test.cc b/src/starboard/nplb/mutex_acquire_try_test.cc index ccd7e5b..e38e897 100644 --- a/src/starboard/nplb/mutex_acquire_try_test.cc +++ b/src/starboard/nplb/mutex_acquire_try_test.cc
@@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" #include "starboard/configuration.h" +#include "starboard/mutex.h" #include "testing/gtest/include/gtest/gtest.h" #if SB_API_VERSION >= 12
diff --git a/src/starboard/nplb/mutex_create_test.cc b/src/starboard/nplb/mutex_create_test.cc index 8c11eaa..f52ba08 100644 --- a/src/starboard/nplb/mutex_create_test.cc +++ b/src/starboard/nplb/mutex_create_test.cc
@@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" #include "starboard/configuration.h" +#include "starboard/mutex.h" #include "testing/gtest/include/gtest/gtest.h" #if SB_API_VERSION >= 12
diff --git a/src/starboard/nplb/mutex_destroy_test.cc b/src/starboard/nplb/mutex_destroy_test.cc index e555b70..5df8a3a 100644 --- a/src/starboard/nplb/mutex_destroy_test.cc +++ b/src/starboard/nplb/mutex_destroy_test.cc
@@ -14,8 +14,8 @@ // Destroy is mostly Sunny Day tested in Create. -#include "starboard/common/mutex.h" #include "starboard/configuration.h" +#include "starboard/mutex.h" #include "testing/gtest/include/gtest/gtest.h" namespace starboard {
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp index 41f8971..ab22a51 100644 --- a/src/starboard/nplb/nplb.gyp +++ b/src/starboard/nplb/nplb.gyp
@@ -129,6 +129,7 @@ 'file_can_open_test.cc', 'file_close_test.cc', 'file_delete_recursive_test.cc', + 'file_delete_test.cc', 'file_get_info_test.cc', 'file_get_path_info_test.cc', 'file_helpers.cc', @@ -191,6 +192,7 @@ 'player_output_mode_supported_test.cc', 'player_test_util.cc', 'player_test_util.h', + 'player_write_sample_test.cc', 'random_helpers.cc', 'recursive_mutex_test.cc', 'rwlock_test.cc',
diff --git a/src/starboard/nplb/nplb_evergreen_compat_tests/storage_test.cc b/src/starboard/nplb/nplb_evergreen_compat_tests/storage_test.cc index 1214d7c..4cd5584 100644 --- a/src/starboard/nplb/nplb_evergreen_compat_tests/storage_test.cc +++ b/src/starboard/nplb/nplb_evergreen_compat_tests/storage_test.cc
@@ -15,9 +15,9 @@ #include <string> #include <vector> +#include "starboard/common/file.h" #include "starboard/common/log.h" #include "starboard/configuration.h" -#include "starboard/file.h" #include "starboard/memory.h" #include "starboard/nplb/nplb_evergreen_compat_tests/checks.h" #include "starboard/system.h"
diff --git a/src/starboard/nplb/player_test_util.cc b/src/starboard/nplb/player_test_util.cc index 88f8233..151cbdf 100644 --- a/src/starboard/nplb/player_test_util.cc +++ b/src/starboard/nplb/player_test_util.cc
@@ -14,12 +14,92 @@ #include "starboard/nplb/player_test_util.h" +#include <functional> + +#include "starboard/audio_sink.h" +#include "starboard/common/string.h" #include "starboard/directory.h" #include "starboard/nplb/player_creation_param_helpers.h" +#include "starboard/shared/starboard/player/video_dmp_reader.h" +#include "starboard/testing/fake_graphics_context_provider.h" namespace starboard { namespace nplb { +namespace { + +using shared::starboard::player::video_dmp::VideoDmpReader; +using std::placeholders::_1; +using std::placeholders::_2; +using std::placeholders::_3; +using std::placeholders::_4; +using testing::FakeGraphicsContextProvider; + +void ErrorFunc(SbPlayer player, + void* context, + SbPlayerError error, + const char* message) { + atomic_bool* error_occurred = static_cast<atomic_bool*>(context); + error_occurred->exchange(true); +} + +} // namespace + +std::vector<SbPlayerTestConfig> GetSupportedSbPlayerTestConfigs() { + const char* kAudioTestFiles[] = {"beneath_the_canopy_aac_stereo.dmp", + "beneath_the_canopy_aac_5_1.dmp", + "beneath_the_canopy_aac_mono.dmp", + "beneath_the_canopy_opus_5_1.dmp", + "beneath_the_canopy_opus_stereo.dmp", + "beneath_the_canopy_opus_mono.dmp", + "sintel_329_ec3.dmp", + "sintel_381_ac3.dmp", + "heaac.dmp"}; + + const char* kVideoTestFiles[] = {"beneath_the_canopy_137_avc.dmp", + "beneath_the_canopy_248_vp9.dmp", + "sintel_399_av1.dmp"}; + + const SbPlayerOutputMode kOutputModes[] = {kSbPlayerOutputModeDecodeToTexture, + kSbPlayerOutputModePunchOut}; + + std::vector<SbPlayerTestConfig> test_configs; + + const char* kEmptyName = NULL; + + for (auto audio_filename : kAudioTestFiles) { + VideoDmpReader dmp_reader(ResolveTestFileName(audio_filename).c_str()); + SB_DCHECK(dmp_reader.number_of_audio_buffers() > 0); + + const auto* audio_sample_info = &dmp_reader.audio_sample_info(); + if (IsMediaConfigSupported(kSbMediaVideoCodecNone, dmp_reader.audio_codec(), + kSbDrmSystemInvalid, audio_sample_info, + "", /* max_video_capabilities */ + kSbPlayerOutputModePunchOut)) { + test_configs.push_back(std::make_tuple(audio_filename, kEmptyName, + kSbPlayerOutputModePunchOut)); + } + } + + for (auto video_filename : kVideoTestFiles) { + VideoDmpReader dmp_reader(ResolveTestFileName(video_filename).c_str()); + SB_DCHECK(dmp_reader.number_of_video_buffers() > 0); + + for (auto output_mode : kOutputModes) { + if (IsMediaConfigSupported(dmp_reader.video_codec(), + kSbMediaAudioCodecNone, kSbDrmSystemInvalid, + NULL, /* audio_sample_info */ + "", /* max_video_capabilities */ + output_mode)) { + test_configs.push_back( + std::make_tuple(kEmptyName, video_filename, output_mode)); + } + } + } + + return test_configs; +} + std::string ResolveTestFileName(const char* filename) { std::vector<char> content_path(kSbFileMaxPath); SB_CHECK(SbSystemGetPath(kSbSystemPathContentDirectory, content_path.data(), @@ -45,10 +125,10 @@ SbPlayerDecoderState state, int ticket) {} -void DummyStatusFunc(SbPlayer player, - void* context, - SbPlayerState state, - int ticket) {} +void DummyPlayerStatusFunc(SbPlayer player, + void* context, + SbPlayerState state, + int ticket) {} void DummyErrorFunc(SbPlayer player, void* context, @@ -116,5 +196,30 @@ #endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT) } +bool IsMediaConfigSupported(SbMediaVideoCodec video_codec, + SbMediaAudioCodec audio_codec, + SbDrmSystem drm_system, + const SbMediaAudioSampleInfo* audio_sample_info, + const char* max_video_capabilities, + SbPlayerOutputMode output_mode) { + if (audio_codec != kSbMediaAudioCodecNone && + audio_sample_info->number_of_channels > SbAudioSinkGetMaxChannels()) { + return false; + } + + atomic_bool error_occurred; + FakeGraphicsContextProvider fake_graphics_context_provider; + SbPlayer player = CallSbPlayerCreate( + fake_graphics_context_provider.window(), video_codec, audio_codec, + drm_system, audio_sample_info, max_video_capabilities, + DummyDeallocateSampleFunc, DummyDecoderStatusFunc, DummyPlayerStatusFunc, + ErrorFunc, &error_occurred, output_mode, + fake_graphics_context_provider.decoder_target_provider()); + bool is_valid_player = SbPlayerIsValid(player); + SbPlayerDestroy(player); + + return is_valid_player && !error_occurred.load(); +} + } // namespace nplb } // namespace starboard
diff --git a/src/starboard/nplb/player_test_util.h b/src/starboard/nplb/player_test_util.h index 335e414..ece5faf 100644 --- a/src/starboard/nplb/player_test_util.h +++ b/src/starboard/nplb/player_test_util.h
@@ -16,6 +16,7 @@ #define STARBOARD_NPLB_PLAYER_TEST_UTIL_H_ #include <string> +#include <tuple> #include <vector> #include "starboard/configuration_constants.h" @@ -24,6 +25,13 @@ namespace starboard { namespace nplb { +typedef std::tuple<const char* /* audio_filename */, + const char* /* video_filename */, + SbPlayerOutputMode /* output_mode */> + SbPlayerTestConfig; + +std::vector<SbPlayerTestConfig> GetSupportedSbPlayerTestConfigs(); + std::string ResolveTestFileName(const char* filename); void DummyDeallocateSampleFunc(SbPlayer player, @@ -64,6 +72,13 @@ bool IsOutputModeSupported(SbPlayerOutputMode output_mode, SbMediaVideoCodec codec); +bool IsMediaConfigSupported(SbMediaVideoCodec video_codec, + SbMediaAudioCodec audio_codec, + SbDrmSystem drm_system, + const SbMediaAudioSampleInfo* audio_sample_info, + const char* max_video_capabilities, + SbPlayerOutputMode output_mode); + } // namespace nplb } // namespace starboard
diff --git a/src/starboard/nplb/player_write_sample_test.cc b/src/starboard/nplb/player_write_sample_test.cc new file mode 100644 index 0000000..13977ee --- /dev/null +++ b/src/starboard/nplb/player_write_sample_test.cc
@@ -0,0 +1,520 @@ +// 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 <deque> +#include <functional> + +#include "starboard/atomic.h" +#include "starboard/common/optional.h" +#include "starboard/common/queue.h" +#include "starboard/common/scoped_ptr.h" +#include "starboard/common/string.h" +#include "starboard/nplb/player_test_util.h" +#include "starboard/shared/starboard/player/video_dmp_reader.h" +#include "starboard/string.h" +#include "starboard/testing/fake_graphics_context_provider.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +using shared::starboard::player::video_dmp::VideoDmpReader; +using testing::FakeGraphicsContextProvider; +using ::testing::ValuesIn; + +const SbTimeMonotonic kDefaultWaitForDecoderStateNeedsDataTimeout = + 5 * kSbTimeSecond; +const SbTimeMonotonic kDefaultWaitForPlayerStateTimeout = 5 * kSbTimeSecond; +const SbTimeMonotonic kDefaultWaitForCallbackEventTimeout = + 15 * kSbTimeMillisecond; + +class SbPlayerWriteSampleTest + : public ::testing::TestWithParam<SbPlayerTestConfig> { + public: + SbPlayerWriteSampleTest(); + + void SetUp() override; + void TearDown() override; + + protected: + struct CallbackEvent { + CallbackEvent() {} + + CallbackEvent(SbPlayer player, SbPlayerState state, int ticket) + : player(player), player_state(state), ticket(ticket) {} + + CallbackEvent(SbPlayer player, SbPlayerDecoderState state, int ticket) + : player(player), decoder_state(state), ticket(ticket) {} + + bool HasStateUpdate() const { + return player_state.has_engaged() || decoder_state.has_engaged(); + } + + SbPlayer player = kSbPlayerInvalid; + optional<SbPlayerState> player_state; + optional<SbPlayerDecoderState> decoder_state; + int ticket = SB_PLAYER_INITIAL_TICKET; + }; + + static void DecoderStatusCallback(SbPlayer player, + void* context, + SbMediaType type, + SbPlayerDecoderState state, + int ticket); + + static void PlayerStatusCallback(SbPlayer player, + void* context, + SbPlayerState state, + int ticket); + + static void ErrorCallback(SbPlayer player, + void* context, + SbPlayerError error, + const char* message); + + void InitializePlayer(); + + void PrepareForSeek(); + + void Seek(const SbTime time); + + // When the |output_mode| is decoding to texture, then this method is used to + // advance the decoded frames. + void GetDecodeTargetWhenSupported(); + + // Callback methods from the underlying player. + void OnDecoderState(SbPlayer player, + SbMediaType media_type, + SbPlayerDecoderState state, + int ticket); + void OnPlayerState(SbPlayer player, SbPlayerState state, int ticket); + void OnError(SbPlayer player, SbPlayerError error, const char* message); + + // Waits for |kSbPlayerDecoderStateNeedsData| to be sent. + void WaitForDecoderStateNeedsData( + const SbTime timeout = kDefaultWaitForDecoderStateNeedsDataTimeout); + + // Waits for desired player state update to be sent. + void WaitForPlayerState( + const SbPlayerState desired_state, + const SbTime timeout = kDefaultWaitForPlayerStateTimeout); + + // Player and Decoder methods for driving input and output. + void WriteSingleInput(size_t index); + void WriteEndOfStream(); + void WriteMultipleInputs(size_t start_index, size_t num_inputs_to_write); + void DrainOutputs(); + + int GetNumBuffers() const; + + SbMediaType GetTestMediaType() const { return test_media_type_; } + + // Determine if the the current event is valid based on previously received + // player state updates, or other inputs to the player. + void AssertPlayerStateIsValid(SbPlayerState state) const; + + bool HasReceivedPlayerState(SbPlayerState state) const { + return player_state_set_.find(state) != player_state_set_.end(); + } + + // Checks if there are pending callback events and, if so, logs the received + // state update in the appropriate tracking container: + // * |decoder_state_queue_| for SbPlayerDecoderState updates. + // * |player_state_set_| for SbPlayerState updates. + // Executes a blocking wait for any new CallbackEvents to be enqueued. + void TryProcessCallbackEvents(SbTime timeout); + + // Queue of events from the underlying player. + Queue<CallbackEvent> callback_event_queue_; + + // Ordered queue of pending decoder state updates. + std::deque<SbPlayerDecoderState> decoder_state_queue_; + + // Set of received player state updates from the underlying player. This is + // used to check that the state updates occur in a valid order during normal + // playback. + std::set<SbPlayerState> player_state_set_; + + // Test instance specific configuration. + std::string dmp_filename_; + SbMediaType test_media_type_; + SbPlayerOutputMode output_mode_; + scoped_ptr<VideoDmpReader> dmp_reader_; + + FakeGraphicsContextProvider fake_graphics_context_provider_; + SbPlayer player_ = kSbPlayerInvalid; + + bool destroy_player_called_ = false; + bool end_of_stream_written_ = false; + atomic_bool error_occurred_; + int ticket_ = SB_PLAYER_INITIAL_TICKET; +}; + +SbPlayerWriteSampleTest::SbPlayerWriteSampleTest() { + const char* audio_filename = std::get<0>(GetParam()); + const char* video_filename = std::get<1>(GetParam()); + output_mode_ = std::get<2>(GetParam()); + + SB_DCHECK(output_mode_ != kSbPlayerOutputModeInvalid); + + if (audio_filename != NULL) { + SB_DCHECK(video_filename == NULL); + + dmp_filename_ = audio_filename; + test_media_type_ = kSbMediaTypeAudio; + } else { + SB_DCHECK(video_filename != NULL); + + dmp_filename_ = video_filename; + test_media_type_ = kSbMediaTypeVideo; + } + dmp_reader_.reset( + new VideoDmpReader(ResolveTestFileName(dmp_filename_.c_str()).c_str())); + + SB_LOG(INFO) << FormatString( + "Initialize SbPlayerWriteSampleTest with dmp file '%s' and with output " + "mode '%s'.", + dmp_filename_.c_str(), + output_mode_ == kSbPlayerOutputModeDecodeToTexture ? "Decode To Texture" + : "Punchout"); +} + +void SbPlayerWriteSampleTest::SetUp() { + SbMediaVideoCodec video_codec = dmp_reader_->video_codec(); + SbMediaAudioCodec audio_codec = dmp_reader_->audio_codec(); + const SbMediaAudioSampleInfo* audio_sample_info = NULL; + + if (test_media_type_ == kSbMediaTypeAudio) { + SB_DCHECK(audio_codec != kSbMediaAudioCodecNone); + + audio_sample_info = &dmp_reader_->audio_sample_info(); + video_codec = kSbMediaVideoCodecNone; + } else { + SB_DCHECK(video_codec != kSbMediaVideoCodecNone); + + audio_codec = kSbMediaAudioCodecNone; + } + + player_ = CallSbPlayerCreate( + fake_graphics_context_provider_.window(), video_codec, audio_codec, + kSbDrmSystemInvalid, audio_sample_info, "", DummyDeallocateSampleFunc, + DecoderStatusCallback, PlayerStatusCallback, ErrorCallback, this, + output_mode_, fake_graphics_context_provider_.decoder_target_provider()); + + ASSERT_TRUE(SbPlayerIsValid(player_)); + + InitializePlayer(); +} + +void SbPlayerWriteSampleTest::TearDown() { + SB_DCHECK(SbPlayerIsValid(player_)); + + ASSERT_FALSE(destroy_player_called_); + destroy_player_called_ = true; + SbPlayerDestroy(player_); + + // We expect the event to be sent already. + ASSERT_NO_FATAL_FAILURE(WaitForPlayerState(kSbPlayerStateDestroyed, 0)); + ASSERT_FALSE(error_occurred_.load()); +} + +// static +void SbPlayerWriteSampleTest::DecoderStatusCallback(SbPlayer player, + void* context, + SbMediaType type, + SbPlayerDecoderState state, + int ticket) { + SbPlayerWriteSampleTest* sb_player_write_sample_test = + static_cast<SbPlayerWriteSampleTest*>(context); + sb_player_write_sample_test->OnDecoderState(player, type, state, ticket); +} + +// static +void SbPlayerWriteSampleTest::PlayerStatusCallback(SbPlayer player, + void* context, + SbPlayerState state, + int ticket) { + SbPlayerWriteSampleTest* sb_player_write_sample_test = + static_cast<SbPlayerWriteSampleTest*>(context); + sb_player_write_sample_test->OnPlayerState(player, state, ticket); +} + +// static +void SbPlayerWriteSampleTest::ErrorCallback(SbPlayer player, + void* context, + SbPlayerError error, + const char* message) { + SbPlayerWriteSampleTest* sb_player_write_sample_test = + static_cast<SbPlayerWriteSampleTest*>(context); + sb_player_write_sample_test->OnError(player, error, message); +} + +void SbPlayerWriteSampleTest::InitializePlayer() { + ASSERT_FALSE(destroy_player_called_); + ASSERT_NO_FATAL_FAILURE(WaitForPlayerState(kSbPlayerStateInitialized)); + Seek(0); + SbPlayerSetPlaybackRate(player_, 1.0); + SbPlayerSetVolume(player_, 1.0); +} + +void SbPlayerWriteSampleTest::PrepareForSeek() { + ASSERT_FALSE(destroy_player_called_); + ASSERT_FALSE(HasReceivedPlayerState(kSbPlayerStateDestroyed)); + ASSERT_TRUE(HasReceivedPlayerState(kSbPlayerStateInitialized)); + player_state_set_.clear(); + player_state_set_.insert(kSbPlayerStateInitialized); + ticket_++; +} + +void SbPlayerWriteSampleTest::Seek(const SbTime time) { + PrepareForSeek(); + SbPlayerSeek2(player_, time, ticket_); + ASSERT_NO_FATAL_FAILURE(WaitForDecoderStateNeedsData()); + ASSERT_TRUE(decoder_state_queue_.empty()); +} + +void SbPlayerWriteSampleTest::GetDecodeTargetWhenSupported() { + if (destroy_player_called_) { + return; + } +#if SB_HAS(GLES2) + fake_graphics_context_provider_.RunOnGlesContextThread([&]() { + ASSERT_TRUE(SbPlayerIsValid(player_)); + if (output_mode_ != kSbPlayerOutputModeDecodeToTexture) { +#if SB_API_VERSION >= 12 + ASSERT_EQ(SbPlayerGetCurrentFrame(player_), kSbDecodeTargetInvalid); +#endif // SB_API_VERSION >= 12 + return; + } + ASSERT_EQ(output_mode_, kSbPlayerOutputModeDecodeToTexture); + SbDecodeTarget frame = SbPlayerGetCurrentFrame(player_); + if (SbDecodeTargetIsValid(frame)) { + SbDecodeTargetRelease(frame); + } + }); +#endif // SB_HAS(GLES2) +} + +void SbPlayerWriteSampleTest::OnDecoderState(SbPlayer player, + SbMediaType type, + SbPlayerDecoderState state, + int ticket) { + switch (state) { + case kSbPlayerDecoderStateNeedsData: + callback_event_queue_.Put(CallbackEvent(player, state, ticket)); + break; +#if SB_API_VERSION < 12 + // Note: we do not add these events to the queue since these states are not + // used in Cobalt and are being deprecated. + case kSbPlayerDecoderStateBufferFull: + case kSbPlayerDecoderStateDestroyed: + break; +#endif // SB_API_VERSION < 12 + } +} + +void SbPlayerWriteSampleTest::OnPlayerState(SbPlayer player, + SbPlayerState state, + int ticket) { + callback_event_queue_.Put(CallbackEvent(player, state, ticket)); +} + +void SbPlayerWriteSampleTest::OnError(SbPlayer player, + SbPlayerError error, + const char* message) { + SB_LOG(ERROR) << FormatString("Got SbPlayerError %d with message '%s'", error, + message != NULL ? message : ""); + error_occurred_.exchange(true); +} + +void SbPlayerWriteSampleTest::WaitForDecoderStateNeedsData( + const SbTime timeout) { + optional<SbPlayerDecoderState> received_state; + SbTimeMonotonic start = SbTimeGetMonotonicNow(); + do { + ASSERT_FALSE(error_occurred_.load()); + GetDecodeTargetWhenSupported(); + ASSERT_NO_FATAL_FAILURE(TryProcessCallbackEvents( + std::min(timeout, kDefaultWaitForCallbackEventTimeout))); + if (decoder_state_queue_.empty()) { + continue; + } + received_state = decoder_state_queue_.front(); + decoder_state_queue_.pop_front(); + if (received_state.value() == kSbPlayerDecoderStateNeedsData) { + break; + } + } while (SbTimeGetMonotonicNow() - start < timeout); + + ASSERT_TRUE(received_state.has_engaged()) << "Did not receive any states."; + ASSERT_EQ(kSbPlayerDecoderStateNeedsData, received_state.value()) + << "Did not receive expected state."; +} + +void SbPlayerWriteSampleTest::WaitForPlayerState( + const SbPlayerState desired_state, + const SbTime timeout) { + SbTimeMonotonic start = SbTimeGetMonotonicNow(); + do { + ASSERT_FALSE(error_occurred_.load()); + GetDecodeTargetWhenSupported(); + ASSERT_NO_FATAL_FAILURE(TryProcessCallbackEvents( + std::min(timeout, kDefaultWaitForCallbackEventTimeout))); + if (HasReceivedPlayerState(desired_state)) { + break; + } + } while (SbTimeGetMonotonicNow() - start < timeout); + ASSERT_TRUE(HasReceivedPlayerState(desired_state)) + << "Did not received expected state."; +} + +void SbPlayerWriteSampleTest::WriteSingleInput(size_t index) { + ASSERT_FALSE(destroy_player_called_); + ASSERT_LT(index, GetNumBuffers()); + SbPlayerSampleInfo sample_info = + dmp_reader_->GetPlayerSampleInfo(test_media_type_, index); + SbPlayerWriteSample2(player_, test_media_type_, &sample_info, 1); +} + +void SbPlayerWriteSampleTest::WriteEndOfStream() { + ASSERT_FALSE(destroy_player_called_); + ASSERT_FALSE(end_of_stream_written_); + end_of_stream_written_ = true; + SbPlayerWriteEndOfStream(player_, test_media_type_); +} + +void SbPlayerWriteSampleTest::WriteMultipleInputs(size_t start_index, + size_t num_inputs_to_write) { + SB_DCHECK(num_inputs_to_write > 0); + SB_DCHECK(start_index < GetNumBuffers()); + + ASSERT_NO_FATAL_FAILURE(WriteSingleInput(start_index)); + ++start_index; + --num_inputs_to_write; + + while (num_inputs_to_write > 0 && start_index < GetNumBuffers()) { + ASSERT_NO_FATAL_FAILURE(WaitForDecoderStateNeedsData()); + ASSERT_NO_FATAL_FAILURE(WriteSingleInput(start_index)); + ++start_index; + --num_inputs_to_write; + } +} + +void SbPlayerWriteSampleTest::DrainOutputs() { + ASSERT_TRUE(end_of_stream_written_); + ASSERT_NO_FATAL_FAILURE(WaitForPlayerState(kSbPlayerStateEndOfStream)); + // We should not get any new decoder events after end of stream. + ASSERT_TRUE(decoder_state_queue_.empty()); +} + +int SbPlayerWriteSampleTest::GetNumBuffers() const { + return test_media_type_ == kSbMediaTypeAudio + ? dmp_reader_->number_of_audio_buffers() + : dmp_reader_->number_of_video_buffers(); +} + +void SbPlayerWriteSampleTest::AssertPlayerStateIsValid( + SbPlayerState state) const { + // Note: it is possible to receive the same state that has been previously + // received in the case of multiple Seek() calls. Prior to any Seek commands + // issued in this test, we should reset the |player_state_set_| member. + ASSERT_FALSE(HasReceivedPlayerState(state)); + + switch (state) { + case kSbPlayerStateInitialized: + // No other states have been received before getting Initialized. + ASSERT_TRUE(player_state_set_.empty()); + break; + case kSbPlayerStatePrerolling: + ASSERT_TRUE(HasReceivedPlayerState(kSbPlayerStateInitialized)); + ASSERT_FALSE(HasReceivedPlayerState(kSbPlayerStateDestroyed)); + break; + case kSbPlayerStatePresenting: + ASSERT_TRUE(HasReceivedPlayerState(kSbPlayerStatePrerolling)); + ASSERT_FALSE(HasReceivedPlayerState(kSbPlayerStateDestroyed)); + break; + case kSbPlayerStateEndOfStream: + ASSERT_TRUE(HasReceivedPlayerState(kSbPlayerStateInitialized)); + ASSERT_TRUE(HasReceivedPlayerState(kSbPlayerStatePrerolling)); + ASSERT_FALSE(HasReceivedPlayerState(kSbPlayerStateDestroyed)); + break; + case kSbPlayerStateDestroyed: + // Nothing stops the user of the player from destroying the player during + // any of the previous states. + ASSERT_TRUE(destroy_player_called_); + break; + } +} + +void SbPlayerWriteSampleTest::TryProcessCallbackEvents(SbTime timeout) { + for (;;) { + auto event = callback_event_queue_.GetTimed(timeout); + if (!event.HasStateUpdate()) { + break; + } + if (event.ticket != ticket_) { + continue; + } + ASSERT_EQ(event.player, player_); + SB_DCHECK(event.decoder_state.has_engaged() ^ + event.player_state.has_engaged()); + if (event.decoder_state.has_engaged()) { + // Callbacks may be in-flight at the time that the player is destroyed by + // a call to |SbPlayerDestroy|. In this case, the callbacks are ignored. + // However no new callbacks are expected after receiving the player status + // |kSbPlayerStateDestroyed|. + ASSERT_FALSE(HasReceivedPlayerState(kSbPlayerStateDestroyed)); + decoder_state_queue_.push_back(event.decoder_state.value()); + continue; + } + ASSERT_NO_FATAL_FAILURE( + AssertPlayerStateIsValid(event.player_state.value())); + player_state_set_.insert(event.player_state.value()); + } +} + +TEST_P(SbPlayerWriteSampleTest, SeekAndDestroy) { + PrepareForSeek(); + SbPlayerSeek2(player_, 1 * kSbTimeSecond, ticket_); +} + +TEST_P(SbPlayerWriteSampleTest, NoInput) { + WriteEndOfStream(); + DrainOutputs(); +} + +TEST_P(SbPlayerWriteSampleTest, SingleInput) { + ASSERT_NO_FATAL_FAILURE(WriteSingleInput(0)); + ASSERT_NO_FATAL_FAILURE(WaitForDecoderStateNeedsData()); + WriteEndOfStream(); + DrainOutputs(); +} + +TEST_P(SbPlayerWriteSampleTest, MultipleInputs) { + ASSERT_NO_FATAL_FAILURE( + WriteMultipleInputs(0, std::min<size_t>(10, GetNumBuffers()))); + ASSERT_NO_FATAL_FAILURE(WaitForDecoderStateNeedsData()); + WriteEndOfStream(); + DrainOutputs(); +} + +INSTANTIATE_TEST_CASE_P(SbPlayerWriteSampleTests, + SbPlayerWriteSampleTest, + ValuesIn(GetSupportedSbPlayerTestConfigs())); + +} // namespace +} // namespace nplb +} // namespace starboard
diff --git a/src/starboard/nplb/system_get_path_test.cc b/src/starboard/nplb/system_get_path_test.cc index 7231d01..55ca991 100644 --- a/src/starboard/nplb/system_get_path_test.cc +++ b/src/starboard/nplb/system_get_path_test.cc
@@ -16,9 +16,9 @@ #include <algorithm> +#include "starboard/common/file.h" #include "starboard/common/string.h" #include "starboard/configuration_constants.h" -#include "starboard/file.h" #include "starboard/memory.h" #include "starboard/nplb/file_helpers.h" #include "starboard/system.h"
diff --git a/src/starboard/raspi/shared/gyp_configuration.gypi b/src/starboard/raspi/shared/gyp_configuration.gypi index deb191c..d2dd46b 100644 --- a/src/starboard/raspi/shared/gyp_configuration.gypi +++ b/src/starboard/raspi/shared/gyp_configuration.gypi
@@ -76,7 +76,8 @@ # libraries. '-L<(sysroot)/opt/vc/lib', '-Wl,-rpath=<(sysroot)/opt/vc/lib', - + # Cleanup unused sections + '-Wl,-gc-sections', # We don't wrap these symbols, but this ensures that they aren't # linked in. '-Wl,--wrap=malloc', @@ -107,9 +108,15 @@ ], 'compiler_flags_qa_size': [ '-Os', + # Compile symbols in separate sections + '-ffunction-sections', + '-fdata-sections', ], 'compiler_flags_qa_speed': [ '-O2', + # Compile symbols in separate sections + '-ffunction-sections', + '-fdata-sections', ], 'compiler_flags_cc_qa': [ '-fno-rtti', @@ -119,9 +126,15 @@ ], 'compiler_flags_gold_size': [ '-Os', + # Compile symbols in separate sections + '-ffunction-sections', + '-fdata-sections', ], 'compiler_flags_gold_speed': [ '-O2', + # Compile symbols in separate sections + '-ffunction-sections', + '-fdata-sections', ], 'compiler_flags_cc_gold': [ '-fno-rtti',
diff --git a/src/starboard/raspi/shared/gyp_configuration.py b/src/starboard/raspi/shared/gyp_configuration.py index b13b62e..faacb40 100644 --- a/src/starboard/raspi/shared/gyp_configuration.py +++ b/src/starboard/raspi/shared/gyp_configuration.py
@@ -72,18 +72,22 @@ self.host_compiler_environment = build.GetHostCompilerEnvironment( clang_specification.GetClangSpecification(), self.build_accelerator) - toolchain = os.path.realpath(os.path.join( - self.raspi_home, - 'tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64')) + toolchain = os.path.realpath( + os.path.join( + self.raspi_home, + 'tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64')) toolchain_bin_dir = os.path.join(toolchain, 'bin') env_variables = self.host_compiler_environment env_variables.update({ - 'CC': self.build_accelerator + ' ' + os.path.join(toolchain_bin_dir, - 'arm-linux-gnueabihf-gcc'), - 'CXX': self.build_accelerator + ' ' + os.path.join(toolchain_bin_dir, - 'arm-linux-gnueabihf-g++'), - 'STRIP': os.path.join(toolchain_bin_dir, 'arm-linux-gnueabihf-strip'), + 'CC': + self.build_accelerator + ' ' + + os.path.join(toolchain_bin_dir, 'arm-linux-gnueabihf-gcc'), + 'CXX': + self.build_accelerator + ' ' + + os.path.join(toolchain_bin_dir, 'arm-linux-gnueabihf-g++'), + 'STRIP': + os.path.join(toolchain_bin_dir, 'arm-linux-gnueabihf-strip'), }) return env_variables @@ -152,6 +156,9 @@ __FILTERED_TESTS = { # pylint: disable=invalid-name 'nplb': [ 'SbDrmTest.AnySupportedKeySystems', + 'SbMediaCanPlayMimeAndKeySystem.AnySupportedKeySystems', + 'SbMediaCanPlayMimeAndKeySystem.KeySystemWithAttributes', + 'SbMediaCanPlayMimeAndKeySystem.MinimumSupport', ], 'player_filter_tests': [ # The implementations for the raspberry pi (0 and 2) are incomplete
diff --git a/src/starboard/raspi/shared/system_get_property.cc b/src/starboard/raspi/shared/system_get_property.cc index 6fa8f5d..ac31872 100644 --- a/src/starboard/raspi/shared/system_get_property.cc +++ b/src/starboard/raspi/shared/system_get_property.cc
@@ -154,16 +154,8 @@ return CopyStringAndTestIfSuccess(out_value, value_length, kFriendlyName); case kSbSystemPropertyPlatformName: { - // Example output: "Raspian Linux armv7l". - utsname name; - - if (uname(&name) == -1) - return false; - - std::string temp = - starboard::FormatString("Raspian %s %s", name.sysname, name.machine); - - return CopyStringAndTestIfSuccess(out_value, value_length, temp.c_str()); + return CopyStringAndTestIfSuccess(out_value, value_length, + "X11; Linux armv7l"); } default:
diff --git a/src/starboard/shared/linux/system_get_used_cpu_memory.cc b/src/starboard/shared/linux/system_get_used_cpu_memory.cc index 5205355..3a7ad2e 100644 --- a/src/starboard/shared/linux/system_get_used_cpu_memory.cc +++ b/src/starboard/shared/linux/system_get_used_cpu_memory.cc
@@ -21,9 +21,9 @@ #include <sys/types.h> #include <unistd.h> +#include "starboard/common/file.h" #include "starboard/common/log.h" #include "starboard/common/string.h" -#include "starboard/file.h" // We find the current amount of used memory on Linux by opening // '/proc/self/status' and scan the file for its "VmRSS" and "VmSwap" entries.
diff --git a/src/starboard/shared/pthread/mutex_acquire.cc b/src/starboard/shared/pthread/mutex_acquire.cc index 67f26b4..6183f7d 100644 --- a/src/starboard/shared/pthread/mutex_acquire.cc +++ b/src/starboard/shared/pthread/mutex_acquire.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" +#include "starboard/mutex.h" #include <pthread.h>
diff --git a/src/starboard/shared/pthread/mutex_acquire_try.cc b/src/starboard/shared/pthread/mutex_acquire_try.cc index 4c216a5..8c5c241 100644 --- a/src/starboard/shared/pthread/mutex_acquire_try.cc +++ b/src/starboard/shared/pthread/mutex_acquire_try.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" +#include "starboard/mutex.h" #include <pthread.h>
diff --git a/src/starboard/shared/pthread/mutex_create.cc b/src/starboard/shared/pthread/mutex_create.cc index e72884d..55b6a94 100644 --- a/src/starboard/shared/pthread/mutex_create.cc +++ b/src/starboard/shared/pthread/mutex_create.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" +#include "starboard/mutex.h" #include <pthread.h>
diff --git a/src/starboard/shared/pthread/mutex_destroy.cc b/src/starboard/shared/pthread/mutex_destroy.cc index c131595..f2d0b15 100644 --- a/src/starboard/shared/pthread/mutex_destroy.cc +++ b/src/starboard/shared/pthread/mutex_destroy.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" +#include "starboard/mutex.h" #include <pthread.h>
diff --git a/src/starboard/shared/pthread/mutex_release.cc b/src/starboard/shared/pthread/mutex_release.cc index fcd7de7..d2ce183 100644 --- a/src/starboard/shared/pthread/mutex_release.cc +++ b/src/starboard/shared/pthread/mutex_release.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" +#include "starboard/mutex.h" #include <pthread.h>
diff --git a/src/starboard/shared/starboard/link_receiver.cc b/src/starboard/shared/starboard/link_receiver.cc index bb97f5d..d5ddadd 100644 --- a/src/starboard/shared/starboard/link_receiver.cc +++ b/src/starboard/shared/starboard/link_receiver.cc
@@ -18,13 +18,13 @@ #include <unordered_map> #include "starboard/atomic.h" +#include "starboard/common/file.h" #include "starboard/common/log.h" #include "starboard/common/scoped_ptr.h" #include "starboard/common/semaphore.h" #include "starboard/common/socket.h" #include "starboard/common/string.h" #include "starboard/configuration_constants.h" -#include "starboard/file.h" #include "starboard/shared/starboard/application.h" #include "starboard/socket_waiter.h" #include "starboard/system.h"
diff --git a/src/starboard/shared/starboard/localized_strings.cc b/src/starboard/shared/starboard/localized_strings.cc index 2d7fb02..838c4e4 100644 --- a/src/starboard/shared/starboard/localized_strings.cc +++ b/src/starboard/shared/starboard/localized_strings.cc
@@ -16,8 +16,8 @@ #include <algorithm> +#include "starboard/common/file.h" #include "starboard/common/log.h" -#include "starboard/file.h" #include "starboard/system.h" #include "starboard/types.h"
diff --git a/src/starboard/shared/starboard/media/codec_util.cc b/src/starboard/shared/starboard/media/codec_util.cc index 64a649b..7d192fd 100644 --- a/src/starboard/shared/starboard/media/codec_util.cc +++ b/src/starboard/shared/starboard/media/codec_util.cc
@@ -499,10 +499,10 @@ return true; } - // 6. Parse chroma subsampling, which we only support 01. + // 6. Parse chroma subsampling, which we only support 00 and 01. // Note that this value is not returned. int chroma; - if (!ReadTwoDigitDecimal(codec + 14, &chroma) || chroma != 1) { + if (!ReadTwoDigitDecimal(codec + 14, &chroma) || (chroma != 0 && chroma != 1)) { return false; }
diff --git a/src/starboard/shared/starboard/media/media_util.cc b/src/starboard/shared/starboard/media/media_util.cc index 9b721cb..3269d04 100644 --- a/src/starboard/shared/starboard/media/media_util.cc +++ b/src/starboard/shared/starboard/media/media_util.cc
@@ -373,8 +373,11 @@ } if (codecs.size() == 0) { - // This is a progressive query. We only support "video/mp4" in this case. - if (mime_type.type() == "video" && mime_type.subtype() == "mp4") { + // This happens when the H5 player is either querying for progressive + // playback support, or probing for generic mp4 support without specific + // codecs. We only support "audio/mp4" and "video/mp4" for these cases. + if ((mime_type.type() == "audio" || mime_type.type() == "video") && + mime_type.subtype() == "mp4") { return kSbMediaSupportTypeMaybe; } return kSbMediaSupportTypeNotSupported;
diff --git a/src/starboard/shared/starboard/player/file_cache_reader.h b/src/starboard/shared/starboard/player/file_cache_reader.h index c9e2a08..a32b222 100644 --- a/src/starboard/shared/starboard/player/file_cache_reader.h +++ b/src/starboard/shared/starboard/player/file_cache_reader.h
@@ -18,8 +18,8 @@ #include <string> #include <vector> +#include "starboard/common/file.h" #include "starboard/common/scoped_ptr.h" -#include "starboard/file.h" namespace starboard { namespace shared {
diff --git a/src/starboard/shared/starboard/player/filter/player_components.h b/src/starboard/shared/starboard/player/filter/player_components.h index 567c4a1..e4c0eef 100644 --- a/src/starboard/shared/starboard/player/filter/player_components.h +++ b/src/starboard/shared/starboard/player/filter/player_components.h
@@ -197,9 +197,10 @@ scoped_refptr<VideoRendererSink>* video_renderer_sink); // Check AudioRenderer ctor for more details on the parameters. - void GetAudioRendererParams(const CreationParameters& creation_parameters, - int* max_cached_frames, - int* min_frames_per_append) const; + virtual void GetAudioRendererParams( + const CreationParameters& creation_parameters, + int* max_cached_frames, + int* min_frames_per_append) const; private: SB_DISALLOW_COPY_AND_ASSIGN(Factory);
diff --git a/src/starboard/shared/starboard/player/filter/testing/file_cache_reader_test.cc b/src/starboard/shared/starboard/player/filter/testing/file_cache_reader_test.cc index 8506b7a..c8ac858 100644 --- a/src/starboard/shared/starboard/player/filter/testing/file_cache_reader_test.cc +++ b/src/starboard/shared/starboard/player/filter/testing/file_cache_reader_test.cc
@@ -18,8 +18,8 @@ #include <string> #include <vector> +#include "starboard/common/file.h" #include "starboard/configuration_constants.h" -#include "starboard/file.h" #include "starboard/memory.h" #include "starboard/shared/starboard/player/filter/testing/test_util.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.h b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.h index 1450b58..49dbd09 100644 --- a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.h +++ b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.h
@@ -86,7 +86,11 @@ SbPlayerOutputMode output_mode, bool using_stub_decoder); - ~VideoDecoderTestFixture() { video_decoder_->Reset(); } + ~VideoDecoderTestFixture() { + if (video_decoder_) { + video_decoder_->Reset(); + } + } void Initialize();
diff --git a/src/starboard/shared/starboard/player/video_dmp_reader.h b/src/starboard/shared/starboard/player/video_dmp_reader.h index 218384d..6770123 100644 --- a/src/starboard/shared/starboard/player/video_dmp_reader.h +++ b/src/starboard/shared/starboard/player/video_dmp_reader.h
@@ -19,6 +19,7 @@ #include <string> #include <vector> +#include "starboard/common/file.h" #include "starboard/common/log.h" #include "starboard/common/mutex.h" #include "starboard/common/optional.h"
diff --git a/src/starboard/shared/stub/mutex_acquire.cc b/src/starboard/shared/stub/mutex_acquire.cc index cede4d1..423202e 100644 --- a/src/starboard/shared/stub/mutex_acquire.cc +++ b/src/starboard/shared/stub/mutex_acquire.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" +#include "starboard/mutex.h" SbMutexResult SbMutexAcquire(SbMutex* mutex) { return kSbMutexDestroyed;
diff --git a/src/starboard/shared/stub/mutex_acquire_try.cc b/src/starboard/shared/stub/mutex_acquire_try.cc index a9f1ba8..efc87b6 100644 --- a/src/starboard/shared/stub/mutex_acquire_try.cc +++ b/src/starboard/shared/stub/mutex_acquire_try.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" +#include "starboard/mutex.h" SbMutexResult SbMutexAcquireTry(SbMutex* mutex) { return kSbMutexDestroyed;
diff --git a/src/starboard/shared/stub/mutex_create.cc b/src/starboard/shared/stub/mutex_create.cc index 11586de..4439ee0 100644 --- a/src/starboard/shared/stub/mutex_create.cc +++ b/src/starboard/shared/stub/mutex_create.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" +#include "starboard/mutex.h" bool SbMutexCreate(SbMutex* mutex) { return false;
diff --git a/src/starboard/shared/stub/mutex_destroy.cc b/src/starboard/shared/stub/mutex_destroy.cc index 7922ddd..b88ae22 100644 --- a/src/starboard/shared/stub/mutex_destroy.cc +++ b/src/starboard/shared/stub/mutex_destroy.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" +#include "starboard/mutex.h" bool SbMutexDestroy(SbMutex* mutex) { return false;
diff --git a/src/starboard/shared/stub/mutex_release.cc b/src/starboard/shared/stub/mutex_release.cc index 88e6071..207b642 100644 --- a/src/starboard/shared/stub/mutex_release.cc +++ b/src/starboard/shared/stub/mutex_release.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/mutex.h" +#include "starboard/mutex.h" bool SbMutexRelease(SbMutex* mutex) { return false;
diff --git a/src/starboard/shared/widevine/drm_system_widevine.cc b/src/starboard/shared/widevine/drm_system_widevine.cc index c3910d3..4a8eaf1 100644 --- a/src/starboard/shared/widevine/drm_system_widevine.cc +++ b/src/starboard/shared/widevine/drm_system_widevine.cc
@@ -26,6 +26,7 @@ #include "starboard/memory.h" #include "starboard/once.h" #include "starboard/shared/starboard/application.h" +#include "starboard/shared/starboard/media/mime_type.h" #include "starboard/shared/widevine/widevine_storage.h" #include "starboard/shared/widevine/widevine_timer.h" #include "starboard/time.h" @@ -40,7 +41,7 @@ namespace { const int kInitializationVectorSize = 16; -const char* kWidevineKeySystem[] = {"com.widevine", "com.widevine.alpha"}; +const char* kWidevineKeySystems[] = {"com.widevine", "com.widevine.alpha"}; const char kWidevineStorageFileName[] = "wvcdm.dat"; // Key usage may be blocked due to incomplete HDCP authentication which could @@ -264,8 +265,28 @@ // static bool DrmSystemWidevine::IsKeySystemSupported(const char* key_system) { - for (auto wv_key_system : kWidevineKeySystem) { - if (SbStringCompareAll(key_system, wv_key_system) == 0) { + SB_DCHECK(key_system); + + // It is possible that the |key_system| comes with extra attributes, like + // `com.widevine.alpha; encryptionscheme="cenc"`. We prepend "key_system/" + // to it, so it can be parsed by MimeType. + starboard::media::MimeType mime_type(std::string("key_system/") + key_system); + + if (!mime_type.is_valid()) { + return false; + } + SB_DCHECK(mime_type.type() == "key_system"); + + for (auto wv_key_system : kWidevineKeySystems) { + if (mime_type.subtype() == wv_key_system) { + for (int i = 0; i < mime_type.GetParamCount(); ++i) { + if (mime_type.GetParamName(i) == "encryptionscheme") { + auto value = mime_type.GetParamStringValue(i); + if (value != "cenc" && value != "cbcs" && value != "cbcs-1-9") { + return false; + } + } + } return true; } }
diff --git a/src/starboard/shared/widevine/widevine_storage.cc b/src/starboard/shared/widevine/widevine_storage.cc index 91819e7..d6c8a3d 100644 --- a/src/starboard/shared/widevine/widevine_storage.cc +++ b/src/starboard/shared/widevine/widevine_storage.cc
@@ -14,8 +14,8 @@ #include "starboard/shared/widevine/widevine_storage.h" +#include "starboard/common/file.h" #include "starboard/common/log.h" -#include "starboard/file.h" #include "starboard/shared/widevine/widevine_keybox_hash.h" #include "starboard/types.h"
diff --git a/src/starboard/shared/x11/application_x11.cc b/src/starboard/shared/x11/application_x11.cc index 5e78b9b..030a2ed 100644 --- a/src/starboard/shared/x11/application_x11.cc +++ b/src/starboard/shared/x11/application_x11.cc
@@ -41,6 +41,10 @@ #include "starboard/shared/x11/window_internal.h" #include "starboard/time.h" +namespace { +const char kTouchscreenPointerSwitch[] = "touchscreen_pointer"; +} + namespace starboard { namespace shared { namespace x11 { @@ -720,6 +724,7 @@ // evdev input will be sent to the first created window only. dev_input_.reset(DevInput::Create(window, ConnectionNumber(display_))); } + touchscreen_pointer_ = GetCommandLine()->HasSwitch(kTouchscreenPointerSwitch); return window; } @@ -1273,7 +1278,8 @@ data->key = XButtonEventToSbKey(x_button_event); data->type = is_press_event ? kSbInputEventTypePress : kSbInputEventTypeUnpress; - data->device_type = kSbInputDeviceTypeMouse; + data->device_type = touchscreen_pointer_ ? kSbInputDeviceTypeTouchScreen + : kSbInputDeviceTypeMouse; if (is_wheel_event) { data->pressure = NAN; data->size = {NAN, NAN}; @@ -1299,11 +1305,17 @@ data->size = {NAN, NAN}; data->tilt = {NAN, NAN}; data->type = kSbInputEventTypeMove; - data->device_type = kSbInputDeviceTypeMouse; + data->device_type = touchscreen_pointer_ ? kSbInputDeviceTypeTouchScreen + : kSbInputDeviceTypeMouse; data->device_id = kMouseDeviceId; data->key_modifiers = XEventStateToSbKeyModifiers(x_motion_event->state); data->position.x = x_motion_event->x; data->position.y = x_motion_event->y; + if (touchscreen_pointer_ && !data->key_modifiers) { + // For touch screens, only report motion events when a button is + // pressed. + return NULL; + } return new Event(kSbEventTypeInput, data.release(), &DeleteDestructor<SbInputData>); }
diff --git a/src/starboard/shared/x11/application_x11.h b/src/starboard/shared/x11/application_x11.h index 75934d3..875dd20 100644 --- a/src/starboard/shared/x11/application_x11.h +++ b/src/starboard/shared/x11/application_x11.h
@@ -155,6 +155,9 @@ // The /dev/input input handler. Only set when there is an open window. scoped_ptr<::starboard::shared::dev_input::DevInput> dev_input_; + + // Indicates whether pointer input is from a touchscreen. + bool touchscreen_pointer_; }; } // namespace x11
diff --git a/src/starboard/stub/configuration.gni b/src/starboard/stub/configuration.gni index 9babbcb..774ab8a 100644 --- a/src/starboard/stub/configuration.gni +++ b/src/starboard/stub/configuration.gni
@@ -18,9 +18,3 @@ # Use media source extension implementation that is conformed to the # Candidate Recommendation of July 5th 2016. cobalt_use_media_source_2016 = true - -declare_args() { - # Set to true to enable distributed compilation using Goma. By default we - # use Goma for stub and linux. - use_goma = true -}
diff --git a/src/starboard/tools/command_line.py b/src/starboard/tools/command_line.py index cecccb5..ddb4b32 100644 --- a/src/starboard/tools/command_line.py +++ b/src/starboard/tools/command_line.py
@@ -23,8 +23,18 @@ import starboard.tools.platform +def AddLoggingArguments(arg_parser): + arg_parser.add_argument( + '--log_level', + choices=['debug', 'warning', 'error', 'critical'], + default='info', + help='The minimum level a log statement must be to be output. This value ' + "is used to initialize the 'logging' module log level.") + + def AddPlatformConfigArguments(arg_parser): """Adds the platform configuration arguments required for building.""" + AddLoggingArguments(arg_parser) default_config, default_platform = build.GetDefaultConfigAndPlatform() arg_parser.add_argument( '-p',
diff --git a/src/starboard/tools/goma.py b/src/starboard/tools/goma.py deleted file mode 100644 index 183ff3f..0000000 --- a/src/starboard/tools/goma.py +++ /dev/null
@@ -1,130 +0,0 @@ -# -# 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. -# -"""Goma specific definitions and helper functions. - -Goma is used for faster builds. Install goma and add directory to PATH. -Provides common functions to setup goma across platform builds. -It checks that goma is enabled and installed, and starts the -goma proxy. - -Override settings using environment variables. -USE_GOMA To enable/disable goma. Default is None. -""" - -import logging -import os -import subprocess -import sys -import util - -from starboard.tools import build_accelerator - - -class Goma(build_accelerator.BuildAccelerator): - """Goma is a distributed build accelerator.""" - - def GetName(self): - return 'gomacc' - - def Use(self): - return FindAndStartGoma() - - -def _GomaEnabledFromEnv(): - """Enable goma if USE_GOMA is defined. - - Returns: - True to enable goma, defaults to False. - """ - if 'USE_GOMA' in os.environ: - return os.environ['USE_GOMA'] == '1' - return False - - -def _GetGomaFromPath(): - """Returns goma directory from PATH, otherwise is None.""" - gomacc_path = util.Which('gomacc') - if gomacc_path is not None: - return os.path.dirname(gomacc_path) - return None - - -def _GomaInstalled(goma_dir): - """Returns True if goma is installed, otherwise is False.""" - if goma_dir and os.path.isdir(goma_dir): - if os.path.isfile(GomaControlFile(goma_dir)): - logging.error('Using Goma installed at: %s', goma_dir) - return True - logging.error('Failed to find goma dir. Check PATH location: %s', goma_dir) - return False - - -def GomaControlFile(goma_dir): - """Returns path to goma control script.""" - return os.path.join(goma_dir, 'goma_ctl.py') - - -def _GomaEnsureStart(goma_dir): - """Starts the goma proxy. - - Checks the proxy status and tries to start if not running. - - Args: - goma_dir: goma install directory - - Returns: - True if goma started, otherwise False. - """ - if not _GomaInstalled(goma_dir): - return False - - goma_ctl = GomaControlFile(goma_dir) - command = [goma_ctl, 'ensure_start'] - logging.error('starting goma proxy...') - - try: - subprocess.check_call(command) - return True - except subprocess.CalledProcessError as e: - logging.error('Goma proxy failed to start.\nCommand: %s\n%s', - ' '.join(e.cmd), e.output) - return False - - -def FindAndStartGoma(enable_in_path=True, exit_on_failed_start=False): - """Uses goma if installed and proxy is running. - - Args: - enable_in_path: If True, enable goma if found in PATH. Otherwise, - it enables it when USE_GOMA=1 is set. - exit_on_failed_start: Boolean to exit if goma is enabled, but wasn't - started. - Returns: - True if goma is enabled and running, otherwise False. - """ - if enable_in_path or _GomaEnabledFromEnv(): - goma_dir = _GetGomaFromPath() - if _GomaEnsureStart(goma_dir): - return True - else: - logging.critical('goma was enabled, but failed to start.') - if exit_on_failed_start: - sys.exit(1) - return False - else: - logging.info('Goma is disabled. To enable, check for gomacc in PATH ' - 'and/or set USE_GOMA=1.') - return False
diff --git a/src/starboard/tools/log_level.py b/src/starboard/tools/log_level.py new file mode 100644 index 0000000..6bb05e0 --- /dev/null +++ b/src/starboard/tools/log_level.py
@@ -0,0 +1,49 @@ +#!/usr/bin/python +# +# 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. +"""Provides a consistent mechanism for the initialize of logging.""" + +import logging +import _env # pylint: disable=unused-import + +_NAME_TO_LEVEL = { + 'info': logging.INFO, + 'debug': logging.DEBUG, + 'warning': logging.WARNING, + 'error': logging.ERROR, + 'critical': logging.CRITICAL, +} + + +def InitializeLogging(args): + """Parses the provided argparse.Namespace to determine a logging level.""" + log_level = logging.INFO + + if args: + # Allow a 'verbose' flag to force |logging.DEBUG|. + if 'verbose' in args and args.verbose: + log_level = logging.DEBUG + elif 'log_level' in args: + log_level = _NAME_TO_LEVEL[args.log_level] + + InitializeLoggingWithLevel(log_level) + + +def InitializeLoggingWithLevel(log_level): + logging.basicConfig( + level=log_level, + format=('[%(process)d:%(asctime)s.%(msecs)03d...:' + '%(levelname)s:%(filename)s(%(lineno)s)] %(message)s'), + datefmt='%m-%d %H:%M')
diff --git a/src/starboard/tools/log_level_test.py b/src/starboard/tools/log_level_test.py new file mode 100755 index 0000000..8167c14 --- /dev/null +++ b/src/starboard/tools/log_level_test.py
@@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# 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. +# +"""Tests the log_level module.""" + +import argparse +import logging +import mock +import unittest +import _env # pylint: disable=unused-import +from starboard.tools import log_level + +_INITIALIZE_LOGGING_MOCK = 'starboard.tools.log_level.InitializeLoggingWithLevel' + + +class LogLevelTest(unittest.TestCase): + + @mock.patch(_INITIALIZE_LOGGING_MOCK) + def testRainyDayNoArgs(self, initialize_logging_mock): + log_level.InitializeLogging(None) + initialize_logging_mock.assert_called_with(logging.INFO) + + @mock.patch(_INITIALIZE_LOGGING_MOCK) + def testRainyDayEmptyArgs(self, initialize_logging_mock): + log_level.InitializeLogging(argparse.Namespace()) + initialize_logging_mock.assert_called_with(logging.INFO) + + @mock.patch(_INITIALIZE_LOGGING_MOCK) + def testSunnyDayCorrectLevels(self, initialize_logging_mock): + for name, level in log_level._NAME_TO_LEVEL.items(): + args = argparse.Namespace() + args.log_level = name + log_level.InitializeLogging(args) + initialize_logging_mock.assert_called_with(level) + + @mock.patch(_INITIALIZE_LOGGING_MOCK) + def testSunnyDayVerboseOverride(self, initialize_logging_mock): + args = argparse.Namespace() + args.verbose = True + log_level.InitializeLogging(args) + initialize_logging_mock.assert_called_with(logging.DEBUG) + + +if __name__ == '__main__': + unittest.main()
diff --git a/src/starboard/tools/toolchain/evergreen_linker.py b/src/starboard/tools/toolchain/evergreen_linker.py index a7bf4d7..04fdc19 100644 --- a/src/starboard/tools/toolchain/evergreen_linker.py +++ b/src/starboard/tools/toolchain/evergreen_linker.py
@@ -28,6 +28,7 @@ return shell.And('{0} ' '--build-id ' + '-gc-sections ' '-X ' '-v ' '--eh-frame-hdr '
diff --git a/src/starboard/ui_navigation.h b/src/starboard/ui_navigation.h index adb1193..6ff4137 100644 --- a/src/starboard/ui_navigation.h +++ b/src/starboard/ui_navigation.h
@@ -143,6 +143,11 @@ // kSbUiNavItemTypeFocus. Any previously focused navigation item should // receive the blur event. If the item is not transitively a content of the // root item, then this does nothing. +#if SB_API_VERSION >= SB_UI_NAVIGATION2_VERSION + // + // Specifying kSbUiNavItemInvalid should remove focus from the UI navigation + // system. +#endif void (*set_focus)(SbUiNavItem item); // This is used to enable or disable user interaction with the specified @@ -193,6 +198,11 @@ // the specified window. Navigation items are only interactable if they are // transitively attached to a window. // +#if SB_API_VERSION >= SB_UI_NAVIGATION2_VERSION + // The native UI engine should never change this navigation item's content + // offset. It is assumed to be used as a proxy for the system window. + // +#endif // A navigation item may only have a SbUiNavItem or SbWindow as its direct // container. The navigation item hierarchy is established using // set_item_container_item() with the root container attached to a SbWindow @@ -242,6 +252,13 @@ // Retrieve the current content offset for the navigation item. If |item| is // not a container, then the content offset is (0,0). +#if SB_API_VERSION >= SB_UI_NAVIGATION2_VERSION + // + // The native UI engine should not change the content offset of a container + // unless one of its contents (possibly recursively) is focused. This is to + // allow seemlessly disabling then re-enabling focus items without having + // their containers change offsets. +#endif void (*get_item_content_offset)(SbUiNavItem item, float* out_content_offset_x, float* out_content_offset_y);
diff --git a/src/testing/gtest/src/gtest.cc b/src/testing/gtest/src/gtest.cc index 7f0193b..50717b7 100644 --- a/src/testing/gtest/src/gtest.cc +++ b/src/testing/gtest/src/gtest.cc
@@ -37,6 +37,7 @@ #if GTEST_OS_STARBOARD #include "starboard/client_porting/eztime/eztime.h" +#include "starboard/common/file.h" #include "starboard/system.h" #else #include <ctype.h>
diff --git a/src/third_party/aom_includes/METATDATA b/src/third_party/aom_includes/METADATA similarity index 100% rename from src/third_party/aom_includes/METATDATA rename to src/third_party/aom_includes/METADATA
diff --git a/src/third_party/crashpad/client/crash_report_database.h b/src/third_party/crashpad/client/crash_report_database.h index cc4b8df..0739a9c 100644 --- a/src/third_party/crashpad/client/crash_report_database.h +++ b/src/third_party/crashpad/client/crash_report_database.h
@@ -404,6 +404,15 @@ //! \return The number of reports cleaned. virtual int CleanDatabase(time_t lockfile_ttl) { return 0; } + //! \brief Deletes the oldest crash reports and their associated metadata, + //! leaving only num_reports_to_keep left in the database. + //! + //! \param[in] num_reports_to_keep To number of most recent reports to leave + //! in the database. + //! + //! \return The operation status code. + virtual OperationStatus RemoveOldReports(int num_reports_to_keep) = 0; + protected: CrashReportDatabase() {}
diff --git a/src/third_party/crashpad/client/crash_report_database_generic.cc b/src/third_party/crashpad/client/crash_report_database_generic.cc index e90bfa6..e807f17 100644 --- a/src/third_party/crashpad/client/crash_report_database_generic.cc +++ b/src/third_party/crashpad/client/crash_report_database_generic.cc
@@ -18,7 +18,9 @@ #include <sys/stat.h> #include <sys/types.h> +#include <algorithm> #include <utility> +#include <vector> #include "base/logging.h" #include "build/build_config.h" @@ -191,6 +193,11 @@ } } +bool WasCreatedSooner(CrashReportDatabase::Report a, + CrashReportDatabase::Report b) { + return a.creation_time < b.creation_time; +} + } // namespace class CrashReportDatabaseGeneric : public CrashReportDatabase { @@ -218,6 +225,7 @@ OperationStatus DeleteReport(const UUID& uuid) override; OperationStatus RequestUpload(const UUID& uuid) override; int CleanDatabase(time_t lockfile_ttl) override; + OperationStatus RemoveOldReports(int num_reports_to_keep) override; // Build a filepath for the directory for the report to hold attachments. base::FilePath AttachmentsPath(const UUID& uuid); @@ -640,6 +648,32 @@ return removed; } +OperationStatus CrashReportDatabaseGeneric::RemoveOldReports( + int num_reports_to_keep) { + std::vector<CrashReportDatabase::Report> pending_reports; + std::vector<CrashReportDatabase::Report> completed_reports; + std::vector<CrashReportDatabase::Report> all_reports; + + GetPendingReports(&pending_reports); + GetCompletedReports(&completed_reports); + + all_reports.insert( + all_reports.end(), pending_reports.begin(), pending_reports.end()); + all_reports.insert( + all_reports.end(), completed_reports.begin(), completed_reports.end()); + std::sort(all_reports.begin(), all_reports.end(), WasCreatedSooner); + + while (all_reports.size() > num_reports_to_keep) { + OperationStatus os = DeleteReport((*all_reports.begin()).uuid); + if (os != kNoError) { + return os; + } + all_reports.erase(all_reports.begin()); + } + + return kNoError; +} + OperationStatus CrashReportDatabaseGeneric::RecordUploadAttempt( UploadReport* report, bool successful,
diff --git a/src/third_party/crashpad/client/crashpad_client.h b/src/third_party/crashpad/client/crashpad_client.h index e381b41..147b974 100644 --- a/src/third_party/crashpad/client/crashpad_client.h +++ b/src/third_party/crashpad/client/crashpad_client.h
@@ -388,6 +388,15 @@ //! //! \return `true` on success, `false` on failure with a message logged. static bool SendEvergreenInfoToHandler(EvergreenInfo evergreen_info); + + //! \brief Sends mapping info to the handler + //! + //! A handler must have already been installed before calling this method. + //! \param[in] annotations A EvergreenAnnotations struct, whose information + //! was created on Evergreen startup. + //! + //! \return `true` on success, `false` on failure with a message logged. + static bool SendAnnotationsToHandler(EvergreenAnnotations annotations); #endif //! \brief Requests that the handler capture a dump even though there hasn't
diff --git a/src/third_party/crashpad/client/crashpad_client_linux.cc b/src/third_party/crashpad/client/crashpad_client_linux.cc index 02a4e57..2435153 100644 --- a/src/third_party/crashpad/client/crashpad_client_linux.cc +++ b/src/third_party/crashpad/client/crashpad_client_linux.cc
@@ -141,6 +141,11 @@ evergreen_info_ = evergreen_info; return SendEvergreenInfoImpl(); } + + bool SendAnnotations(EvergreenAnnotations annotations) { + annotations_ = annotations; + return SendAnnotationsImpl(); + } #endif // The base implementation for all signal handlers, suitable for calling @@ -181,6 +186,7 @@ #if defined(STARBOARD) const EvergreenInfo& GetEvergreenInfo() { return evergreen_info_; } + const EvergreenAnnotations& GetAnnotations() { return annotations_; } #endif const ExceptionInformation& GetExceptionInfo() { @@ -189,6 +195,7 @@ #if defined(STARBOARD) virtual bool SendEvergreenInfoImpl() = 0; + virtual bool SendAnnotationsImpl() = 0; #endif virtual void HandleCrashImpl() = 0; @@ -211,6 +218,7 @@ #if defined(STARBOARD) EvergreenInfo evergreen_info_; + EvergreenAnnotations annotations_; #endif static SignalHandler* handler_; @@ -250,6 +258,7 @@ #if defined(STARBOARD) bool SendEvergreenInfoImpl() override { return false; } + bool SendAnnotationsImpl() override { return false; } #endif void HandleCrashImpl() override { @@ -353,6 +362,14 @@ client.SendEvergreenInfo(info); return true; } + + bool SendAnnotationsImpl() override { + ExceptionHandlerClient client(sock_to_handler_.get(), true); + ExceptionHandlerProtocol::ClientInformation info = {}; + info.annotations_address = FromPointerCast<VMAddress>(&GetAnnotations()); + client.SendAnnotations(info); + return true; + } #endif void HandleCrashImpl() override { @@ -576,6 +593,16 @@ return SignalHandler::Get()->SendEvergreenInfo(evergreen_info); } + +bool CrashpadClient::SendAnnotationsToHandler( + EvergreenAnnotations annotations) { + if (!SignalHandler::Get()) { + DLOG(ERROR) << "Crashpad isn't enabled"; + return false; + } + + return SignalHandler::Get()->SendAnnotations(annotations); +} #endif // static
diff --git a/src/third_party/crashpad/handler/crash_report_upload_thread.cc b/src/third_party/crashpad/handler/crash_report_upload_thread.cc index ac0f7c1..db960b1 100644 --- a/src/third_party/crashpad/handler/crash_report_upload_thread.cc +++ b/src/third_party/crashpad/handler/crash_report_upload_thread.cc
@@ -242,7 +242,7 @@ break; } #if defined(STARBOARD) - database_->DeleteReport(report.uuid); + database_->RemoveOldReports(/*num_reports_to_save=*/2); #endif }
diff --git a/src/third_party/crashpad/handler/linux/capture_snapshot.cc b/src/third_party/crashpad/handler/linux/capture_snapshot.cc index d792945..488bbba 100644 --- a/src/third_party/crashpad/handler/linux/capture_snapshot.cc +++ b/src/third_party/crashpad/handler/linux/capture_snapshot.cc
@@ -34,14 +34,15 @@ std::unique_ptr<ProcessSnapshotSanitized>* sanitized_snapshot #if defined(STARBOARD) , - VMAddress evergreen_information_address + VMAddress evergreen_information_address, + VMAddress annotations_address #endif ) { std::unique_ptr<ProcessSnapshotLinux> process_snapshot( new ProcessSnapshotLinux()); #if defined(STARBOARD) - if (!process_snapshot->Initialize(connection, - evergreen_information_address)) { + if (!process_snapshot->Initialize( + connection, evergreen_information_address, annotations_address)) { #else if (!process_snapshot->Initialize(connection)) { #endif
diff --git a/src/third_party/crashpad/handler/linux/capture_snapshot.h b/src/third_party/crashpad/handler/linux/capture_snapshot.h index d191b8b..51eca35 100644 --- a/src/third_party/crashpad/handler/linux/capture_snapshot.h +++ b/src/third_party/crashpad/handler/linux/capture_snapshot.h
@@ -67,7 +67,8 @@ std::unique_ptr<ProcessSnapshotSanitized>* sanitized_snapshot #if defined(STARBOARD) , - VMAddress evergreen_information_address + VMAddress evergreen_information_address, + VMAddress annotations_address #endif );
diff --git a/src/third_party/crashpad/handler/linux/crash_report_exception_handler.cc b/src/third_party/crashpad/handler/linux/crash_report_exception_handler.cc index 3a59dc7..b0f68ce 100644 --- a/src/third_party/crashpad/handler/linux/crash_report_exception_handler.cc +++ b/src/third_party/crashpad/handler/linux/crash_report_exception_handler.cc
@@ -86,6 +86,12 @@ evergreen_info_ = info.evergreen_information_address; return true; } + +bool CrashReportExceptionHandler::AddAnnotations( + const ExceptionHandlerProtocol::ClientInformation& info) { + annotations_address_ = info.annotations_address; + return true; +} #endif bool CrashReportExceptionHandler::HandleException( @@ -150,7 +156,8 @@ &sanitized_snapshot #if defined(STARBOARD) , - evergreen_info_ + evergreen_info_, + annotations_address_ #endif )) { return false;
diff --git a/src/third_party/crashpad/handler/linux/crash_report_exception_handler.h b/src/third_party/crashpad/handler/linux/crash_report_exception_handler.h index b5ea3f7..5cca2ad 100644 --- a/src/third_party/crashpad/handler/linux/crash_report_exception_handler.h +++ b/src/third_party/crashpad/handler/linux/crash_report_exception_handler.h
@@ -87,6 +87,8 @@ #if defined(STARBOARD) bool AddEvergreenInfo( const ExceptionHandlerProtocol::ClientInformation& info) override; + bool AddAnnotations( + const ExceptionHandlerProtocol::ClientInformation& info) override; #endif bool HandleExceptionWithBroker( @@ -120,6 +122,7 @@ const UserStreamDataSources* user_stream_data_sources_; // weak #if defined(STARBOARD) VMAddress evergreen_info_; + VMAddress annotations_address_; #endif DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler);
diff --git a/src/third_party/crashpad/handler/linux/exception_handler_server.cc b/src/third_party/crashpad/handler/linux/exception_handler_server.cc index d49cc1c..63215d5 100644 --- a/src/third_party/crashpad/handler/linux/exception_handler_server.cc +++ b/src/third_party/crashpad/handler/linux/exception_handler_server.cc
@@ -442,6 +442,8 @@ #if defined(STARBOARD) case ExceptionHandlerProtocol::ClientToServerMessage::kTypeAddEvergreenInfo: return HandleAddEvergreenInfoRequest(creds, message.client_info); + case ExceptionHandlerProtocol::ClientToServerMessage::kTypeAddAnnotations: + return HandleAddAnnotationsRequest(creds, message.client_info); #endif } @@ -456,6 +458,12 @@ const ExceptionHandlerProtocol::ClientInformation& client_info) { return delegate_->AddEvergreenInfo(client_info); } + +bool ExceptionHandlerServer::HandleAddAnnotationsRequest( + const ucred& creds, + const ExceptionHandlerProtocol::ClientInformation& client_info) { + return delegate_->AddAnnotations(client_info); +} #endif bool ExceptionHandlerServer::HandleCrashDumpRequest(
diff --git a/src/third_party/crashpad/handler/linux/exception_handler_server.h b/src/third_party/crashpad/handler/linux/exception_handler_server.h index 0f0e73c..1e87157 100644 --- a/src/third_party/crashpad/handler/linux/exception_handler_server.h +++ b/src/third_party/crashpad/handler/linux/exception_handler_server.h
@@ -102,6 +102,13 @@ //! \return `true` on success. `false` on failure with a message logged. virtual bool AddEvergreenInfo( const ExceptionHandlerProtocol::ClientInformation& info) = 0; + + //! \brief Called on receipt of a request to add Evergreen Annotations. + //! + //! \param[in] info Information on the client. + //! \return `true` on success. `false` on failure with a message logged. + virtual bool AddAnnotations( + const ExceptionHandlerProtocol::ClientInformation& info) = 0; #endif //! \brief Called on the receipt of a crash dump request from a client for a @@ -193,6 +200,9 @@ bool HandleAddEvergreenInfoRequest( const ucred& creds, const ExceptionHandlerProtocol::ClientInformation& client_info); + bool HandleAddAnnotationsRequest( + const ucred& creds, + const ExceptionHandlerProtocol::ClientInformation& client_info); #endif std::unordered_map<int, std::unique_ptr<Event>> clients_;
diff --git a/src/third_party/crashpad/snapshot/linux/process_snapshot_linux.cc b/src/third_party/crashpad/snapshot/linux/process_snapshot_linux.cc index 32ee101..a731187 100644 --- a/src/third_party/crashpad/snapshot/linux/process_snapshot_linux.cc +++ b/src/third_party/crashpad/snapshot/linux/process_snapshot_linux.cc
@@ -55,7 +55,8 @@ #if defined(STARBOARD) bool ProcessSnapshotLinux::Initialize(PtraceConnection* connection, - VMAddress evergreen_information_address) { + VMAddress evergreen_information_address, + VMAddress annotations_address) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); if (gettimeofday(&snapshot_time_, nullptr) != 0) { @@ -69,6 +70,15 @@ return false; } + EvergreenAnnotations annotations; + if (!memory_range_.Read( + annotations_address, sizeof(EvergreenAnnotations), &annotations)) { + LOG(ERROR) << "Could not read annotations"; + } else { + AddAnnotation("user_agent_string", + std::string(annotations.user_agent_string)); + } + system_.Initialize(&process_reader_, &snapshot_time_); InitializeThreads();
diff --git a/src/third_party/crashpad/snapshot/linux/process_snapshot_linux.h b/src/third_party/crashpad/snapshot/linux/process_snapshot_linux.h index 6c5d7a8..c78a709 100644 --- a/src/third_party/crashpad/snapshot/linux/process_snapshot_linux.h +++ b/src/third_party/crashpad/snapshot/linux/process_snapshot_linux.h
@@ -70,11 +70,14 @@ //! \param[in] connection A connection to the process to snapshot. //! \param[in] evergreen_information_address An address sent to the handler //! server that points to a populated EvergreenInfo struct. + //! \param[in] annotations_address An address sent to the handler server that + //! that points to a populated EvergreenAnnotations struct. //! //! \return `true` if the snapshot could be created, `false` otherwise with //! an appropriate message logged. bool Initialize(PtraceConnection* connnection, - VMAddress evergreen_information_address); + VMAddress evergreen_information_address, + VMAddress annotations_address); #endif //! \brief Finds the thread whose stack contains \a stack_address.
diff --git a/src/third_party/crashpad/util/linux/exception_handler_client.cc b/src/third_party/crashpad/util/linux/exception_handler_client.cc index b1df219..de27275 100644 --- a/src/third_party/crashpad/util/linux/exception_handler_client.cc +++ b/src/third_party/crashpad/util/linux/exception_handler_client.cc
@@ -89,6 +89,11 @@ const ExceptionHandlerProtocol::ClientInformation& info) { return SendEvergreenInfoRequest(info); } + +bool ExceptionHandlerClient::SendAnnotations( + const ExceptionHandlerProtocol::ClientInformation& info) { + return SendAddAnnotationsRequest(info); +} #endif int ExceptionHandlerClient::RequestCrashDump( @@ -161,6 +166,17 @@ UnixCredentialSocket::SendMsg(server_sock_, &message, sizeof(message)); return true; } + +bool ExceptionHandlerClient::SendAddAnnotationsRequest( + const ExceptionHandlerProtocol::ClientInformation& info) { + ExceptionHandlerProtocol::ClientToServerMessage message; + message.type = + ExceptionHandlerProtocol::ClientToServerMessage::kTypeAddAnnotations; + message.client_info = info; + + UnixCredentialSocket::SendMsg(server_sock_, &message, sizeof(message)); + return true; +} #endif int ExceptionHandlerClient::SendCrashDumpRequest(
diff --git a/src/third_party/crashpad/util/linux/exception_handler_client.h b/src/third_party/crashpad/util/linux/exception_handler_client.h index 3a27739..e2f6398 100644 --- a/src/third_party/crashpad/util/linux/exception_handler_client.h +++ b/src/third_party/crashpad/util/linux/exception_handler_client.h
@@ -57,6 +57,12 @@ //! \return `true` on success or `false` on failure. bool SendEvergreenInfo( const ExceptionHandlerProtocol::ClientInformation& info); + + //! \brief Sends EvergreenAnnotations to the ExceptionHandlerServer. + //! + //! \param[in] info Information to about this client. + //! \return `true` on success or `false` on failure. + bool SendAnnotations(const ExceptionHandlerProtocol::ClientInformation& info); #endif //! \brief Request a crash dump from the ExceptionHandlerServer. @@ -83,6 +89,9 @@ #if defined(STARBOARD) bool SendEvergreenInfoRequest( const ExceptionHandlerProtocol::ClientInformation& info); + + bool SendAddAnnotationsRequest( + const ExceptionHandlerProtocol::ClientInformation& info); #endif int SendCrashDumpRequest( const ExceptionHandlerProtocol::ClientInformation& info,
diff --git a/src/third_party/crashpad/util/linux/exception_handler_protocol.cc b/src/third_party/crashpad/util/linux/exception_handler_protocol.cc index 2220ecf..b139017 100644 --- a/src/third_party/crashpad/util/linux/exception_handler_protocol.cc +++ b/src/third_party/crashpad/util/linux/exception_handler_protocol.cc
@@ -25,7 +25,8 @@ #endif // OS_LINUX #if defined(STARBOARD) , - evergreen_information_address(0) + evergreen_information_address(0), + annotations_address(0) #endif { }
diff --git a/src/third_party/crashpad/util/linux/exception_handler_protocol.h b/src/third_party/crashpad/util/linux/exception_handler_protocol.h index 9edd82a..dbfaeca 100644 --- a/src/third_party/crashpad/util/linux/exception_handler_protocol.h +++ b/src/third_party/crashpad/util/linux/exception_handler_protocol.h
@@ -56,6 +56,10 @@ //! \brief The address in the client's address space of an EvergreenInfo //! struct, or 0 if there is no such struct. VMAddress evergreen_information_address; + + //! \brief The address in the client's address space of an + //! EvergreenAnnotations struct, or 0 if there is no such struct. + VMAddress annotations_address; #endif #if defined(OS_LINUX) @@ -93,7 +97,8 @@ #if defined(STARBOARD) //! \brief Used to store Evergreen mapping info in the handler for use at //! time of crash. - kTypeAddEvergreenInfo + kTypeAddEvergreenInfo, + kTypeAddAnnotations, #endif };
diff --git a/src/third_party/crashpad/wrapper/wrapper.cc b/src/third_party/crashpad/wrapper/wrapper.cc index 8b8a18d..0ab09e5 100644 --- a/src/third_party/crashpad/wrapper/wrapper.cc +++ b/src/third_party/crashpad/wrapper/wrapper.cc
@@ -206,6 +206,11 @@ return client->SendEvergreenInfoToHandler(evergreen_info); } +bool AddAnnotationsToCrashpad(EvergreenAnnotations annotations) { + ::crashpad::CrashpadClient* client = GetCrashpadClient(); + return client->SendAnnotationsToHandler(annotations); +} + } // namespace wrapper } // namespace crashpad } // namespace third_party
diff --git a/src/third_party/crashpad/wrapper/wrapper.h b/src/third_party/crashpad/wrapper/wrapper.h index c2b366f..57ab399 100644 --- a/src/third_party/crashpad/wrapper/wrapper.h +++ b/src/third_party/crashpad/wrapper/wrapper.h
@@ -25,6 +25,8 @@ bool AddEvergreenInfoToCrashpad(EvergreenInfo evergreen_info); +bool AddAnnotationsToCrashpad(EvergreenAnnotations annotations); + } // namespace wrapper } // namespace crashpad } // namespace third_party
diff --git a/src/third_party/crashpad/wrapper/wrapper_stub.cc b/src/third_party/crashpad/wrapper/wrapper_stub.cc index 6158445..f2aeb8a 100644 --- a/src/third_party/crashpad/wrapper/wrapper_stub.cc +++ b/src/third_party/crashpad/wrapper/wrapper_stub.cc
@@ -24,6 +24,10 @@ return false; } +bool AddAnnotationsToCrashpad(EvergreenAnnotations annotations) { + return false; +} + } // namespace wrapper } // namespace crashpad } // namespace third_party \ No newline at end of file
diff --git a/src/third_party/libdav1d/METATDATA b/src/third_party/libdav1d/METADATA similarity index 100% rename from src/third_party/libdav1d/METATDATA rename to src/third_party/libdav1d/METADATA
diff --git a/src/third_party/precommit-hooks/clang-format_wrapper.py b/src/third_party/precommit-hooks/clang-format_wrapper.py new file mode 100755 index 0000000..b11325c --- /dev/null +++ b/src/third_party/precommit-hooks/clang-format_wrapper.py
@@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +import os +import platform +import subprocess +import sys + +if __name__ == '__main__': + clang_format_args = sys.argv[1:] + path_to_clang_format = [os.getcwd(), 'buildtools'] + + system = platform.system() + if system == 'Linux': + path_to_clang_format += ['linux64', 'clang-format'] + elif system == 'Darwin': + path_to_clang_format += ['win', 'clang-format.exe'] + elif system == 'Windows': + path_to_clang_format += ['mac', 'clang-format'] + else: + sys.exit(1) + + clang_format_executable = os.path.join(*path_to_clang_format) + sys.exit(subprocess.call([clang_format_executable] + clang_format_args))
diff --git a/src/third_party/precommit-hooks/gcheckstyle_wrapper.py b/src/third_party/precommit-hooks/gcheckstyle_wrapper.py new file mode 100755 index 0000000..0275960 --- /dev/null +++ b/src/third_party/precommit-hooks/gcheckstyle_wrapper.py
@@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +import platform +import subprocess +import sys + +try: + from internal_tools_paths import checkstyle_path +except ImportError: + checkstyle_path = None + +if __name__ == '__main__': + gcheckstyle_args = sys.argv[1:] + try: + sys.exit(subprocess.call([checkstyle_path] + gcheckstyle_args)) + except OSError: + print('Checkstyle not found, skipping.') + sys.exit(0)
diff --git a/src/third_party/precommit-hooks/google-java-format_wrapper.py b/src/third_party/precommit-hooks/google-java-format_wrapper.py new file mode 100755 index 0000000..f244fa3 --- /dev/null +++ b/src/third_party/precommit-hooks/google-java-format_wrapper.py
@@ -0,0 +1,12 @@ +#!/usr/bin/env python3 + +import platform +import subprocess +import sys + +if __name__ == '__main__': + if platform.system() != 'Linux': + sys.exit(0) + + google_java_format_args = sys.argv[1:] + sys.exit(subprocess.call(['google-java-format'] + google_java_format_args))
diff --git a/src/third_party/web_platform_tests/fetch/api/request/request-consume-empty.html b/src/third_party/web_platform_tests/fetch/api/request/request-consume-empty.html index c3ca838..a5bc141 100644 --- a/src/third_party/web_platform_tests/fetch/api/request/request-consume-empty.html +++ b/src/third_party/web_platform_tests/fetch/api/request/request-consume-empty.html
@@ -69,12 +69,18 @@ }, "Consume request's body as " + bodyType); } +/* Cobalt doesn't support FormData request body var formData = new FormData(); +*/ checkRequestWithNoBody("text", checkBodyText); +/* Cobalt doesn't support Blob request body checkRequestWithNoBody("blob", checkBodyBlob); +*/ checkRequestWithNoBody("arrayBuffer", checkBodyArrayBuffer); checkRequestWithNoBody("json", checkBodyJSON); +/* Cobalt doesn't support FormData request body checkRequestWithNoBody("formData", checkBodyFormData); +*/ function checkRequestWithEmptyBody(bodyType, body, asText) { promise_test(function(test) { @@ -98,9 +104,11 @@ checkRequestWithEmptyBody("text", "", false); checkRequestWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), true); checkRequestWithEmptyBody("text", "", true); +/* Cobalt doesn't support URLSearchParams and FormData request body checkRequestWithEmptyBody("URLSearchParams", new URLSearchParams(""), true); // FIXME: This test assumes that the empty string be returned but it is not clear whether that is right. See https://github.com/w3c/web-platform-tests/pull/3950. checkRequestWithEmptyBody("FormData", new FormData(), true); +*/ checkRequestWithEmptyBody("ArrayBuffer", new ArrayBuffer(), true); </script> </body>
diff --git a/src/third_party/web_platform_tests/fetch/api/request/request-consume.html b/src/third_party/web_platform_tests/fetch/api/request/request-consume.html index 9ac7041..880f471 100644 --- a/src/third_party/web_platform_tests/fetch/api/request/request-consume.html +++ b/src/third_party/web_platform_tests/fetch/api/request/request-consume.html
@@ -69,11 +69,13 @@ assert_false(request.bodyUsed, "bodyUsed is false at init"); return checkBodyText(request, expected); }, "Consume " + bodyType + " request's body as text"); +/* Cobalt doesn't support Blob request body promise_test(function(test) { var request = new Request("", {"method": "POST", "body": body }); assert_false(request.bodyUsed, "bodyUsed is false at init"); return checkBodyBlob(request, expected); }, "Consume " + bodyType + " request's body as blob"); +*/ promise_test(function(test) { var request = new Request("", {"method": "POST", "body": body }); assert_false(request.bodyUsed, "bodyUsed is false at init"); @@ -114,6 +116,7 @@ checkRequestBody(new Float32Array(getArrayBuffer()), string, "Float32Array"); checkRequestBody(new DataView(getArrayBufferWithZeros(), 1, 8), string, "DataView"); +/* Cobalt doesn't support FormData request body promise_test(function(test) { var formData = new FormData(); formData.append("name", "value") @@ -121,6 +124,7 @@ assert_false(request.bodyUsed, "bodyUsed is false at init"); return checkBodyFormData(request, formData); }, "Consume FormData request's body as FormData"); +*/ function checkBlobResponseBody(blobBody, blobData, bodyType, checkFunction) { promise_test(function(test) { @@ -130,11 +134,15 @@ }, "Consume blob response's body as " + bodyType); } +/* Cobalt doesn't support Blob request body checkBlobResponseBody(blob, textData, "blob", checkBodyBlob); +*/ checkBlobResponseBody(blob, textData, "text", checkBodyText); checkBlobResponseBody(blob, textData, "json", checkBodyJSON); checkBlobResponseBody(blob, textData, "arrayBuffer", checkBodyArrayBuffer); +/* Cobalt doesn't support Blob request body checkBlobResponseBody(new Blob([""]), "", "blob (empty blob as input)", checkBodyBlob); +*/ var goodJSONValues = ["null", "1", "true", "\"string\""]; goodJSONValues.forEach(function(value) {
diff --git a/src/third_party/zlib/contrib/optimizations/chunkcopy.h b/src/third_party/zlib/contrib/optimizations/chunkcopy.h index 38ba0ed..c856b6a 100644 --- a/src/third_party/zlib/contrib/optimizations/chunkcopy.h +++ b/src/third_party/zlib/contrib/optimizations/chunkcopy.h
@@ -406,6 +406,26 @@ return chunkcopy_lapped_relaxed(out, dist, len); } +/* TODO(cavalcanti): see crbug.com/1110083. */ +static inline unsigned char FAR* chunkcopy_safe_ugly(unsigned char FAR* out, + unsigned dist, + unsigned len, + unsigned char FAR* limit) { +#if defined(__GNUC__) && !defined(__clang__) + /* Speed is the same as using chunkcopy_safe + w/ GCC on ARM (tested gcc 6.3 and 7.5) and avoids + undefined behavior. + */ + return chunkcopy_core_safe(out, out - dist, len, limit); +#elif defined(__clang__) && defined(ARMV8_OS_ANDROID) && !defined(__aarch64__) + /* Seems to perform better on 32bit (i.e. Android). */ + return chunkcopy_core_safe(out, out - dist, len, limit); +#else + /* Seems to perform better on 64bit. */ + return chunkcopy_lapped_safe(out, dist, len, limit); +#endif +} + /* * The chunk-copy code above deals with writing the decoded DEFLATE data to * the output with SIMD methods to increase decode speed. Reading the input
diff --git a/src/third_party/zlib/contrib/optimizations/inffast_chunk.c b/src/third_party/zlib/contrib/optimizations/inffast_chunk.c index 4099edf..4bacbc4 100644 --- a/src/third_party/zlib/contrib/optimizations/inffast_chunk.c +++ b/src/third_party/zlib/contrib/optimizations/inffast_chunk.c
@@ -276,7 +276,7 @@ the main copy is near the end. */ out = chunkunroll_relaxed(out, &dist, &len); - out = chunkcopy_safe(out, out - dist, len, limit); + out = chunkcopy_safe_ugly(out, dist, len, limit); } else { /* from points to window, so there is no risk of overlapping pointers requiring memset-like behaviour
diff --git a/src/v8/METADATA b/src/v8/METADATA new file mode 100644 index 0000000..8522c17 --- /dev/null +++ b/src/v8/METADATA
@@ -0,0 +1,22 @@ +name: "v8" +description: + "Subtree at v8." + "v8 is Google's JavaScript engine developed for The Chromium Project. Cobalt " + "uses v8 as its primary JavaScript engine. v8 works closely with Cobalt's " + "script interface and templated bindings code." +third_party { + url { + type: LOCAL_SOURCE + value: "/v8_mirror" + } + url { + type: GIT + value: "https://chromium.googlesource.com/v8/v8" + } + version: "1e6ebba9def991e536159fa658bf5564c054733f" + last_upgrade_date { + year: 2019 + month: 8 + day: 26 + } +}
diff --git a/src/v8/include/v8config.h b/src/v8/include/v8config.h index dd065a0..766ca5d 100644 --- a/src/v8/include/v8config.h +++ b/src/v8/include/v8config.h
@@ -56,7 +56,6 @@ // ----------------------------------------------------------------------------- // Operating system detection // -// V8_OS_STARBOARD - Starboard (platform abstraction layer for the Cobalt project) // V8_OS_ANDROID - Android // V8_OS_BSD - BSDish (Mac OS X, Net/Free/Open/DragonFlyBSD) // V8_OS_CYGWIN - Cygwin @@ -71,6 +70,7 @@ // V8_OS_POSIX - POSIX compatible (mostly everything except Windows) // V8_OS_QNX - QNX Neutrino // V8_OS_SOLARIS - Sun Solaris and OpenSolaris +// V8_OS_STARBOARD - Starboard (platform abstraction layer for the Cobalt project) // V8_OS_AIX - AIX // V8_OS_WIN - Microsoft Windows
diff --git a/src/v8/src/base/atomicops.h b/src/v8/src/base/atomicops.h index 18c99a2..09acdc2 100644 --- a/src/v8/src/base/atomicops.h +++ b/src/v8/src/base/atomicops.h
@@ -72,9 +72,9 @@ // Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or // Atomic64 routines below, depending on your architecture. #if defined(V8_OS_STARBOARD) -typedef SbAtomicPtr AtomicWord; +using AtomicWord = SbAtomicPtr; #else -typedef intptr_t AtomicWord; +using AtomicWord = intptr_t; #endif // Atomically execute:
diff --git a/src/v8/src/base/cpu.cc b/src/v8/src/base/cpu.cc index a13c13e..46daeed 100644 --- a/src/v8/src/base/cpu.cc +++ b/src/v8/src/base/cpu.cc
@@ -5,15 +5,9 @@ #include "src/base/cpu.h" #if defined(STARBOARD) -#include "starboard/client_porting/poem/stdlib_poem.h" #include "starboard/cpu_features.h" #endif -#if V8_HOST_ARCH_MIPS || V8_HOST_ARCH_MIPS64 -// Assume that if we're on a MIPS platform, we're on Linux. -#define V8_OS_LINUX 1 -#endif - #if V8_LIBC_MSVCRT #include <intrin.h> // __cpuid() #endif @@ -43,13 +37,11 @@ #endif #include <ctype.h> -#if !V8_OS_STARBOARD #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> -#endif #include "src/base/logging.h" #if V8_OS_WIN
diff --git a/src/v8/src/base/once.cc b/src/v8/src/base/once.cc index 7378b54..0222687 100644 --- a/src/v8/src/base/once.cc +++ b/src/v8/src/base/once.cc
@@ -6,6 +6,8 @@ #ifdef _WIN32 #include <windows.h> +#elif defined(V8_OS_STARBOARD) +#include "starboard/thread.h" #else #include <sched.h> #endif @@ -49,6 +51,8 @@ ONCE_STATE_EXECUTING_FUNCTION) { #ifdef _WIN32 ::Sleep(0); +#elif defined(V8_OS_STARBOARD) + SbThreadYield(); #else sched_yield(); #endif
diff --git a/src/v8/src/base/platform/condition-variable.cc b/src/v8/src/base/platform/condition-variable.cc index b319793..04ea291 100644 --- a/src/v8/src/base/platform/condition-variable.cc +++ b/src/v8/src/base/platform/condition-variable.cc
@@ -165,7 +165,6 @@ SbConditionVariableCreate(&native_handle_, nullptr); } - ConditionVariable::~ConditionVariable() { SbConditionVariableDestroy(&native_handle_); } @@ -178,12 +177,10 @@ SbConditionVariableBroadcast(&native_handle_); } - void ConditionVariable::Wait(Mutex* mutex) { SbConditionVariableWait(&native_handle_, &mutex->native_handle()); } - bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) { SbTime microseconds = static_cast<SbTime>(rel_time.InMicroseconds()); SbConditionVariableResult result = SbConditionVariableWaitTimed( @@ -192,7 +189,7 @@ return result == kSbConditionVariableSignaled; } -#endif // V8_OS_POSIX +#endif // V8_OS_STARBOARD } // namespace base -} // namespace v8 \ No newline at end of file +} // namespace v8
diff --git a/src/v8/src/base/platform/mutex.cc b/src/v8/src/base/platform/mutex.cc index 68f5132..88d9ba8 100644 --- a/src/v8/src/base/platform/mutex.cc +++ b/src/v8/src/base/platform/mutex.cc
@@ -4,9 +4,7 @@ #include "src/base/platform/mutex.h" -#if !V8_OS_STARBOARD #include <errno.h> -#endif namespace v8 { namespace base {
diff --git a/src/v8/src/base/platform/platform-starboard.cc b/src/v8/src/base/platform/platform-starboard.cc index 3cd69ec..a9a0118 100644 --- a/src/v8/src/base/platform/platform-starboard.cc +++ b/src/v8/src/base/platform/platform-starboard.cc
@@ -1,25 +1,17 @@ -// Copyright 2018 Google Inc. 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. +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Platform-specific code for Starboard goes here. Starboard is the platform +// abstraction layer for Cobalt, an HTML5 container used mainly by YouTube +// LivingRoom products. #include "src/base/lazy-instance.h" #include "src/base/macros.h" #include "src/base/platform/platform.h" #include "src/base/platform/time.h" -#include "src/base/utils/random-number-generator.h" - #include "src/base/timezone-cache.h" - +#include "src/base/utils/random-number-generator.h" #include "starboard/common/condition_variable.h" #include "starboard/common/log.h" #include "starboard/common/string.h" @@ -102,9 +94,7 @@ #endif } -double OS::TimeCurrentMillis() { - return Time::Now().ToJsTime(); -} +double OS::TimeCurrentMillis() { return Time::Now().ToJsTime(); } int OS::ActivationFrameAlignment() { #if V8_TARGET_ARCH_ARM @@ -148,7 +138,8 @@ break; default: SB_LOG(ERROR) << "The requested memory allocation access is not" - " implemented for Starboard: " << static_cast<int>(access); + " implemented for Starboard: " + << static_cast<int>(access); return nullptr; } void* result = SbMemoryMap(size, sb_flags, "v8::Base::Allocate"); @@ -247,10 +238,10 @@ break; case OS::MemoryPermission::kReadExecute: #if SB_CAN(MAP_EXECUTABLE_MEMORY) - new_protection = SbMemoryMapFlags(kSbMemoryMapProtectRead | - kSbMemoryMapProtectExec); + new_protection = + SbMemoryMapFlags(kSbMemoryMapProtectRead | kSbMemoryMapProtectExec); #else - CHECK(false); + UNREACHABLE(); #endif break; default: @@ -417,9 +408,7 @@ set_name(options.name()); } -Thread::~Thread() { - delete data_; -} +Thread::~Thread() { delete data_; } static void SetThreadName(const char* name) { SbThreadSetName(name); }
diff --git a/src/v8/src/base/platform/semaphore.cc b/src/v8/src/base/platform/semaphore.cc index f37801a..3545bab 100644 --- a/src/v8/src/base/platform/semaphore.cc +++ b/src/v8/src/base/platform/semaphore.cc
@@ -190,21 +190,13 @@ #elif V8_OS_STARBOARD -Semaphore::Semaphore(int count) : native_handle_(count) { - DCHECK_GE(count, 0); -} +Semaphore::Semaphore(int count) : native_handle_(count) { DCHECK_GE(count, 0); } -Semaphore::~Semaphore() { -} +Semaphore::~Semaphore() {} -void Semaphore::Signal() { - native_handle_.Put(); -} +void Semaphore::Signal() { native_handle_.Put(); } - -void Semaphore::Wait() { - native_handle_.Take(); -} +void Semaphore::Wait() { native_handle_.Take(); } bool Semaphore::WaitFor(const TimeDelta& rel_time) { SbTime microseconds = rel_time.InMicroseconds();
diff --git a/src/v8/src/base/platform/time.cc b/src/v8/src/base/platform/time.cc index 5aa6dcd..ff1fcd8 100644 --- a/src/v8/src/base/platform/time.cc +++ b/src/v8/src/base/platform/time.cc
@@ -458,15 +458,11 @@ #elif V8_OS_STARBOARD -Time Time::Now() { - return Time(SbTimeToPosix(SbTimeGetNow())); -} +Time Time::Now() { return Time(SbTimeToPosix(SbTimeGetNow())); } -Time Time::NowFromSystemTime() { - return Now(); -} +Time Time::NowFromSystemTime() { return Now(); } -#endif // V8_OS_WIN +#endif // V8_OS_STARBOARD // static TimeTicks TimeTicks::HighResolutionNow() {
diff --git a/src/venv/.gitkeep b/src/venv/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/venv/.gitkeep