Newer
Older
/**
* @file streams.hpp
* @copyright Copyright (c) 2022 University of Turku, MIT License
* @author Nicolas Pope
*/
#pragma once
#include <ftl/handle.hpp>
#include <ftl/threads.hpp>
#include <ftl/protocol/channels.hpp>
#include <ftl/protocol/channelSet.hpp>
#include <ftl/protocol/packet.hpp>
#include <string>
#include <vector>
#include <unordered_set>
namespace ftl {
namespace protocol {
/* Represents a request for data through a stream */
struct Request {
ftl::protocol::Channel channel;
int bitrate;
int count;
ftl::protocol::Codec codec;
};
using RequestCallback = std::function<bool(const ftl::protocol::Request&)>;
using StreamCallback = std::function<bool(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &)>;
kMaxBitrate,
kAdaptiveBitrate,
kObservers,
kURI
};
enum struct StreamType {
kMixed,
kUnknown,
kLive,
kRecorded
};
/**
* Base stream class to be implemented. Provides encode and decode functionality
* around a generic packet read and write mechanism. Some specialisations will
* provide and automatically handle control signals.
*
* Streams are bidirectional, frames can be both received and written.
*/
class Stream {
public:
virtual ~Stream() {};
/**
* Obtain all packets for next frame. The provided callback function is
* called once for every packet. This function might continue to call the
* callback even after the read function returns, for example with a
* NetStream.
*/
ftl::Handle onPacket(const StreamCallback &cb) { return cb_.on(cb); }
ftl::Handle onRequest(const std::function<bool(const Request &)> &cb) { return request_cb_.on(cb); }
virtual bool post(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &)=0;
// TODO: Add methods for: pause, paused, statistics
/**
* Start the stream. Calls to the onPacket callback will only occur after
* a call to this function (and before a call to end()).
*/
virtual bool begin()=0;
virtual bool end()=0;
/**
* Is the stream active? Generally true if begin() has been called, false
* initially and after end(). However, it may go false for other reasons.
* If false, no calls to onPacket will occur and posts will be ignored.
*/
virtual bool active()=0;
/**
* @brief Clear all state. This will remove all information about available
* and enabled frames or channels. You will then need to enable frames and
* channels again. If active the stream will remain active.
*
* @brief Re-request all channels and state. This will also cause video encoding
* to generate new I-frames as if a new connection is made. All persistent data
* channels would also become available. For file streams this would reset the
* stream to the beginning of the file.
*
*/
virtual void refresh();
/**
* @brief Check if a frame is available.
*
* @param id Frameset and frame number
* @return true if data is available for the frame
* @return false if no data has been seen
bool available(FrameID id) const;
bool available(FrameID id, ftl::protocol::Channel channel) const;
bool available(FrameID id, const ftl::protocol::ChannelSet channels) const;
ftl::Handle onAvailable(const std::function<bool(FrameID, ftl::protocol::Channel)> &cb) { return avail_cb_.on(cb); }
* @brief Get all channels seen for a frame. If the frame does not exist then
* an empty set is returned.
*
* @param id Frameset and frame number
* @return Set of all seen channels, or empty.
ftl::protocol::ChannelSet channels(FrameID id) const;
ftl::protocol::ChannelSet enabledChannels(FrameID id) const;
* @brief Get all available frames in the stream.
*
* @return Set of frame IDs
std::unordered_set<FrameID> frames() const;
/**
* @brief Get all enabled frames in the stream.
*
* @return Set of frame IDs
*/
std::unordered_set<FrameID> enabled() const;
/**
* @brief Check if a frame is enabled.
*
* @param id Frameset and frame number
* @return true if data for this frame is enabled.
* @return false if data not enabled or frame does not exist.
*/
bool enabled(FrameID id) const;
bool enabled(FrameID id, ftl::protocol::Channel channel) const;
/**
* Number of framesets in stream.
*/
inline size_t size() const { return state_.size(); }
virtual bool enable(FrameID id);
virtual bool enable(FrameID id, ftl::protocol::Channel channel);
virtual bool enable(FrameID id, const ftl::protocol::ChannelSet &channels);
// TODO: Disable
virtual void setProperty(ftl::protocol::StreamProperty opt, int value)=0;
virtual int getProperty(ftl::protocol::StreamProperty opt)=0;
virtual bool supportsProperty(ftl::protocol::StreamProperty opt)=0;
virtual StreamType type() const { return StreamType::kUnknown; }
void trigger(const ftl::protocol::StreamPacket &spkt, const ftl::protocol::Packet &pkt);
void seen(FrameID id, ftl::protocol::Channel channel);
void request(const Request &req);
mutable SHARED_MUTEX mtx_;
ftl::protocol::ChannelSet selected;
ftl::protocol::ChannelSet available;
ftl::Handler<const ftl::protocol::StreamPacket&, const ftl::protocol::Packet&> cb_;
ftl::Handler<const Request &> request_cb_;
ftl::Handler<FrameID, ftl::protocol::Channel> avail_cb_;
std::unordered_map<int, FSState> state_;