diff --git a/src/core.rs b/src/core.rs
index 003ad11..236de3c 100644
--- a/src/core.rs
+++ b/src/core.rs
@@ -5,7 +5,7 @@
 use std::ptr;
 use std::borrow::Cow;
 use std::marker::PhantomData;
-use std::ffi::CString;
+use std::ffi::{CString, CStr};
 use std::i32;
 use libc::{c_void, c_char, c_int};
 use crate::sys;
@@ -31,6 +31,8 @@ pub struct Instance {
 
 }
 
+unsafe impl Send for Instance {}
+
 impl Instance {
     /// Create and initialize a libvlc instance with specified args.
     /// Note: args.len() has to be less or equal to i32::MAX
@@ -119,6 +121,15 @@ impl Instance {
         }
     }
 
+    /// Returns the VLM event manager
+    pub fn vlm_event_manager<'a>(&'a self) -> EventManager<'a> {
+        unsafe{
+            let p = sys::libvlc_vlm_get_event_manager(self.ptr);
+            assert!(!p.is_null());
+            EventManager{ptr: p, _phantomdata: ::std::marker::PhantomData}
+        }
+    }
+
     /// Set logging callback
     pub fn set_log<F: Fn(LogLevel, Log, Cow<str>) + Send + 'static>(&self, f: F) {
         let cb: Box<Box<dyn Fn(LogLevel, Log, Cow<str>) + Send + 'static>> = Box::new(Box::new(f));
@@ -296,17 +307,17 @@ pub enum Event {
     MediaDiscovererStarted,
     MediaDiscovererEnded,
 
-    VlmMediaAdded,
-    VlmMediaRemoved,
-    VlmMediaChanged,
-    VlmMediaInstanceStarted,
-    VlmMediaInstanceStopped,
-    VlmMediaInstanceStatusInit,
-    VlmMediaInstanceStatusOpening,
-    VlmMediaInstanceStatusPlaying,
-    VlmMediaInstanceStatusPause,
-    VlmMediaInstanceStatusEnd,
-    VlmMediaInstanceStatusError
+    VlmMediaAdded(Option<String>, Option<String>),
+    VlmMediaRemoved(Option<String>, Option<String>),
+    VlmMediaChanged(Option<String>, Option<String>),
+    VlmMediaInstanceStarted(Option<String>, Option<String>),
+    VlmMediaInstanceStopped(Option<String>, Option<String>),
+    VlmMediaInstanceStatusInit(Option<String>, Option<String>),
+    VlmMediaInstanceStatusOpening(Option<String>, Option<String>),
+    VlmMediaInstanceStatusPlaying(Option<String>, Option<String>),
+    VlmMediaInstanceStatusPause(Option<String>, Option<String>),
+    VlmMediaInstanceStatusEnd(Option<String>, Option<String>),
+    VlmMediaInstanceStatusError(Option<String>, Option<String>)
 }
 
 pub struct EventManager<'a> {
@@ -485,37 +496,59 @@ fn conv_event(pe: *const sys::libvlc_event_t) -> Event {
             Event::MediaDiscovererEnded
         },
         EventType::VlmMediaAdded => {
-            Event::VlmMediaAdded
+            unsafe {
+                Event::VlmMediaAdded(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name))
+            }
         },
         EventType::VlmMediaRemoved => {
-            Event::VlmMediaRemoved
+            unsafe {
+                Event::VlmMediaRemoved(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name))
+            }
         },
         EventType::VlmMediaChanged => {
-            Event::VlmMediaChanged
+            unsafe {
+                Event::VlmMediaChanged(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name))
+            }
         },
         EventType::VlmMediaInstanceStarted => {
-            Event::VlmMediaInstanceStarted
+            unsafe {
+                Event::VlmMediaInstanceStarted(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name))
+            }
         },
         EventType::VlmMediaInstanceStopped => {
-            Event::VlmMediaInstanceStopped
+            unsafe {
+                Event::VlmMediaInstanceStopped(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name))
+            }
         },
         EventType::VlmMediaInstanceStatusInit => {
-            Event::VlmMediaInstanceStatusInit
+            unsafe {
+                Event::VlmMediaInstanceStatusInit(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name))
+            }
         },
         EventType::VlmMediaInstanceStatusOpening => {
-            Event::VlmMediaInstanceStatusOpening
+            unsafe {
+                Event::VlmMediaInstanceStatusOpening(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name))
+            }
         },
         EventType::VlmMediaInstanceStatusPlaying => {
-            Event::VlmMediaInstanceStatusPlaying
+            unsafe {
+                Event::VlmMediaInstanceStatusPlaying(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name))
+            }
         },
         EventType::VlmMediaInstanceStatusPause => {
-            Event::VlmMediaInstanceStatusPause
+            unsafe {
+                Event::VlmMediaInstanceStatusPause(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name))
+            }
         },
         EventType::VlmMediaInstanceStatusEnd => {
-            Event::VlmMediaInstanceStatusEnd
+            unsafe {
+                Event::VlmMediaInstanceStatusEnd(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name))
+            }
         },
         EventType::VlmMediaInstanceStatusError => {
-            Event::VlmMediaInstanceStatusError
+            unsafe {
+                Event::VlmMediaInstanceStatusError(from_cstr((*pe).u.vlm_media_event.psz_instance_name), from_cstr((*pe).u.vlm_media_event.psz_media_name))
+            }
         },
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index 0772446..db9d611 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -15,6 +15,7 @@ mod media_library;
 mod enums;
 mod video;
 mod audio;
+mod vlm;
 
 pub use crate::enums::*;
 pub use crate::core::*;
@@ -24,3 +25,4 @@ pub use crate::media_list::*;
 pub use crate::media_library::*;
 pub use crate::video::*;
 pub use crate::audio::*;
+pub use crate::vlm::*;
diff --git a/src/media.rs b/src/media.rs
index 4c4a44f..f100d01 100644
--- a/src/media.rs
+++ b/src/media.rs
@@ -12,6 +12,8 @@ pub struct Media {
     pub(crate) ptr: *mut sys::libvlc_media_t,
 }
 
+unsafe impl Send for Media {}
+
 impl Media {
     /// Create a media with a certain given media resource location, for instance a valid URL.
     pub fn new_location(instance: &Instance, mrl: &str) -> Option<Media> {
diff --git a/src/media_player.rs b/src/media_player.rs
index 8bbcc6f..669665f 100644
--- a/src/media_player.rs
+++ b/src/media_player.rs
@@ -15,6 +15,8 @@ pub struct MediaPlayer {
     pub(crate) ptr: *mut sys::libvlc_media_player_t,
 }
 
+unsafe impl Send for MediaPlayer {}
+
 impl MediaPlayer {
     /// Create an empty Media Player object
     pub fn new(instance: &Instance) -> Option<MediaPlayer> {
diff --git a/src/vlm.rs b/src/vlm.rs
new file mode 100644
index 0000000..9ad7283
--- /dev/null
+++ b/src/vlm.rs
@@ -0,0 +1,147 @@
+use std::ffi::CString;
+use std::os::raw::c_char;
+use std::ptr;
+
+use crate::{Instance, sys};
+use crate::tools::{from_cstr, to_cstr};
+
+pub trait Vlm {
+    fn add_broadcast(&self, name: &str, input: &str, output: &str, options: Option<Vec<String>>, enabled: bool, loop_broadcast: bool, ) -> Result<(), ()>;
+
+    fn add_vod(&self, name: &str, input: &str, mux: &str, options: Option<Vec<String>>, enabled: bool) -> Result<(), ()>;
+
+    fn play_media(&self, name: &str) -> Result<(), ()>;
+
+    fn pause_media(&self, name: &str) -> Result<(), ()>;
+
+    fn stop_media(&self, name: &str) -> Result<(), ()>;
+
+    fn get_media_instance_position(&self, name: &str, instance: i32) -> Result<f32, ()>;
+
+    fn get_media_instance_length(&self, name: &str, instance: i32) -> Result<i32, ()>;
+
+    fn get_media_instance_time(&self, name: &str, instance: i32) -> Result<i32, ()>;
+
+    fn get_media_instance_rate(&self, name: &str, instance: i32) -> Result<i32, ()>;
+
+    fn show_media(&self, name: &str) -> Result<String, ()>;
+}
+
+impl Vlm for Instance {
+    fn add_broadcast(&self, name: &str, input: &str, output: &str, options: Option<Vec<String>>, enabled: bool, loop_broadcast: bool, ) -> Result<(), ()> {
+        let name = to_cstr(name);
+        let input = to_cstr(input);
+        let output = to_cstr(output);
+        let opts_c_ptr: Vec<*const c_char>;
+        let opts_c: Vec<CString>;
+        let enabled = if enabled { 1 } else { 0 };
+        let loop_broadcast = if loop_broadcast { 1 } else { 0 };
+        if let Some(vec) = options {
+            opts_c = vec.into_iter()
+                .map(|x| CString::new(x).expect("Error: Unexpected null byte")).collect();
+            opts_c_ptr = opts_c.iter().map(|x| x.as_ptr()).collect();
+        } else {
+            opts_c_ptr = Vec::new();
+        }
+        let result = unsafe {
+            if opts_c_ptr.is_empty() {
+                sys::libvlc_vlm_add_broadcast(self.ptr, name.as_ptr(), input.as_ptr(), output.as_ptr(), 0, ptr::null(), enabled, loop_broadcast)
+            } else {
+                sys::libvlc_vlm_add_broadcast(self.ptr, name.as_ptr(), input.as_ptr(), output.as_ptr(), opts_c_ptr.len() as i32, opts_c_ptr.as_ptr(), enabled, loop_broadcast)
+            }
+        };
+        if result == 0 { Ok(()) } else { Err(()) }
+    }
+
+    fn add_vod(&self, name: &str, input: &str, mux: &str, options: Option<Vec<String>>, enabled: bool) -> Result<(), ()> {
+        let name = to_cstr(name);
+        let input = to_cstr(input);
+        let mux = to_cstr(mux);
+        let opts_c_ptr: Vec<*const c_char>;
+        let opts_c: Vec<CString>;
+        let enabled = if enabled { 1 } else { 0 };
+        if let Some(vec) = options {
+            opts_c = vec.into_iter()
+                .map(|x| CString::new(x).expect("Error: Unexpected null byte")).collect();
+            opts_c_ptr = opts_c.iter().map(|x| x.as_ptr()).collect();
+        } else {
+            opts_c_ptr = Vec::new();
+        }
+        let result = unsafe {
+            if opts_c_ptr.is_empty() {
+                sys::libvlc_vlm_add_vod(self.ptr, name.as_ptr(), input.as_ptr(), 0, ptr::null(), enabled, mux.as_ptr())
+            } else {
+                sys::libvlc_vlm_add_vod(self.ptr, name.as_ptr(), input.as_ptr(), opts_c_ptr.len() as i32, opts_c_ptr.as_ptr(), enabled, mux.as_ptr())
+            }
+        };
+        if result == 0 { Ok(()) } else { Err(()) }
+    }
+
+    fn play_media(&self, name: &str) -> Result<(), ()> {
+        let name = to_cstr(name);
+        let result = unsafe {
+            sys::libvlc_vlm_play_media(self.ptr, name.as_ptr())
+        };
+        if result == 0 { Ok(()) } else { Err(()) }
+    }
+
+    fn pause_media(&self, name: &str) -> Result<(), ()> {
+        let name = to_cstr(name);
+        let result = unsafe {
+            sys::libvlc_vlm_pause_media(self.ptr, name.as_ptr())
+        };
+        if result == 0 { Ok(()) } else { Err(()) }
+    }
+
+    fn stop_media(&self, name: &str) -> Result<(), ()> {
+        let name = to_cstr(name);
+        let result = unsafe {
+            sys::libvlc_vlm_stop_media(self.ptr, name.as_ptr())
+        };
+        if result == 0 { Ok(()) } else { Err(()) }
+    }
+
+    fn get_media_instance_position(&self, name: &str, instance: i32) -> Result<f32, ()> {
+        let name = to_cstr(name);
+        let result = unsafe {
+            sys::libvlc_vlm_get_media_instance_position(self.ptr, name.as_ptr(), instance)
+        };
+        if result != -1f32 { Ok(result) } else { Err(()) }
+    }
+
+    fn get_media_instance_length(&self, name: &str, instance: i32) -> Result<i32, ()> {
+        let name = to_cstr(name);
+        let result = unsafe {
+            sys::libvlc_vlm_get_media_instance_length(self.ptr, name.as_ptr(), instance)
+        };
+        if result != -1 { Ok(result) } else { Err(()) }
+    }
+
+    fn get_media_instance_time(&self, name: &str, instance: i32) -> Result<i32, ()> {
+        let name = to_cstr(name);
+        let result = unsafe {
+            sys::libvlc_vlm_get_media_instance_time(self.ptr, name.as_ptr(), instance)
+        };
+        if result != -1 { Ok(result) } else { Err(()) }
+    }
+
+    fn get_media_instance_rate(&self, name: &str, instance: i32) -> Result<i32, ()> {
+        let name = to_cstr(name);
+        let result = unsafe {
+            sys::libvlc_vlm_get_media_instance_rate(self.ptr, name.as_ptr(), instance)
+        };
+        if result != -1 { Ok(result) } else { Err(()) }
+    }
+
+    fn show_media(&self, name: &str) -> Result<String, ()> {
+        let name = to_cstr(name);
+        let result = unsafe {
+            from_cstr(sys::libvlc_vlm_show_media(self.ptr, name.as_ptr()))
+        };
+        if let Some(data) = result {
+            Ok(data.to_string())
+        } else {
+            Err(())
+        }
+    }
+}