blob: 5e7f772b1a8709f3868f4bca640ab8589fa76b8d [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_VIDEO_CAPTURE_BROADCASTING_RECEIVER_H_
#define SERVICES_VIDEO_CAPTURE_BROADCASTING_RECEIVER_H_
#include <map>
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "build/build_config.h"
#include "media/capture/video/video_frame_receiver.h"
#include "media/capture/video_capture_types.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/video_capture/public/cpp/video_frame_access_handler.h"
#include "services/video_capture/public/mojom/video_frame_handler.mojom.h"
namespace video_capture {
// Implementation of media::VideoFrameReceiver that distributes frames to
// potentially multiple clients.
class BroadcastingReceiver : public media::VideoFrameReceiver {
public:
class BufferContext {
public:
BufferContext(int32_t buffer_id,
media::mojom::VideoBufferHandlePtr buffer_handle);
~BufferContext();
BufferContext(BufferContext&& other);
BufferContext& operator=(BufferContext&& other);
int32_t buffer_context_id() const { return buffer_context_id_; }
int32_t buffer_id() const { return buffer_id_; }
void IncreaseConsumerCount();
void DecreaseConsumerCount();
bool IsStillBeingConsumed() const;
bool is_retired() const { return is_retired_; }
void set_retired() { is_retired_ = true; }
media::mojom::VideoBufferHandlePtr CloneBufferHandle(
media::VideoCaptureBufferType target_buffer_type);
private:
int32_t buffer_context_id_;
int32_t buffer_id_;
media::mojom::VideoBufferHandlePtr buffer_handle_;
// Indicates how many consumers are currently relying on
// |access_permission_|.
int32_t consumer_hold_count_;
bool is_retired_;
};
BroadcastingReceiver();
~BroadcastingReceiver() override;
base::WeakPtr<media::VideoFrameReceiver> GetWeakPtr();
// Indicates to the BroadcastingReceiver that we want to restart the source
// without letting connected clients know about the restart. The
// BroadcastingReceiver will hide the OnStopped() event sent by the source
// from the connected clients and instead invoke the given
// |on_stopped_handler|. It will also not forward the subsequent
// OnStarted() and possibly OnStartedUsingGpuDecode() events to clients who
// have already received these events.
void HideSourceRestartFromClients(base::OnceClosure on_stopped_handler);
void SetOnStoppedHandler(base::OnceClosure on_stopped_handler);
// Returns a client_id that can be used for a call to Suspend/Resume/Remove.
int32_t AddClient(mojo::PendingRemote<mojom::VideoFrameHandler> client,
media::VideoCaptureBufferType target_buffer_type);
void SuspendClient(int32_t client_id);
void ResumeClient(int32_t client_id);
// Returns ownership of the client back to the caller.
mojo::Remote<mojom::VideoFrameHandler> RemoveClient(int32_t client_id);
// media::VideoFrameReceiver:
void OnCaptureConfigurationChanged() override;
void OnNewBuffer(int32_t buffer_id,
media::mojom::VideoBufferHandlePtr buffer_handle) override;
void OnFrameReadyInBuffer(media::ReadyFrameInBuffer frame) override;
void OnBufferRetired(int32_t buffer_id) override;
void OnError(media::VideoCaptureError error) override;
void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override;
void OnNewSubCaptureTargetVersion(
uint32_t sub_capture_target_version) override;
void OnFrameWithEmptyRegionCapture() override;
void OnLog(const std::string& message) override;
void OnStarted() override;
void OnStartedUsingGpuDecode() override;
void OnStopped() override;
private:
friend class BroadcastingReceiverTest;
enum class Status {
kOnStartedHasNotYetBeenCalled,
kOnStartedHasBeenCalled,
kOnStartedUsingGpuDecodeHasBeenCalled,
kDeviceIsRestarting,
kOnErrorHasBeenCalled,
kOnStoppedHasBeenCalled
};
// Wrapper that suppresses calls to OnStarted() and OnStartedUsingGpuDecode()
// after they have already been called once. Keeps track of whether or not
// a client is suspended.
class ClientContext {
public:
ClientContext(mojo::PendingRemote<mojom::VideoFrameHandler> client,
media::VideoCaptureBufferType target_buffer_type);
~ClientContext();
ClientContext(ClientContext&& other);
ClientContext& operator=(ClientContext&& other);
void OnStarted();
void OnStartedUsingGpuDecode();
mojo::Remote<mojom::VideoFrameHandler>& client() { return client_; }
media::VideoCaptureBufferType target_buffer_type() {
return target_buffer_type_;
}
void set_is_suspended(bool suspended) { is_suspended_ = suspended; }
bool is_suspended() const { return is_suspended_; }
void set_has_client_frame_access_handler_remote() {
has_client_frame_access_handler_remote_ = true;
}
bool has_client_frame_access_handler_remote() const {
return has_client_frame_access_handler_remote_;
}
private:
mojo::Remote<mojom::VideoFrameHandler> client_;
media::VideoCaptureBufferType target_buffer_type_;
bool is_suspended_;
bool on_started_has_been_called_;
bool on_started_using_gpu_decode_has_been_called_;
bool has_client_frame_access_handler_remote_;
};
class ClientVideoFrameAccessHandler;
void OnClientFinishedConsumingFrame(int32_t buffer_context_id);
void OnClientDisconnected(int32_t client_id);
std::vector<BufferContext>::iterator FindUnretiredBufferContextFromBufferId(
int32_t buffer_id);
SEQUENCE_CHECKER(sequence_checker_);
scoped_refptr<VideoFrameAccessHandlerRemote> frame_access_handler_remote_;
std::map<int32_t /*client_id*/, ClientContext> clients_;
std::vector<BufferContext> buffer_contexts_;
Status status_;
base::OnceClosure on_stopped_handler_;
// Keeps track of the last VideoCaptureError that arrived via OnError().
// This is used for relaying the error event to clients that connect after the
// OnError() call has been received.
media::VideoCaptureError error_;
std::map<
int32_t,
std::unique_ptr<
media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>>
scoped_access_permissions_by_buffer_context_id_;
// Keeps track of the id value for the next client to be added. This member is
// incremented each time a client is added and represents a unique identifier
// for each client.
int32_t next_client_id_;
base::WeakPtrFactory<BroadcastingReceiver> weak_factory_{this};
};
} // namespace video_capture
#endif // SERVICES_VIDEO_CAPTURE_BROADCASTING_RECEIVER_H_