added initial draft of lib-gst-meet-c. added shell.nix for deps
This commit is contained in:
parent
2634c68ad6
commit
9af6db6c02
|
@ -667,6 +667,17 @@ dependencies = [
|
||||||
"xmpp-parsers-gst-meet",
|
"xmpp-parsers-gst-meet",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lib-gst-meet-c"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"glib",
|
||||||
|
"gstreamer",
|
||||||
|
"lib-gst-meet",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.99"
|
version = "0.2.99"
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
members = [
|
members = [
|
||||||
"gst-meet",
|
"gst-meet",
|
||||||
"lib-gst-meet",
|
"lib-gst-meet",
|
||||||
|
"lib-gst-meet-c",
|
||||||
"nice-gst-meet",
|
"nice-gst-meet",
|
||||||
"nice-gst-meet-sys",
|
"nice-gst-meet-sys",
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
[package]
|
||||||
|
name = "lib-gst-meet-c"
|
||||||
|
description = "Connect GStreamer pipelines to Jitsi Meet conferences (C bindings)"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT/Apache-2.0"
|
||||||
|
authors = ["Jasper Hugo <jasper@avstack.io>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = { version = "1", default-features = false }
|
||||||
|
glib = { version = "0.14", default-features = false }
|
||||||
|
gstreamer = { version = "0.17", default-features = false }
|
||||||
|
lib-gst-meet = { version = "0.1", path = "../lib-gst-meet", default-features = false }
|
||||||
|
tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "gstmeet"
|
||||||
|
crate_type = ["staticlib", "cdylib"]
|
|
@ -0,0 +1,3 @@
|
||||||
|
language = "C"
|
||||||
|
include_guard = "gstmeet_h"
|
||||||
|
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
|
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef gstmeet_h
|
||||||
|
#define gstmeet_h
|
||||||
|
|
||||||
|
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef struct Context Context;
|
||||||
|
|
||||||
|
typedef struct ConferenceConfig {
|
||||||
|
const char *muc;
|
||||||
|
const char *focus;
|
||||||
|
const char *nick;
|
||||||
|
const char *region;
|
||||||
|
const char *video_codec;
|
||||||
|
} ConferenceConfig;
|
||||||
|
|
||||||
|
typedef struct Participant {
|
||||||
|
const char *jid;
|
||||||
|
const char *muc_jid;
|
||||||
|
const char *nick;
|
||||||
|
} Participant;
|
||||||
|
|
||||||
|
struct Context *gstmeet_init(void);
|
||||||
|
|
||||||
|
void gstmeet_deinit(struct Context *context);
|
||||||
|
|
||||||
|
JitsiConnection *gstmeet_connection_new(struct Context *context,
|
||||||
|
const char *websocket_url,
|
||||||
|
const char *xmpp_domain);
|
||||||
|
|
||||||
|
void gstmeet_connection_free(JitsiConnection *connection);
|
||||||
|
|
||||||
|
bool gstmeet_connection_connect(struct Context *context, JitsiConnection *connection);
|
||||||
|
|
||||||
|
JitsiConference *gstmeet_connection_join_conference(struct Context *context,
|
||||||
|
JitsiConnection *connection,
|
||||||
|
GMainContext *glib_main_context,
|
||||||
|
const struct ConferenceConfig *config);
|
||||||
|
|
||||||
|
bool gstmeet_conference_connected(struct Context *context, JitsiConference *conference);
|
||||||
|
|
||||||
|
bool gstmeet_conference_leave(struct Context *context, JitsiConference *conference);
|
||||||
|
|
||||||
|
bool gstmeet_conference_set_muted(struct Context *context,
|
||||||
|
JitsiConference *conference,
|
||||||
|
MediaType media_type,
|
||||||
|
bool muted);
|
||||||
|
|
||||||
|
GstPipeline *gstmeet_conference_pipeline(struct Context *context, JitsiConference *conference);
|
||||||
|
|
||||||
|
GstElement *gstmeet_conference_audio_sink_element(struct Context *context,
|
||||||
|
JitsiConference *conference);
|
||||||
|
|
||||||
|
GstElement *gstmeet_conference_video_sink_element(struct Context *context,
|
||||||
|
JitsiConference *conference);
|
||||||
|
|
||||||
|
void gstmeet_conference_on_participant(struct Context *context,
|
||||||
|
JitsiConference *conference,
|
||||||
|
GstBin *(*f)(struct Participant));
|
||||||
|
|
||||||
|
#endif /* gstmeet_h */
|
|
@ -0,0 +1,211 @@
|
||||||
|
use std::{
|
||||||
|
ffi::{CStr, CString},
|
||||||
|
os::raw::c_char,
|
||||||
|
ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use glib::{ffi::GMainContext, translate::{from_glib_full, ToGlibPtr}};
|
||||||
|
pub use lib_gst_meet::{JitsiConference, JitsiConnection, MediaType};
|
||||||
|
use lib_gst_meet::JitsiConferenceConfig;
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
|
pub struct Context {
|
||||||
|
runtime: Runtime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ConferenceConfig {
|
||||||
|
pub muc: *const c_char,
|
||||||
|
pub focus: *const c_char,
|
||||||
|
pub nick: *const c_char,
|
||||||
|
pub region: *const c_char,
|
||||||
|
pub video_codec: *const c_char,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Participant {
|
||||||
|
pub jid: *const c_char,
|
||||||
|
pub muc_jid: *const c_char,
|
||||||
|
pub nick: *const c_char,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ResultExt<T> {
|
||||||
|
fn ok_raw_or_log(self) -> *mut T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ResultExt<T> for Result<T> {
|
||||||
|
fn ok_raw_or_log(self) -> *mut T {
|
||||||
|
match self {
|
||||||
|
Ok(o) => Box::into_raw(Box::new(o)),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("lib-gst-meet: {:?}", e);
|
||||||
|
ptr::null_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn gstmeet_init() -> *mut Context {
|
||||||
|
Runtime::new()
|
||||||
|
.map(|runtime| Context { runtime })
|
||||||
|
.map_err(|e| e.into())
|
||||||
|
.ok_raw_or_log()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_deinit(context: *mut Context) {
|
||||||
|
Box::from_raw(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_connection_new(
|
||||||
|
context: *mut Context,
|
||||||
|
websocket_url: *const c_char,
|
||||||
|
xmpp_domain: *const c_char,
|
||||||
|
) -> *mut JitsiConnection {
|
||||||
|
let websocket_url = CStr::from_ptr(websocket_url);
|
||||||
|
let xmpp_domain = CStr::from_ptr(xmpp_domain);
|
||||||
|
(*context)
|
||||||
|
.runtime
|
||||||
|
.block_on(JitsiConnection::new(&websocket_url.to_string_lossy(), &xmpp_domain.to_string_lossy()))
|
||||||
|
.map(|(connection, background)| {
|
||||||
|
(*context).runtime.spawn(background);
|
||||||
|
connection
|
||||||
|
})
|
||||||
|
.ok_raw_or_log()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_connection_free(connection: *mut JitsiConnection) {
|
||||||
|
Box::from_raw(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_connection_connect(context: *mut Context, connection: *mut JitsiConnection) -> bool {
|
||||||
|
(*context)
|
||||||
|
.runtime
|
||||||
|
.block_on((*connection).connect())
|
||||||
|
.map_err(|e| eprintln!("lib-gst-meet: {:?}", e))
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_connection_join_conference(
|
||||||
|
context: *mut Context,
|
||||||
|
connection: *mut JitsiConnection,
|
||||||
|
glib_main_context: *mut GMainContext,
|
||||||
|
config: *const ConferenceConfig,
|
||||||
|
) -> *mut JitsiConference {
|
||||||
|
let muc = match CStr::from_ptr((*config).muc).to_string_lossy().parse() {
|
||||||
|
Ok(jid) => jid,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("lib-gst-meet: invalid MUC JID: {:?}", e);
|
||||||
|
return ptr::null_mut();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let focus = match CStr::from_ptr((*config).focus).to_string_lossy().parse() {
|
||||||
|
Ok(jid) => jid,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("lib-gst-meet: invalid focus JID: {:?}", e);
|
||||||
|
return ptr::null_mut();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let config = JitsiConferenceConfig {
|
||||||
|
muc,
|
||||||
|
focus,
|
||||||
|
nick: CStr::from_ptr((*config).nick).to_string_lossy().to_string(),
|
||||||
|
region: CStr::from_ptr((*config).region).to_string_lossy().to_string(),
|
||||||
|
video_codec: CStr::from_ptr((*config).video_codec).to_string_lossy().to_string(),
|
||||||
|
};
|
||||||
|
(*context)
|
||||||
|
.runtime
|
||||||
|
.block_on((*connection).join_conference(from_glib_full(glib_main_context), config))
|
||||||
|
.ok_raw_or_log()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_conference_connected(context: *mut Context, conference: *mut JitsiConference) -> bool {
|
||||||
|
(*context)
|
||||||
|
.runtime
|
||||||
|
.block_on((*conference).connected())
|
||||||
|
.map_err(|e| eprintln!("lib-gst-meet: {:?}", e))
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_conference_leave(context: *mut Context, conference: *mut JitsiConference) -> bool {
|
||||||
|
(*context)
|
||||||
|
.runtime
|
||||||
|
.block_on(Box::from_raw(conference).connected())
|
||||||
|
.map_err(|e| eprintln!("lib-gst-meet: {:?}", e))
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_conference_set_muted(context: *mut Context, conference: *mut JitsiConference, media_type: MediaType, muted: bool) -> bool {
|
||||||
|
(*context)
|
||||||
|
.runtime
|
||||||
|
.block_on((*conference).set_muted(media_type, muted))
|
||||||
|
.map_err(|e| eprintln!("lib-gst-meet: {:?}", e))
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_conference_pipeline(context: *mut Context, conference: *mut JitsiConference) -> *mut gstreamer::ffi::GstPipeline {
|
||||||
|
(*context)
|
||||||
|
.runtime
|
||||||
|
.block_on((*conference).pipeline())
|
||||||
|
.map(|pipeline| pipeline.to_glib_full())
|
||||||
|
.map_err(|e| eprintln!("lib-gst-meet: {:?}", e))
|
||||||
|
.unwrap_or(ptr::null_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_conference_audio_sink_element(context: *mut Context, conference: *mut JitsiConference) -> *mut gstreamer::ffi::GstElement {
|
||||||
|
(*context)
|
||||||
|
.runtime
|
||||||
|
.block_on((*conference).audio_sink_element())
|
||||||
|
.map(|pipeline| pipeline.to_glib_full())
|
||||||
|
.map_err(|e| eprintln!("lib-gst-meet: {:?}", e))
|
||||||
|
.unwrap_or(ptr::null_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_conference_video_sink_element(context: *mut Context, conference: *mut JitsiConference) -> *mut gstreamer::ffi::GstElement {
|
||||||
|
(*context)
|
||||||
|
.runtime
|
||||||
|
.block_on((*conference).video_sink_element())
|
||||||
|
.map(|pipeline| pipeline.to_glib_full())
|
||||||
|
.map_err(|e| eprintln!("lib-gst-meet: {:?}", e))
|
||||||
|
.unwrap_or(ptr::null_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn gstmeet_conference_on_participant(
|
||||||
|
context: *mut Context,
|
||||||
|
conference: *mut JitsiConference,
|
||||||
|
f: unsafe extern "C" fn(Participant) -> *mut gstreamer::ffi::GstBin,
|
||||||
|
) {
|
||||||
|
(*context)
|
||||||
|
.runtime
|
||||||
|
.block_on((*conference).on_participant(move |participant| Box::pin(async move {
|
||||||
|
let participant = Participant {
|
||||||
|
jid: CString::new(participant.jid.to_string())?.into_raw() as *const _,
|
||||||
|
muc_jid: CString::new(participant.muc_jid.to_string())?.into_raw() as *const _,
|
||||||
|
nick: participant
|
||||||
|
.nick
|
||||||
|
.map(|nick| Ok::<_, anyhow::Error>(CString::new(nick)?.into_raw() as *const _))
|
||||||
|
.transpose()?
|
||||||
|
.unwrap_or_else(ptr::null),
|
||||||
|
};
|
||||||
|
let maybe_bin = f(participant);
|
||||||
|
if maybe_bin.is_null() {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Ok(Some(from_glib_full(maybe_bin)))
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ pub struct Source {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
|
#[repr(C)]
|
||||||
pub enum MediaType {
|
pub enum MediaType {
|
||||||
Video,
|
Video,
|
||||||
Audio,
|
Audio,
|
||||||
|
|
Loading…
Reference in New Issue