Chromium Code Reviews| 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_ |
| + |