Index: services/media/audio/audio_output.h |
diff --git a/services/media/audio/audio_output.h b/services/media/audio/audio_output.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..38db12669c5cd76cfeba7755f637303e182e8aae |
--- /dev/null |
+++ b/services/media/audio/audio_output.h |
@@ -0,0 +1,169 @@ |
+// Copyright 2015 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. |
+ |
+#ifndef SERVICES_MEDIA_AUDIO_AUDIO_OUTPUT_H_ |
+#define SERVICES_MEDIA_AUDIO_AUDIO_OUTPUT_H_ |
+ |
+#include <deque> |
+#include <memory> |
+#include <set> |
+ |
+#include "base/callback.h" |
+#include "base/synchronization/lock.h" |
+#include "base/threading/sequenced_worker_pool.h" |
+#include "mojo/services/media/common/cpp/local_time.h" |
+#include "services/media/audio/audio_pipe.h" |
+#include "services/media/audio/audio_track_impl.h" |
+#include "services/media/audio/fwd_decls.h" |
+ |
+namespace mojo { |
+namespace media { |
+namespace audio { |
+ |
+class AudioOutput { |
+ public: |
+ virtual ~AudioOutput(); |
+ |
+ // AddTrack/RemoveTrack |
+ // |
+ // Adds or removes a track to/from the set of current set of tracks serviced |
+ // by this outputs. Called only from the main message loop. Obtains the |
jeffbrown
2015/11/04 23:43:32
outputs -> output
johngro
2015/11/06 02:20:24
Done.
|
+ // processing_lock and may block for the time it takes the derrived class to |
jeffbrown
2015/11/04 23:43:33
derrived -> derived
johngro
2015/11/06 02:20:24
Done.
|
+ // run its processing task if the task is in progress when the method was |
+ // called. |
jeffbrown
2015/11/04 23:43:32
In general it's safer to avoid immediately calling
johngro
2015/11/06 02:20:24
I'm not sure that I understand the question. As t
|
+ MediaResult AddTrackLink(AudioTrackToOutputLinkPtr link); |
+ MediaResult RemoveTrackLink(const AudioTrackToOutputLinkPtr& link); |
+ |
+ protected: |
+ explicit AudioOutput(AudioOutputManager* manager); |
+ |
+ ////////////////////////////////////////////////////////////////////////////// |
+ // |
+ // Methods which may be implemented by derived classes to customize behavior. |
+ // |
+ ////////////////////////////////////////////////////////////////////////////// |
+ |
+ // Init |
+ // |
+ // Called during startup on the AudioServer's main message loop thread. No |
+ // locks are being held at this point. Derived classes should allocate their |
+ // hardware resources and initialize any internal state. Return |
+ // MediaResult::OK if everything is good and the output is ready to do work. |
+ virtual MediaResult Init(); |
jeffbrown
2015/11/04 23:43:32
Consider using a convention such as OnInit() to di
johngro
2015/11/06 02:20:24
If I had not intended for the method to be overrid
|
+ |
+ // Cleanup |
+ // |
+ // Called at shutdown on the AudioServer's main message loop thread to allow |
+ // derived classes to clean up any allocated resources. All pending |
+ // processing callbacks have either been nerfed or run till completion. All |
+ // AudioTrack tracks have been disconnected. No locks are being held. |
+ virtual void Cleanup(); |
+ |
+ // Process |
+ // |
+ // Called from within the context of the processing lock any time a scheduled |
jeffbrown
2015/11/04 23:43:32
Technically you don't need a lock to guarantee ser
johngro
2015/11/06 02:20:24
The lock is not being used to guarantee serializat
|
+ // processing callback fires. One callback will be automatically scheduled at |
+ // the end of initialization. After that, derived classes are responsible for |
+ // scheduling all subsequent callbacks to keep the engine running. |
+ virtual void Process() = 0; |
+ |
+ // InitializeLink |
+ // |
+ // Called on the AudioServer's main message loop any time a track is being |
+ // added to this output. Outputs should allocate and initialize any |
+ // bookkeeping they will need to perform mixing on behalf of the newly added |
+ // track. |
+ // |
+ // @return MediaResult::OK if initialization succeeded, or an appropriate |
+ // error code otherwise. |
+ virtual MediaResult InitializeLink(const AudioTrackToOutputLinkPtr& link); |
+ |
+ ////////////////////////////////////////////////////////////////////////////// |
+ // |
+ // Methods which may used by derived classes from within the context of a |
+ // processing callback. Note; since these methods are intended to be called |
+ // from the within a processing callback, the processing_lock will always be |
jeffbrown
2015/11/04 23:43:32
This here suggests that these methods should be pr
johngro
2015/11/06 02:20:24
I don't understand. The context, in this case, is
|
+ // held when they are called. |
+ // |
+ |
+ // ScheduleCallback |
+ // |
+ // Schedule a processing callback at the specified absolute time on the local |
+ // clock. |
+ void ScheduleCallback(LocalTime when); |
+ |
+ // ShutdownSelf |
+ // |
+ // Kick off the process of shooting ourselves in the head. Note, after this |
+ // method has been called, no new callbacks may be scheduled. As soon as the |
+ // main message loop finds out about our shutdown request, it will complete |
+ // the process of shutting us down, unlinking us from our tracks and calling |
+ // the Cleanup method. |
+ void ShutdownSelf(); |
+ |
+ // shutting_down |
+ // |
+ // Check the shutting down flag. Only the base class may modify the flag, but |
+ // derived classes are free to check it at any time. |
+ inline bool shutting_down() const { return shutting_down_; } |
+ |
+ // TODO(johngro): Order this by priority. Figure out how we are going to be |
+ // able to quickly find a track with a specific priority in order to optimize |
+ // changes of priority. Perhaps uniquify the priorities by assigning a |
+ // sequence number to the lower bits (avoiding collisions when assigning new |
+ // priorities will be the trick). |
jeffbrown
2015/11/04 23:43:33
Could just use a heap.
johngro
2015/11/06 02:20:24
sure, I pretty much already am; right now I am usi
|
+ // |
+ // Right now, we have no priorities, so this is just a set of track/output |
+ // links. |
+ AudioTrackToOutputLinkSet links_; |
+ AudioOutputManager* manager_; |
+ |
+ private: |
+ // It's always nice when you manager is also your friend. Seriously though, |
+ // the AudioOutputManager gets to call Init and Shutown, no one else |
+ // (including derived classes) should be able to. |
+ friend class AudioOutputManager; |
+ |
+ // Thunk used to schedule delayed processing tasks on our task_runner. |
+ static void ProcessThunk(AudioOutputWeakPtr weak_output); |
+ |
+ // Called from the AudioOutputManager after an output has been created. |
+ // Gives derived classes a chance to set up hardware, then sets up the |
+ // machinery needed for scheduling processing tasks and schedules the first |
+ // processing callback immediately in order to get the process running. |
+ MediaResult Init(const AudioOutputPtr& self, |
+ scoped_refptr<base::SequencedTaskRunner> task_runner); |
+ |
+ // Called from Shutdown (main message loop) and ShutdowSelf (processing |
jeffbrown
2015/11/04 23:43:32
I think it's a little weird for there to be two di
johngro
2015/11/06 02:20:24
That is how things handled now. Shutdown self pos
|
+ // context). Starts the process of shutdown, preventing new processing tasks |
+ // from being scheduled, and nerfing any tasks in flight. |
+ // |
+ // @return true if this call just kicked off the process of shutting down, |
+ // false otherwise. |
+ bool BeginShutdown(); |
+ |
+ // Called from the AudioOutputManager on the main message loop |
+ // thread. Makes certain that the process of shutdown has started, |
+ // synchronizes with any processing tasks which were executing at the time, |
+ // then finishes the shutdown process by unlinking from all tracks and |
+ // cleaning up all resources. |
+ void Shutdown(); |
+ |
+ base::Lock processing_lock_; |
jeffbrown
2015/11/04 23:43:33
We won't need this lock if the processing state is
johngro
2015/11/06 02:20:24
I disagree. See my comments regarding synchroniza
|
+ base::Lock shutdown_lock_; |
jeffbrown
2015/11/04 23:43:32
We won't need this lock is shutdown is always init
johngro
2015/11/06 02:20:24
Unfortunately, I think it is an important requirem
|
+ scoped_refptr<base::SequencedTaskRunner> task_runner_; |
+ AudioOutputWeakPtr weak_self_; |
+ |
+ // TODO(johngro): Eliminate the shutting down flag and just use the |
+ // task_runner_'s nullness for this test? |
+ volatile bool shutting_down_ = false; |
+ volatile bool shut_down_ = false; |
+}; |
+ |
+} // namespace audio |
+} // namespace media |
+} // namespace mojo |
+ |
+#endif // SERVICES_MEDIA_AUDIO_AUDIO_OUTPUT_H_ |
+ |