blob: 1ad888c6c50661380c26f6dad6853d24093c9fa0 [file] [log] [blame]
// 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_COMMON_RATE_CONTROL_BASE_H_
#define SERVICES_MEDIA_COMMON_RATE_CONTROL_BASE_H_
#include <deque>
#include "base/synchronization/lock.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/services/media/common/cpp/linear_transform.h"
#include "mojo/services/media/common/interfaces/media_common.mojom.h"
#include "mojo/services/media/common/interfaces/rate_control.mojom.h"
namespace mojo {
namespace media {
class RateControlBase : public RateControl {
public:
// Default constructor and destructor
RateControlBase();
~RateControlBase() override;
bool Bind(InterfaceRequest<RateControl> request);
bool is_bound() const { return binding_.is_bound(); }
// Close any existing connections to clients, clear any pending rate changes
// and set the clock rate to 0/1.
void Reset();
// TODO(johngro): snapshotting the current transform requires an evaluation of
// all the pending timeline transformations. Currently, we allow users to
// schedule an arbitrary number of pending transformations. This could cause
// DoS hazards if a malicious (or just poorly written) application is
// schedules a ton of transformations, and then something like the mixer
// threads in the audio server is forced to collapse all of these
// transformations in order to mix then next set of outbound audio frames.
//
// A simple way to avoid this would be to allow the user to have only one
// pending transformation at any point in time.
//
// It would be nice to be able to simply return the transformation and use
// Rvalue references in calling code to access the temporary snapshot, but
// style does not permit us to use Rvalue references in such a way.
//
// Also; the way pending transformations get applied probably needs to be
// re-worked. Currently, when we snapshot, we collapse any pending
// transformations which should have occurred relative to LocalClock::now()
// into the current transformation. For both video and audio, however, we are
// always mixing/composing for a point in time in the near future, not for
// right now. We really want to given the mixer compositor a view of what the
// transformation is going to be at the mix/composition point, not what it is
// now. Additionally, since audio process many frames at a time, we need to
// give the audio mixer some knowledge of when we think the snapshotted
// transformation is going to change next. The audio mixer wants to mix up to
// that point, but not past it, and then fetch the new transformation before
// proceeding.
void SnapshotCurrentTransform(LinearTransform* out,
uint32_t* generation = nullptr);
// RateControl interface
//
void GetCurrentTransform(const GetCurrentTransformCallback& cbk) override;
void SetTargetTimelineID(uint32_t id) override;
void SetCurrentQuad(TimelineQuadPtr quad) override;
void SetRate(int32_t reference_delta, uint32_t target_delta) override;
void SetRateAtReferenceTime(int32_t reference_delta,
uint32_t target_delta,
int64_t reference_time) override;
void SetRateAtTargetTime(int32_t reference_delta,
uint32_t target_delta,
int64_t target_time) override;
void CancelPendingChanges() override;
protected:
void ApplyPendingChangesLocked(int64_t target_now);
void AdvanceGenerationLocked() {
// bump the generation counter. Do not use the value 0.
while (!(++generation_)) {}
}
void OnIllegalRateChange(int32_t numerator, uint32_t denominator);
Binding<RateControl> binding_;
uint32_t target_timeline_id = TimelineTransform::kLocalTimeID;
// Transformation state.
//
// Note: We use the LinearTransforms such that space A is the target timeline
// and space B is the reference timeline. Applying this convention,
// transforming from target to reference is the "forward" transformation and
// is always defined. Transforming from reference to target is the "reverse"
// transformation, and is only defined when we are not paused.
// <pedantic>
// OK; It is defined, but the equation has a singularity and the mapping is
// not 1-to-1.
// </pedantic>.
base::Lock transform_lock_;
LinearTransform current_transform_;
std::deque<LinearTransform> reference_pending_changes_;
std::deque<LinearTransform> target_pending_changes_;
uint32_t generation_ = 1;
};
} // namespace media
} // namespace mojo
#endif // SERVICES_MEDIA_COMMON_RATE_CONTROL_BASE_H_