| Index: services/media/audio/audio_track_to_output_link.h
|
| diff --git a/services/media/audio/audio_track_to_output_link.h b/services/media/audio/audio_track_to_output_link.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f9d31ec1d2a6302540175e4c2549856553cadadf
|
| --- /dev/null
|
| +++ b/services/media/audio/audio_track_to_output_link.h
|
| @@ -0,0 +1,128 @@
|
| +// 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_TRACK_TO_OUTPUT_LINK_H_
|
| +#define SERVICES_MEDIA_AUDIO_AUDIO_TRACK_TO_OUTPUT_LINK_H_
|
| +
|
| +#include <deque>
|
| +#include <memory>
|
| +
|
| +#include "base/synchronization/lock.h"
|
| +#include "services/media/audio/audio_pipe.h"
|
| +#include "services/media/audio/fwd_decls.h"
|
| +
|
| +namespace mojo {
|
| +namespace media {
|
| +namespace audio {
|
| +
|
| +// AudioTrackToOutputLink is a small class which tracks the relationship between
|
| +// an audio track and an audio output. Tracks and outputs are expected to hold
|
| +// strong pointers to the state in the collections they use to track their
|
| +// peers.
|
| +//
|
| +// When either a track or an output ceases to exist, its collection will clear
|
| +// releasing the reference to the shared state. When the other half of the
|
| +// relationship realizes that its peer has gone away (typically by failing to
|
| +// promote the weak reference to its peer held in the share state object), it
|
| +// can purge the state object strong pointer from its collection triggering the
|
| +// final cleanup of the shared state.
|
| +//
|
| +// Because the final cleanup of the shared state can be triggered either from an
|
| +// output manager mixer thread, or from the audio service's main message loop,
|
| +// it must be safe to destruct all of the shared state from any thread in the
|
| +// system. No assumptions may be made about threading when destructing.
|
| +//
|
| +// The AudioTrackToOutputLink object holds a queue of pending audio packet
|
| +// references sourced from the AudioTrack to be rendered on the audio output.
|
| +// The references are safe to release either from an output manager thread, or
|
| +// from the audio service's main message loop thread (which drives track
|
| +// behavior).
|
| +//
|
| +// Finally, both the Output may have a pointer to a Bookkeeping object in order
|
| +// to manage bookkeeping tasks specific to the Track/Output relationship. The
|
| +// following rules must be obeyed at all times...
|
| +//
|
| +// + Derrived classes of the Bookkeeping object created by the Output must be
|
| +// safe to destroy either thread. During destruction, no potentially blocking
|
| +// operations may be performed. No heavy operations (such as logging) should
|
| +// be performed.
|
| +// + Only the output is permitted to access the output bookkeeping. The track
|
| +// must make no attempts to modify the bookkeeping or its pointer.
|
| +// + Outputs must hold a strong reference to the shared link object object
|
| +// whenever they are accessing their bookkeeping object. The link object is
|
| +// considered to be the owner of the Bookkeeping, users must never hold a
|
| +// naked pointer to their bookkeeping if the link could possibly destruct.
|
| +//
|
| +class AudioTrackToOutputLink {
|
| + public:
|
| + struct Bookkeeping {
|
| + virtual ~Bookkeeping();
|
| + };
|
| +
|
| + using BookkeepingPtr = std::unique_ptr<Bookkeeping>;
|
| + using PacketQueue = std::deque<AudioPipe::AudioPacketRefPtr>;
|
| + using PacketQueuePtr = std::unique_ptr<PacketQueue>;
|
| +
|
| + static AudioTrackToOutputLinkPtr New(AudioTrackImplWeakPtr track,
|
| + AudioOutputWeakPtr output);
|
| + virtual ~AudioTrackToOutputLink();
|
| +
|
| + // Accessors for the track and output pointers. Automatically attempts to
|
| + // promote the weak pointer to a strong pointer.
|
| + //
|
| + // TODO(johngro): Given the way outputs are currently shut down, there is
|
| + // actually no need for the link to hold a weak pointer to output. By the
|
| + // time it destructs, All references to it are guaranteed to have been removed
|
| + // from all tracks in the context of the main event loop. Consider converting
|
| + // this from a weak pointer to a strong pointer.
|
| + AudioTrackImplPtr GetTrack() { return track_.lock(); }
|
| + AudioOutputPtr GetOutput() { return output_.lock(); }
|
| +
|
| + // AudioTrack PendingQueue operations. Never call these from the AudioOutput.
|
| + void PushToPendingQueue(const AudioPipe::AudioPacketRefPtr& pkt);
|
| + void FlushPendingQueue();
|
| +
|
| + // AudioOutput PendingQueue operations. Never call these from the AudioTrack.
|
| + // When consuming audio, AudioOutputs must always pair their calls to
|
| + // LockPendingQueueFront and UnlockPendingQueueFront, passing the pointer to
|
| + // the reference to the front of the queue they obtained in the process (even
|
| + // if the front of the queue was nullptr).
|
| + //
|
| + // Doing so ensures that AudioTracks which are attempting to flush the pending
|
| + // queue are forced to wait if the front of the queue is involved in a mixing
|
| + // operation. This, in turn, guarantees that audio packets are always
|
| + // returned to the user in the order which they were queued in without forcing
|
| + // AudioTracks to wait to queue new data if a mix operation is in progress.
|
| + AudioPipe::AudioPacketRefPtr LockPendingQueueFront(bool* was_flushed);
|
| + void UnlockPendingQueueFront(AudioPipe::AudioPacketRefPtr* pkt,
|
| + bool release_packet);
|
| +
|
| + // Bookkeeping access.
|
| + //
|
| + BookkeepingPtr& output_bookkeeping() { return output_bookkeeping_; }
|
| +
|
| + private:
|
| + void ReleaseQueue(const PacketQueuePtr& queue);
|
| +
|
| + AudioTrackToOutputLink(AudioTrackImplWeakPtr track,
|
| + AudioOutputWeakPtr output);
|
| +
|
| + AudioTrackImplWeakPtr track_;
|
| + AudioOutputWeakPtr output_;
|
| + BookkeepingPtr output_bookkeeping_;
|
| +
|
| + base::Lock flush_lock_;
|
| + base::Lock pending_queue_lock_;
|
| + PacketQueuePtr pending_queue_;
|
| + bool flushed_ = true;
|
| +#if !(defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON))
|
| + std::atomic<bool> flush_lock_held_;
|
| +#endif
|
| +};
|
| +
|
| +} // namespace audio
|
| +} // namespace media
|
| +} // namespace mojo
|
| +
|
| +#endif // SERVICES_MEDIA_AUDIO_AUDIO_TRACK_TO_OUTPUT_LINK_H_
|
|
|