| // Copyright 2015 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. |
| |
| // A cross-platform base application engine that is used to manage the main |
| // event loop |
| |
| #ifndef STARBOARD_SHARED_STARBOARD_APPLICATION_H_ |
| #define STARBOARD_SHARED_STARBOARD_APPLICATION_H_ |
| |
| #include <vector> |
| |
| #include "starboard/atomic.h" |
| #include "starboard/condition_variable.h" |
| #include "starboard/event.h" |
| #include "starboard/log.h" |
| #include "starboard/player.h" |
| #include "starboard/shared/internal_only.h" |
| #include "starboard/shared/starboard/command_line.h" |
| #include "starboard/shared/starboard/player/video_frame_internal.h" |
| #include "starboard/thread.h" |
| #include "starboard/time.h" |
| #include "starboard/types.h" |
| #include "starboard/window.h" |
| |
| namespace starboard { |
| namespace shared { |
| namespace starboard { |
| |
| // A small application framework for managing the application life-cycle, and |
| // dispatching events to the Starboard event handler, SbEventHandle. |
| class Application { |
| public: |
| typedef player::VideoFrame VideoFrame; |
| |
| // You can use a void(void *) function to signal that a state-transition event |
| // has completed. |
| typedef SbEventDataDestructor EventHandledCallback; |
| |
| // Signature for a function that will be called at the beginning of Teardown. |
| typedef void(*TeardownCallback)(void); |
| |
| // Enumeration of states that the application can be in. |
| enum State { |
| // The initial Unstarted state. |
| kStateUnstarted, |
| |
| // The normal foreground, fully-visible state after receiving the initial |
| // START event or after UNPAUSE from Paused. |
| kStateStarted, |
| |
| // The background-but-visible or partially-obscured state after receiving an |
| // PAUSE event from Started or RESUME event from Suspended. |
| kStatePaused, |
| |
| // The fully-obscured or about-to-be-terminated state after receiving a |
| // SUSPEND event in Paused. |
| kStateSuspended, |
| |
| // The completely terminated state after receiving the STOP event in the |
| // Suspended state. |
| kStateStopped, |
| }; |
| |
| // Structure to keep track of scheduled events, also used as the data argument |
| // for kSbEventTypeScheduled Events. |
| struct TimedEvent { |
| TimedEvent(SbEventId eid, |
| SbEventCallback func, |
| void* data, |
| SbTimeMonotonic delay) |
| : id(eid), |
| callback(func), |
| context(data), |
| target_time(delay + SbTimeGetMonotonicNow()), |
| canceled(false) {} |
| |
| SbEventId id; |
| SbEventCallback callback; |
| void* context; |
| SbTimeMonotonic target_time; |
| bool canceled; |
| }; |
| |
| // Destructor function that deletes the value as the parameterized type. |
| template <typename T> |
| static void DeleteDestructor(void* value) { |
| delete static_cast<T*>(value); |
| } |
| |
| // Destructor function that deletes the value as an array of the |
| // parameterized type. |
| template <typename T> |
| static void DeleteArrayDestructor(void* value) { |
| delete[] static_cast<T*>(value); |
| } |
| |
| // A Starboard event and its destructor. Takes ownership of the event, thus |
| // deleting the event and calling the destructor on its data when it is |
| // deleted. |
| struct Event { |
| Event(SbEventType type, void* data, SbEventDataDestructor destructor) |
| : event(new SbEvent()), destructor(destructor), error_level(0) { |
| event->type = type; |
| event->data = data; |
| } |
| explicit Event(TimedEvent* data) |
| : event(new SbEvent()), |
| destructor(&DeleteDestructor<TimedEvent>), |
| error_level(0) { |
| event->type = kSbEventTypeScheduled; |
| event->data = data; |
| } |
| ~Event() { |
| if (destructor) { |
| destructor(event->data); |
| } |
| if (event) { |
| delete event; |
| } |
| } |
| |
| SbEvent* event; |
| SbEventDataDestructor destructor; |
| int error_level; |
| }; |
| |
| Application(); |
| virtual ~Application(); |
| |
| // Gets the current instance of the Application. DCHECKS if called before the |
| // application has been constructed. |
| static inline Application* Get() { |
| Application* instance = reinterpret_cast<Application*>( |
| SbAtomicAcquire_LoadPtr(reinterpret_cast<SbAtomicPtr*>(&g_instance))); |
| SB_DCHECK(instance); |
| return instance; |
| } |
| |
| // Runs the application with the current thread as the Main Starboard Thread, |
| // blocking until application exit. This method will dispatch all appropriate |
| // initialization and teardown events. Returns the resulting error level. |
| int Run(int argc, char** argv); |
| |
| // Retrieves the CommandLine for the application. |
| // NULL until Run() is called. |
| CommandLine* GetCommandLine(); |
| |
| // Signals that the application should transition from STARTED to PAUSED as |
| // soon as possible. Does nothing if already PAUSED or SUSPENDED. May be |
| // called from an external thread. |
| // |
| // |context|: A context value to pass to |callback| on event completion. Must |
| // not be NULL if callback is not NULL. |
| // |callback|: A function to call on event completion, from the main thread. |
| void Pause(void* context, EventHandledCallback callback); |
| |
| // Signals that the application should transition to STARTED as soon as |
| // possible, moving through all required state transitions to get there. Does |
| // nothing if already STARTED. May be called from an external thread. |
| // |
| // |context|: A context value to pass to |callback| on event completion. Must |
| // not be NULL if callback is not NULL. |
| // |callback|: A function to call on event completion, from the main thread. |
| void Unpause(void* context, EventHandledCallback callback); |
| |
| // Signals that the application should transition to SUSPENDED as soon as |
| // possible, moving through all required state transitions to get there. Does |
| // nothing if already SUSPENDED. May be called from an external thread. |
| // |
| // |context|: A context value to pass to |callback| on event completion. Must |
| // not be NULL if callback is not NULL. |
| // |callback|: A function to call on event completion, from the main thread. |
| void Suspend(void* context, EventHandledCallback callback); |
| |
| // Signals that the application should transition to PAUSED from SUSPENDED as |
| // soon as possible. Does nothing if already PAUSED or STARTED. May be called |
| // from an external thread. |
| // |
| // |context|: A context value to pass to |callback| on event completion. Must |
| // not be NULL if callback is not NULL. |
| // |callback|: A function to call on event completion, from the main thread. |
| void Resume(void* context, EventHandledCallback callback); |
| |
| // Signals that the application should gracefully terminate as soon as |
| // possible. Will transition through PAUSED and SUSPENDED to STOPPED as |
| // appropriate for the current state. May be called from an external thread. |
| void Stop(int error_level); |
| |
| // Schedules an event into the event queue. May be called from an external |
| // thread. |
| SbEventId Schedule(SbEventCallback callback, |
| void* context, |
| SbTimeMonotonic delay); |
| |
| // Cancels an event that was previously scheduled. May be called from an |
| // external thread. |
| void Cancel(SbEventId id); |
| |
| #if SB_HAS(PLAYER) && \ |
| (SB_API_VERSION >= SB_PLAYER_DECODE_TO_TEXTURE_API_VERSION || \ |
| SB_IS(PLAYER_PUNCHED_OUT)) |
| // Handles receiving a new video frame of |player| from the media system. Only |
| // used when the application needs to composite video frames with punch-out |
| // video manually (should be rare). Will be called from an external thread. |
| void HandleFrame(SbPlayer player, |
| const scoped_refptr<VideoFrame>& frame, |
| int x, |
| int y, |
| int width, |
| int height); |
| #endif // SB_HAS(PLAYER) && \ |
| (SB_API_VERSION >= SB_PLAYER_DECODE_TO_TEXTURE_API_VERSION || \ |
| SB_IS(PLAYER_PUNCHED_OUT)) |
| |
| // Registers a |callback| function that will be called when |Teardown| is |
| // called. |
| void RegisterTeardownCallback(TeardownCallback callback) { |
| ScopedLock lock(callbacks_lock_); |
| teardown_callbacks_.push_back(callback); |
| } |
| |
| protected: |
| // Initializes any systems that need initialization before application |
| // start. Subclasses may override this method to run initialization code that |
| // must be run before application start event is handled. |
| virtual void Initialize() {} |
| |
| // Tears down any systems that need tearing down before application |
| // termination. Subclasses may override this method to run teardown code that |
| // must be run after the application stop event is handled. |
| virtual void Teardown() {} |
| |
| // Does any platform-specific tearing-down AFTER the application has |
| // processed the Suspend event, but before actual suspension. |
| virtual void OnSuspend() {} |
| |
| // Does any platform-specific initialization BEFORE the application has |
| // processed the Resume event. |
| virtual void OnResume() {} |
| |
| #if SB_HAS(PLAYER) && \ |
| (SB_API_VERSION >= SB_PLAYER_DECODE_TO_TEXTURE_API_VERSION || \ |
| SB_IS(PLAYER_PUNCHED_OUT)) |
| // Subclasses may override this method to accept video frames from the media |
| // system. Will be called from an external thread. |
| virtual void AcceptFrame(SbPlayer player, |
| const scoped_refptr<VideoFrame>& frame, |
| int x, |
| int y, |
| int width, |
| int height) {} |
| #endif // SB_HAS(PLAYER) && \ |
| (SB_API_VERSION >= SB_PLAYER_DECODE_TO_TEXTURE_API_VERSION || \ |
| SB_IS(PLAYER_PUNCHED_OUT)) |
| |
| // Blocks until the next event is available. Subclasses must implement this |
| // method to provide events for the platform. Gives ownership to the caller. |
| virtual Event* GetNextEvent() = 0; |
| |
| // Blocks until the next event is available, then dispatches the event to the |
| // system event handler. Derived classes that override this should still use |
| // |DispatchAndDelete| to maintain consistency of the application state. |
| // Returns whether to keep servicing the event queue, i.e. false means to |
| // abort the event queue. |
| virtual bool DispatchNextEvent() { |
| return DispatchAndDelete(GetNextEvent()); |
| } |
| |
| // Injects an event into the queue, such that it will be returned from |
| // GetNextEvent(), giving ownership of the event. NULL is valid, and will just |
| // wake up the main loop. May be called from an external thread. Subclasses |
| // must implement this method. |
| virtual void Inject(Event* event) = 0; |
| |
| // Injects a new TimedEvent into the scheduled event queue, passing |
| // ownership. May be called from an external thread. |
| virtual void InjectTimedEvent(TimedEvent* timed_event) = 0; |
| |
| // Cancels the timed event associated with the given SbEventId, if it hasn't |
| // already fired. May be called from an external thread. |
| virtual void CancelTimedEvent(SbEventId event_id) = 0; |
| |
| // Gets the next timed event that has met or passed its target time. Returns |
| // NULL if there are no due TimedEvents queued. Passes ownership to caller. |
| virtual TimedEvent* GetNextDueTimedEvent() = 0; |
| |
| // Gets the next time that a TimedEvent is due. Returns |
| // SbTimeGetMonotonicNow() if the next TimedEvent is past due. Returns |
| // kSbTimeMax if there are no queued TimedEvents. |
| virtual SbTimeMonotonic GetNextTimedEventTargetTime() = 0; |
| |
| // Sets the launch deep link string, if any, which is passed in the start |
| // event that initializes and starts Cobalt. |
| void SetStartLink(const char* start_link); |
| |
| // Returns whether the current thread is the Application thread. |
| bool IsCurrentThread() const { |
| return SbThreadIsEqual(thread_, SbThreadGetCurrent()); |
| } |
| |
| // Returns the current application state. |
| State state() const { return state_; } |
| |
| // Returns true if the Start event should be sent in |Run| before entering the |
| // event loop. Derived classes that return false must call |DispatchStart|. |
| virtual bool IsStartImmediate() { return true; } |
| |
| // Dispatches a Start event to the system event handler. |
| void DispatchStart(); |
| |
| // Dispatches |event| to the system event handler, taking ownership of the |
| // event. Checks for consistency with the current application state when state |
| // events are dispatched. Returns whether to keep servicing the event queue, |
| // i.e. false means to abort the event queue. |
| bool DispatchAndDelete(Application::Event* event); |
| |
| private: |
| void CallTeardownCallbacks(); |
| |
| // The single application instance. |
| static Application* g_instance; |
| |
| // The error_level set by the last call to Stop(). |
| int error_level_; |
| |
| // The thread that this application was created on, which is assumed to be the |
| // main thread. |
| SbThread thread_; |
| |
| // CommandLine instance initialized in |Run|. |
| scoped_ptr<CommandLine> command_line_; |
| |
| // The deep link included in the Start event sent to Cobalt. Initially NULL, |
| // derived classes may set it during initialization using |SetStartLink|. |
| char* start_link_; |
| |
| // The current state that the application is in based on what events it has |
| // actually processed. Should only be accessed on the main thread. |
| State state_; |
| |
| // Protect the teardown_callbacks_ vector. |
| Mutex callbacks_lock_; |
| |
| // Callbacks that must be called when Teardown is called. |
| std::vector<TeardownCallback> teardown_callbacks_; |
| }; |
| |
| } // namespace starboard |
| } // namespace shared |
| } // namespace starboard |
| |
| #endif // STARBOARD_SHARED_STARBOARD_APPLICATION_H_ |