Skip to content
Extraits de code Groupes Projets
Vérifiée Valider dee59503 rédigé par Kubat's avatar Kubat
Parcourir les fichiers

LEKTORD: Split the c_wrapper thing into smaller files

parent b3d2e11c
Aucune branche associée trouvée
Aucune étiquette associée trouvée
1 requête de fusion!197Draft: Refactor the whole code.
/// So the C/C++ part of the code can call the Rust panic and unwind things. With that tokio can
/// catch an abort and stay alive.
#[export_name = "___lkt_abort"]
pub(super) extern "C" fn lkt_abort() {
panic!()
}
use super::{PlayerEvent, STATE};
use anyhow::{bail, Error, Result};
use lektor_nkdb::PlayState;
use lektor_utils::*;
use std::{ffi::*, path::Path, ptr::NonNull};
/// Safe wrapper around `mod_stop_playback`. Stops the playback. Same as [player_toggle_pause], don't update
/// the database yourself, it will be done by a callback chain.
pub(crate) fn player_stop() -> Result<()> {
extern "C" {
fn mod_stop_playback() -> c_int;
}
if 0 != unsafe { mod_stop_playback() } {
bail!("failed to stop playback")
}
Ok(())
}
/// Safe wrapper around `mod_set_paused`. Set the pause state of the player. Same remark as
/// [player_toggle_pause], don't update the database yourself, it will be done by a callback chain
/// latter.
pub(crate) fn player_set_paused(state: PlayState) -> Result<()> {
extern "C" {
fn mod_set_paused(_: c_int) -> c_int;
}
let paused = match state {
PlayState::Stop => bail!("can't convert stop into a paused flag"),
PlayState::Play => 0 as c_int,
PlayState::Pause => 1 as c_int,
};
if 0 != unsafe { mod_set_paused(paused) } {
bail!("failed to set paused state to {state:?}")
}
Ok(())
}
/// Safe wrapper around `mod_toggle_pause`. Send the toggle signal to the player. No need to update
/// the database in addition to this call, the database will be updated when the change will be
/// made in the mpv player.
pub(crate) fn player_toggle_pause() -> Result<()> {
extern "C" {
fn mod_toggle_pause() -> c_int;
}
if 0 != unsafe { mod_toggle_pause() } {
anyhow::bail!("failed to toggle pause state")
}
Ok(())
}
/// Safe wrapper around `mod_set_position` Set the position in the player module.
#[allow(dead_code)]
pub(crate) fn player_set_position(position: i64) -> Result<()> {
extern "C" {
fn mod_set_position(_: c_int) -> c_int;
}
let position = c_int::try_from(position)?;
if 0 != unsafe { mod_set_position(position) } {
anyhow::bail!("failed to set player position to {position}s")
}
Ok(())
}
/// Safe wrapper around `mod_get_duration` Get the duration of the current playing file.
pub(crate) fn player_get_duration() -> Result<i64> {
extern "C" {
fn mod_get_duration(_: NonNull<c_int>) -> c_int;
}
let mut duration: c_int = 0;
if 0 != unsafe { mod_get_duration(NonNull::new_unchecked((&mut duration) as *mut _)) } {
anyhow::bail!("failed to get current kara duration")
}
Ok(duration.into())
}
/// Safe wrapper around `mod_get_elapsed` Get the duration since the begin of the kara.
pub(crate) fn player_get_elapsed() -> Result<i64> {
extern "C" {
fn mod_get_elapsed(_: NonNull<c_int>) -> c_int;
}
let mut elapsed: c_int = 0;
if 0 != unsafe { mod_get_elapsed(NonNull::new_unchecked((&mut elapsed) as *mut _)) } {
anyhow::bail!("failed to get current kara elapsed time since start of file")
}
Ok(elapsed.into())
}
/// Safe wrapper around `mod_load_file` Tell the player to load a file by its path.
pub(crate) fn player_load_file(path: impl AsRef<Path>, id: u64) -> Result<()> {
extern "C" {
fn mod_load_file(_: NonNull<c_char>, _: u64) -> c_int;
}
let path = path
.as_ref()
.to_str()
.ok_or_else(|| Error::msg("path contained non-utf8 characters"))?;
let cstr = CString::new(path)?;
if 0 != unsafe { mod_load_file(NonNull::new_unchecked(cstr.as_ptr() as *mut _), id) } {
anyhow::bail!("failed load file {path}")
}
Ok(())
}
/// Safe wrapper around `mod_set_volume` Set the volume of the player.
#[allow(dead_code)]
pub(crate) fn player_set_playback_volume(vol: i64) -> Result<()> {
extern "C" {
fn mod_set_volume(_: c_int) -> c_int;
}
let vol = c_int::try_from(vol)?.clamp(0, 100);
if 0 != unsafe { mod_set_volume(vol) } {
anyhow::bail!("failed to set player volume to {vol}%")
}
Ok(())
}
fn send_msg(msg: PlayerEvent) {
if let Some((sender, _)) = unsafe { STATE.get() } {
if let Err(err) = sender.blocking_send(msg) {
log::error!("failed to send msg {msg:?}: {err}");
}
} else {
log::error!("no lektord state was set for the player module")
}
}
/// Set the play state in the database, the signal is send from the player.
#[no_mangle]
pub(super) extern "C" fn lkt_toggle_play_state(state: c_int) {
send_msg(PlayerEvent::SetPlayState(state))
}
/// The player needs to play the next kara in the queue.
#[no_mangle]
pub(super) extern "C" fn lkt_play_next() {
send_msg(PlayerEvent::PlayNext)
}
/// The player needs to play the previous kara in the queue or in the history.
#[no_mangle]
pub(super) extern "C" fn lkt_play_prev() {
send_msg(PlayerEvent::PlayPrev)
}
//! Interface with the C/C++ part of the code. The only place we allow unsafe code in this crate.
use crate::LektorStatePtr;
use anyhow::{bail, Error, Result};
use anyhow::{bail, Result};
use lektor_nkdb::PlayState;
use lektor_utils::{config::LektorPlayerConfig, *};
use std::{
ffi::*,
path::Path,
ptr::NonNull,
sync::{Arc, OnceLock},
};
mod abort;
mod commands;
mod loging;
mod playstate;
use playstate::*;
use self::{abort::*, playstate::*};
pub(crate) use commands::*;
/// The lektord state pointer to pass to the player module. Should be better to pass to its
/// constructor...
......@@ -159,147 +162,3 @@ pub async fn close_player_module() -> Result<()> {
Ok(())
}
/// Safe wrapper around `mod_stop_playback`. Stops the playback. Same as [player_toggle_pause], don't update
/// the database yourself, it will be done by a callback chain.
pub(crate) fn player_stop() -> Result<()> {
extern "C" {
fn mod_stop_playback() -> c_int;
}
if 0 != unsafe { mod_stop_playback() } {
bail!("failed to stop playback")
}
Ok(())
}
/// Safe wrapper around `mod_set_paused`. Set the pause state of the player. Same remark as
/// [player_toggle_pause], don't update the database yourself, it will be done by a callback chain
/// latter.
pub(crate) fn player_set_paused(state: PlayState) -> Result<()> {
extern "C" {
fn mod_set_paused(_: c_int) -> c_int;
}
let paused = match state {
PlayState::Stop => bail!("can't convert stop into a paused flag"),
PlayState::Play => 0 as c_int,
PlayState::Pause => 1 as c_int,
};
if 0 != unsafe { mod_set_paused(paused) } {
bail!("failed to set paused state to {state:?}")
}
Ok(())
}
/// Safe wrapper around `mod_toggle_pause`. Send the toggle signal to the player. No need to update
/// the database in addition to this call, the database will be updated when the change will be
/// made in the mpv player.
pub(crate) fn player_toggle_pause() -> Result<()> {
extern "C" {
fn mod_toggle_pause() -> c_int;
}
if 0 != unsafe { mod_toggle_pause() } {
anyhow::bail!("failed to toggle pause state")
}
Ok(())
}
/// Safe wrapper around `mod_set_position` Set the position in the player module.
#[allow(dead_code)]
pub(crate) fn player_set_position(position: i64) -> Result<()> {
extern "C" {
fn mod_set_position(_: c_int) -> c_int;
}
let position = c_int::try_from(position)?;
if 0 != unsafe { mod_set_position(position) } {
anyhow::bail!("failed to set player position to {position}s")
}
Ok(())
}
/// Safe wrapper around `mod_get_duration` Get the duration of the current playing file.
pub(crate) fn player_get_duration() -> Result<i64> {
extern "C" {
fn mod_get_duration(_: NonNull<c_int>) -> c_int;
}
let mut duration: c_int = 0;
if 0 != unsafe { mod_get_duration(NonNull::new_unchecked((&mut duration) as *mut _)) } {
anyhow::bail!("failed to get current kara duration")
}
Ok(duration.into())
}
/// Safe wrapper around `mod_get_elapsed` Get the duration since the begin of the kara.
pub(crate) fn player_get_elapsed() -> Result<i64> {
extern "C" {
fn mod_get_elapsed(_: NonNull<c_int>) -> c_int;
}
let mut elapsed: c_int = 0;
if 0 != unsafe { mod_get_elapsed(NonNull::new_unchecked((&mut elapsed) as *mut _)) } {
anyhow::bail!("failed to get current kara elapsed time since start of file")
}
Ok(elapsed.into())
}
/// Safe wrapper around `mod_load_file` Tell the player to load a file by its path.
pub(crate) fn player_load_file(path: impl AsRef<Path>, id: u64) -> Result<()> {
extern "C" {
fn mod_load_file(_: NonNull<c_char>, _: u64) -> c_int;
}
let path = path
.as_ref()
.to_str()
.ok_or_else(|| Error::msg("path contained non-utf8 characters"))?;
let cstr = CString::new(path)?;
if 0 != unsafe { mod_load_file(NonNull::new_unchecked(cstr.as_ptr() as *mut _), id) } {
anyhow::bail!("failed load file {path}")
}
Ok(())
}
/// Safe wrapper around `mod_set_volume` Set the volume of the player.
#[allow(dead_code)]
pub(crate) fn player_set_playback_volume(vol: i64) -> Result<()> {
extern "C" {
fn mod_set_volume(_: c_int) -> c_int;
}
let vol = c_int::try_from(vol)?.clamp(0, 100);
if 0 != unsafe { mod_set_volume(vol) } {
anyhow::bail!("failed to set player volume to {vol}%")
}
Ok(())
}
fn send_msg(msg: PlayerEvent) {
if let Some((sender, _)) = unsafe { STATE.get() } {
if let Err(err) = sender.blocking_send(msg) {
log::error!("failed to send msg {msg:?}: {err}");
}
} else {
log::error!("no lektord state was set for the player module")
}
}
/// Set the play state in the database, the signal is send from the player.
#[no_mangle]
extern "C" fn lkt_toggle_play_state(state: c_int) {
send_msg(PlayerEvent::SetPlayState(state))
}
/// The player needs to play the next kara in the queue.
#[no_mangle]
extern "C" fn lkt_play_next() {
send_msg(PlayerEvent::PlayNext)
}
/// The player needs to play the previous kara in the queue or in the history.
#[no_mangle]
extern "C" fn lkt_play_prev() {
send_msg(PlayerEvent::PlayPrev)
}
/// So the C/C++ part of the code can call the Rust panic and unwind things. With that tokio can
/// catch an abort and stay alive.
#[export_name = "___lkt_abort"]
extern "C" fn lkt_abort() {
panic!()
}
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter