blob: e38146cc6238c1f7f7b213db45c069f17e76e397 [file] [log] [blame]
// Copyright 2022 The Fuchsia 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 SRC_MEDIA_AUDIO_AUDIO_CORE_V2_STREAM_SINK_SERVER_H_
#define SRC_MEDIA_AUDIO_AUDIO_CORE_V2_STREAM_SINK_SERVER_H_
#include <fidl/fuchsia.audio/cpp/wire.h>
#include <fidl/fuchsia.media/cpp/wire.h>
#include <fidl/fuchsia.media2/cpp/wire.h>
#include <zircon/errors.h>
#include <deque>
#include <memory>
#include <unordered_map>
#include "src/media/audio/lib/format2/format.h"
#include "src/media/audio/lib/format2/stream_converter.h"
#include "src/media/audio/services/common/base_fidl_server.h"
#include "src/media/audio/services/common/memory_mapped_buffer.h"
namespace media_audio {
// This is intended to be used by capturers. Each capturer is represented by a ConsumerNode, which
// sends StreamSink messages to this server, which records the sequence of incoming packets, which
// can be read by the CapturePacket method.
class StreamSinkServer
: public BaseFidlServer<StreamSinkServer, fidl::WireServer, fuchsia_audio::StreamSink> {
public:
struct Args {
// Format of packets sent to this StreamSink.
Format format;
// The StreamSink client writes packets to this payload buffer.
std::shared_ptr<MemoryMappedBuffer> payload_buffer;
};
// The returned server will live until the `server_end` channel is closed.
static std::shared_ptr<StreamSinkServer> Create(
std::shared_ptr<const FidlThread> thread,
fidl::ServerEnd<fuchsia_audio::StreamSink> server_end, Args args);
// Implementation of fidl::WireServer<fuchsia_audio::StreamSink>.
void PutPacket(PutPacketRequestView request, PutPacketCompleter::Sync& completer) final;
void StartSegment(StartSegmentRequestView request, StartSegmentCompleter::Sync& completer) final;
void End(EndCompleter::Sync& completer) final;
void WillClose(WillCloseRequestView request, WillCloseCompleter::Sync& completer) final;
// Waits until `dest_bytes` has arrived via PutPacket, then writes that to `dest_buffer`. The
// callback is invoked once the packet is written. If multiple CapturePacket calls are pending
// concurrently, they are handled in sequential order. If sequential calls happen quickly enough,
// this will capture a continuous sequence of packets, otherwise there may be overflows.
using CaptureCallback =
fit::callback<void(int64_t timestamp, int64_t bytes_captured, zx::duration overflow)>;
void CapturePacket(void* dest_buffer, int64_t dest_bytes, CaptureCallback callback);
// Drop all pending packets.
void DiscardPackets();
private:
static inline constexpr std::string_view kClassName = "StreamSinkServer";
template <typename ServerT, template <typename T> typename FidlServerT, typename ProtocolT>
friend class BaseFidlServer;
explicit StreamSinkServer(Args args);
void ServePendingCaptures();
void CloseWithReason(fuchsia_media2::ConsumerClosedReason reason);
const Format format_;
const StreamConverter stream_converter_;
const std::shared_ptr<MemoryMappedBuffer> payload_buffer_;
struct PendingPacket {
zx::time timestamp;
zx::duration overflow; // how much overflow happened before this packet
char* data;
int64_t bytes_remaining;
zx::eventpair fence;
};
std::deque<PendingPacket> pending_packets_;
struct PendingCapture {
char* data;
int64_t bytes_remaining;
int64_t bytes_captured;
std::optional<zx::time> start_timestamp;
std::optional<zx::time> next_timestamp;
zx::duration overflow;
CaptureCallback callback;
};
std::deque<PendingCapture> pending_captures_;
std::optional<zx::time> next_continuous_timestamp_;
};
} // namespace media_audio
#endif // SRC_MEDIA_AUDIO_AUDIO_CORE_V2_STREAM_SINK_SERVER_H_