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
use crate::connection::Connection;

use std::ffi::CStr;
use std::sync::atomic::{AtomicPtr, Ordering};

/// Different type of video streams supported.
pub enum StreamVideoType {
    /// This is a video stream coming from a camera.
    Camera,
    /// This is a video stream coming from a screen capture.
    Screen,
    /// This is a custom video stream.
    Custom,
    /// Unknown video stream type.
    __Unknown,
}

impl From<ffi::otc_stream_video_type> for StreamVideoType {
    fn from(type_: ffi::otc_stream_video_type) -> StreamVideoType {
        match type_ {
            ffi::otc_stream_video_type_OTC_STREAM_VIDEO_TYPE_CAMERA => StreamVideoType::Camera,
            ffi::otc_stream_video_type_OTC_STREAM_VIDEO_TYPE_SCREEN => StreamVideoType::Screen,
            ffi::otc_stream_video_type_OTC_STREAM_VIDEO_TYPE_CUSTOM => StreamVideoType::Custom,
            _ => StreamVideoType::__Unknown,
        }
    }
}

pub struct Stream {
    ptr: AtomicPtr<*const ffi::otc_stream>,
}

impl Stream {
    pub fn inner(&self) -> *const ffi::otc_stream {
        self.ptr.load(Ordering::Relaxed) as *const _
    }

    string_getter!(
        /// Gets the uniquer identifier for this stream.
        => (id, otc_stream_get_id)
    );
    string_getter!(
        /// Gets the name of the stream. The publisher of the stream
        /// can set this name to identify the stream.
        => (name, otc_stream_get_name)
    );

    /// Checks whether this stream is currently publishing video or not.
    pub fn has_video(&self) -> bool {
        unsafe { ffi::otc_stream_has_video(self.ptr.load(Ordering::Relaxed) as *const _) != 0 }
    }

    /// Checks whether this stream contains a video track or not.
    pub fn has_video_track(&self) -> bool {
        unsafe {
            ffi::otc_stream_has_video_track(self.ptr.load(Ordering::Relaxed) as *const _) != 0
        }
    }

    /// Checks whether this stream is currently publishing audio or not.
    pub fn has_audio(&self) -> bool {
        unsafe { ffi::otc_stream_has_audio(self.ptr.load(Ordering::Relaxed) as *const _) != 0 }
    }

    /// Checks whether this stream contains an audio track or not.
    pub fn has_audio_track(&self) -> bool {
        unsafe {
            ffi::otc_stream_has_audio_track(self.ptr.load(Ordering::Relaxed) as *const _) != 0
        }
    }

    /// Return the width of the stream in pixels.
    pub fn get_video_width(&self) -> i32 {
        unsafe { ffi::otc_stream_get_video_width(self.ptr.load(Ordering::Relaxed) as *const _) }
    }

    /// Return the height of the stream in pixels.
    pub fn get_video_height(&self) -> i32 {
        unsafe { ffi::otc_stream_get_video_height(self.ptr.load(Ordering::Relaxed) as *const _) }
    }

    /// Get the creation time of the stream.
    pub fn get_creation_time(&self) -> i64 {
        unsafe { ffi::otc_stream_get_creation_time(self.ptr.load(Ordering::Relaxed) as *const _) }
    }

    pub fn get_video_type(&self) -> StreamVideoType {
        unsafe { ffi::otc_stream_get_video_type(self.ptr.load(Ordering::Relaxed) as *const _) }
            .into()
    }

    /// Get the Connection associated with the client publishing the stream.
    pub fn get_connection(&self) -> Connection {
        unsafe { ffi::otc_stream_get_connection(self.ptr.load(Ordering::Relaxed) as *const _) }
            .into()
    }
}

impl Clone for Stream {
    fn clone(&self) -> Self {
        (self.ptr.load(Ordering::Relaxed) as *const ffi::otc_stream).into()
    }
}

impl Drop for Stream {
    fn drop(&mut self) {
        let ptr = self.ptr.load(Ordering::Relaxed);

        if ptr.is_null() {
            return;
        }

        unsafe {
            ffi::otc_stream_delete(ptr as *mut _);
        }

        self.ptr.store(std::ptr::null_mut(), Ordering::Relaxed);
    }
}

impl From<*const ffi::otc_stream> for Stream {
    #[allow(clippy::not_unsafe_ptr_arg_deref)]
    fn from(ptr: *const ffi::otc_stream) -> Stream {
        let ptr = unsafe { ffi::otc_stream_copy(ptr) };
        Stream {
            ptr: AtomicPtr::new(ptr as *mut _),
        }
    }
}