1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! This module contains types related to `Payload` sent from the device.
//!
//! `Payload` is an abstracted container that is mainly used to transfer an image, but also meta data of the image.
//! See [`Payload`] and [`ImageInfo`] for more details.
pub use cameleon_device::PixelFormat;
use std::time;
use async_channel::{Receiver, Sender};
use super::{StreamError, StreamResult};
/// Represents Payload type of the image.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PayloadType {
/// Payload contains just an image data only.
Image,
/// Payload contains multiple data chunks, and its first chunk is an image.
ImageExtendedChunk,
/// Payload contains multiple data chunks, no gurantee about its first chunk.
Chunk,
}
/// Image meta information.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ImageInfo {
/// Width of the image.
pub width: usize,
/// Height of the image.
pub height: usize,
/// X offset in pixels from the whole image origin. Some devices have capability of
/// sending multiple extracted image regions, this fields used for the purpose.
pub x_offset: usize,
/// Y offset in pixels from the whole image origin. Some devices have capability of
/// sending multiple extracted image regions, this fields used for the purpose.
pub y_offset: usize,
/// [`PixelFormat`] of the image.
pub pixel_format: PixelFormat,
/// Size of image in bytes.
pub image_size: usize,
}
/// A payload sent from the device.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Payload {
pub(crate) id: u64,
pub(crate) payload_type: PayloadType,
pub(crate) image_info: Option<ImageInfo>,
pub(crate) payload: Vec<u8>,
pub(crate) valid_payload_size: usize,
pub(crate) timestamp: time::Duration,
}
impl Payload {
/// Returns [`PayloadType`] of the payload.
pub fn payload_type(&self) -> PayloadType {
self.payload_type
}
/// Returns [`ImageInfo`] if `payload_type` is [`PayloadType::Image`] or
/// [`PayloadType::ImageExtendedChunk`].
pub fn image_info(&self) -> Option<&ImageInfo> {
self.image_info.as_ref()
}
/// Returns the image bytes in the payload if `payload_type` is [`PayloadType::Image`] or
/// [`PayloadType::ImageExtendedChunk`].
pub fn image(&self) -> Option<&[u8]> {
let image_info = self.image_info()?;
Some(&self.payload[..image_info.image_size])
}
/// Returns the whole payload. Use [`Self::image`] instead if you interested only
/// in image region of the payload.
pub fn payload(&self) -> &[u8] {
&self.payload[..self.valid_payload_size]
}
/// Returns unique id of `payload`, which sequentially incremented every time the device send a
/// `payload`.
pub fn id(&self) -> u64 {
self.id
}
/// Timestamp of the device when the payload is generated.
pub fn timestamp(&self) -> time::Duration {
self.timestamp
}
/// Returns the payload as `Vec<u8>`.
pub fn into_vec(mut self) -> Vec<u8> {
self.payload.resize(self.valid_payload_size, 0);
self.payload
}
}
/// An Receiver of the `Payload` which is sent from a device.
#[derive(Debug, Clone)]
pub struct PayloadReceiver {
/// Sends back `payload` to the device for reusing it.
tx: Sender<Payload>,
/// Receives `payload` from the device.
rx: Receiver<StreamResult<Payload>>,
}
impl PayloadReceiver {
/// Receives [`Payload`] sent from the device.
pub async fn recv(&self) -> StreamResult<Payload> {
self.rx.recv().await?
}
/// Tries to receive [`Payload`].
/// This method doesn't wait arrival of `payload` and immediately returns `StreamError` if
/// the channel is empty.
pub fn try_recv(&self) -> StreamResult<Payload> {
self.rx.try_recv()?
}
/// Receives [`Payload`] sent from the device.
/// If the channel is empty, this method blocks until the device produces the payload.
pub fn recv_blocking(&self) -> StreamResult<Payload> {
self.rx.recv_blocking()?
}
/// Sends back [`Payload`] to the device to reuse already allocated `payload`.
///
/// Sending back `payload` may improve performance of streaming, but not required to call this
/// method.
pub fn send_back(&self, payload: Payload) {
self.tx.try_send(payload).ok();
}
}
/// A sender of the [`Payload`] which is sent to the host.
#[derive(Debug, Clone)]
pub struct PayloadSender {
/// Receives from the device.
tx: Sender<StreamResult<Payload>>,
/// Sends back payload to reuse it.
rx: Receiver<Payload>,
}
impl PayloadSender {
/// Sends [`Payload`] to the host.
pub async fn send(&self, payload: StreamResult<Payload>) -> StreamResult<()> {
Ok(self.tx.send(payload).await?)
}
/// Tries to send [`Payload`] to the host.
/// Returns `StreamError` if the channel is full or empty.
pub fn try_send(&self, payload: StreamResult<Payload>) -> StreamResult<()> {
Ok(self.tx.try_send(payload)?)
}
/// Tries to receive [`Payload`].
/// This method doesn't wait arrival of `payload` and immediately returns `StreamError` if
/// the channel is empty.
pub fn try_recv(&self) -> StreamResult<Payload> {
Ok(self.rx.try_recv()?)
}
}
/// Creates [`PayloadReceiver`] and [`PayloadSender`].
pub fn channel(payload_cap: usize, buffer_cap: usize) -> (PayloadSender, PayloadReceiver) {
let (device_tx, host_rx) = async_channel::bounded(payload_cap);
let (host_tx, device_rx) = async_channel::bounded(buffer_cap);
(
PayloadSender {
tx: device_tx,
rx: device_rx,
},
PayloadReceiver {
tx: host_tx,
rx: host_rx,
},
)
}
impl From<async_channel::RecvError> for StreamError {
fn from(err: async_channel::RecvError) -> Self {
StreamError::ReceiveError(err.to_string().into())
}
}
impl From<async_channel::TryRecvError> for StreamError {
fn from(err: async_channel::TryRecvError) -> Self {
StreamError::ReceiveError(err.to_string().into())
}
}
impl<T> From<async_channel::SendError<T>> for StreamError {
fn from(err: async_channel::SendError<T>) -> Self {
StreamError::ReceiveError(err.to_string().into())
}
}
impl<T> From<async_channel::TrySendError<T>> for StreamError {
fn from(err: async_channel::TrySendError<T>) -> Self {
StreamError::ReceiveError(err.to_string().into())
}
}