diff --git a/src/LibVLCSharp/Events/MediaPlayerEventManager.cs b/src/LibVLCSharp/Events/MediaPlayerEventManager.cs
index 1985e6880..004b831ee 100644
--- a/src/LibVLCSharp/Events/MediaPlayerEventManager.cs
+++ b/src/LibVLCSharp/Events/MediaPlayerEventManager.cs
@@ -37,6 +37,7 @@ internal class MediaPlayerEventManager : EventManager
         EventHandler<MediaPlayerProgramDeletedEventArgs>? _mediaPlayerProgramDeleted;
         EventHandler<MediaPlayerProgramSelectedEventArgs>? _mediaPlayerProgramSelected;
         EventHandler<MediaPlayerProgramUpdatedEventArgs>? _mediaPlayerProgramUpdated;
+        EventHandler<MediaPlayerRecordChangedEventArgs>? _mediaplayerRecordChanged;
 
         public MediaPlayerEventManager(IntPtr ptr) : base(ptr)
         {
@@ -174,6 +175,10 @@ protected internal override void AttachEvent<T>(EventType eventType, EventHandle
                     _mediaPlayerProgramSelected += eventHandler as EventHandler<MediaPlayerProgramSelectedEventArgs>;
                     Attach(eventType, OnProgramSelected);
                     break;
+                case EventType.MediaPlayerRecordChanged:
+                    _mediaplayerRecordChanged += eventHandler as EventHandler<MediaPlayerRecordChangedEventArgs>;
+                    Attach(eventType, OnRecordChanged);
+                    break;
                 default:
                     OnEventUnhandled(this, eventType);
                     break;
@@ -312,6 +317,10 @@ protected internal override void DetachEvent<T>(EventType eventType, EventHandle
                     _mediaPlayerProgramSelected -= eventHandler as EventHandler<MediaPlayerProgramSelectedEventArgs>;
                     Detach(eventType);
                     break;
+                case EventType.MediaPlayerRecordChanged:
+                    _mediaplayerRecordChanged -= eventHandler as EventHandler<MediaPlayerRecordChangedEventArgs>;
+                    Detach(eventType);
+                    break;
                 default:
                     OnEventUnhandled(this, eventType);
                     break;
@@ -503,5 +512,13 @@ void OnProgramSelected(IntPtr ptr)
             _mediaPlayerProgramSelected?.Invoke(this,
                 new MediaPlayerProgramSelectedEventArgs(selectionChanged.UnselectedId, selectionChanged.SelectedId));
         }
+
+        void OnRecordChanged(IntPtr ptr)
+        {
+            var recordChanged = RetrieveEvent(ptr).Union.RecordChanged;
+
+            _mediaplayerRecordChanged?.Invoke(this,
+                new MediaPlayerRecordChangedEventArgs(recordChanged.IsRecording, recordChanged.RecordedFilePath.FromUtf8()));
+        }
     }
 }
diff --git a/src/LibVLCSharp/LibVLCEvents.cs b/src/LibVLCSharp/LibVLCEvents.cs
index f2da867c4..049480dd2 100644
--- a/src/LibVLCSharp/LibVLCEvents.cs
+++ b/src/LibVLCSharp/LibVLCEvents.cs
@@ -31,7 +31,7 @@ internal enum EventType
         MediaPlayerSnapshotTaken = MediaPlayerPausableChanged + 2,
         MediaPlayerLengthChanged,
         MediaPlayerVout,
-        MediaPlayerESAdded,
+        MediaPlayerESAdded = MediaPlayerVout + 2,
         MediaPlayerESDeleted,
         MediaPlayerESSelected,
         MediaPlayerCorked,
@@ -53,6 +53,7 @@ internal enum EventType
         MediaPlayerTitleListChanged,
         MediaPlayerTitleSelectionChanged,
         MediaPlayerChapterChanged,
+        MediaPlayerRecordChanged,
         MediaListItemAdded = 0x200,
         MediaListWillAddItem,
         MediaListItemDeleted,
@@ -161,6 +162,8 @@ internal readonly struct EventUnion
             internal readonly VolumeChanged MediaPlayerVolumeChanged;
             [FieldOffset(0)]
             internal readonly AudioDeviceChanged AudioDeviceChanged;
+            [FieldOffset(0)]
+            internal readonly RecordChanged RecordChanged;
 
             // renderer discoverer
             [FieldOffset(0)]
@@ -296,6 +299,13 @@ internal readonly struct AudioDeviceChanged
             internal readonly IntPtr Device;
         }
 
+        [StructLayout(LayoutKind.Sequential)]
+        internal readonly struct RecordChanged
+        {
+            internal readonly bool IsRecording;
+            internal readonly IntPtr RecordedFilePath;
+        }
+
         [StructLayout(LayoutKind.Sequential)]
         internal readonly struct MediaPlayerMediaChanged
         {
@@ -807,6 +817,29 @@ internal MediaPlayerProgramSelectedEventArgs(int unselectedId, int selectedId)
         }
     }
 
+    /// <summary>
+    /// The mediaplayer started or stopped recording
+    /// </summary>
+    public class MediaPlayerRecordChangedEventArgs : EventArgs
+    {
+        /// <summary>
+        /// True if the mediaplayer started recording, 
+        /// false when the mediaplayer stopped recording
+        /// </summary>
+        public readonly bool IsRecording;
+
+        /// <summary>
+        /// filepath of the recorded file, only valid when <see cref="IsRecording"/> is false
+        /// </summary>
+        public readonly string? FilePath;
+
+        internal MediaPlayerRecordChangedEventArgs(bool isRecording, string? filePath)
+        {
+            IsRecording = isRecording;
+            FilePath = filePath;
+        }
+    }
+
     #endregion
 
     #region MediaList events
diff --git a/src/LibVLCSharp/MediaPlayer.cs b/src/LibVLCSharp/MediaPlayer.cs
index a33321a53..46d0ec9c6 100644
--- a/src/LibVLCSharp/MediaPlayer.cs
+++ b/src/LibVLCSharp/MediaPlayer.cs
@@ -559,6 +559,11 @@ internal static extern int LibVLCMediaPlayerAddSlave(IntPtr mediaPlayer, MediaSl
             internal static extern bool LibVLCVideoSetOutputCallbacks(IntPtr mediaplayer, VideoEngine engine, OutputSetup? outputSetup, 
                 OutputCleanup? outputCleanup, OutputSetResize? resize, UpdateOutput updateOutput, Swap swap, MakeCurrent makeCurrent, 
                 GetProcAddress? getProcAddress, FrameMetadata? metadata, OutputSelectPlane? selectPlane, IntPtr opaque);
+
+            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
+                EntryPoint = "libvlc_media_player_record")]
+            internal static extern void LibVLCMediaPlayerRecord(IntPtr mediaplayer, bool enable, IntPtr path);
+
 #if ANDROID
             [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
                 EntryPoint = "libvlc_media_player_set_android_context")]
@@ -2067,6 +2072,27 @@ public bool SetOutputCallbacks(VideoEngine engine, OutputSetup? outputSetup, Out
         FrameMetadata? _frameMetadata;
         OutputSelectPlane? _outputSelectPlane;
 
+        /// <summary>
+        /// Start recording
+        /// <para/>
+        /// Users should subscribe to <see cref="MediaPlayer.RecordChanged"/> beforehand to get the final filepath of the recorded file and 
+        /// monitor the recording state.
+        /// <para/>
+        /// LibVLC 4.0 and later
+        /// </summary>
+        /// <param name="directory">path of the recording directory or NULL (use default path)</param>
+        public void StartRecording(string? directory = null) => Native.LibVLCMediaPlayerRecord(NativeReference, enable: true, directory.ToUtf8());
+
+        /// <summary>
+        /// Stop recording
+        /// <para/>
+        /// Users should subscribe to <see cref="MediaPlayer.RecordChanged"/> beforehand to get the final filepath of the recorded file and 
+        /// monitor the recording state.
+        /// <para/>
+        /// LibVLC 4.0 and later
+        /// </summary>
+        public void StopRecording() => Native.LibVLCMediaPlayerRecord(NativeReference, enable: false, IntPtr.Zero);
+
         readonly MediaConfiguration Configuration = new MediaConfiguration();
 
 #if UNITY
@@ -3003,6 +3029,15 @@ public event EventHandler<MediaPlayerProgramSelectedEventArgs> ProgramSelected
             add => EventManager.AttachEvent(EventType.MediaPlayerProgramSelected, value);
             remove => EventManager.DetachEvent(EventType.MediaPlayerProgramSelected, value);
         }
+
+        /// <summary>
+        /// The recording state of the mediaplayer changed
+        /// </summary>
+        public event EventHandler<MediaPlayerRecordChangedEventArgs> RecordChanged
+        {
+            add => EventManager.AttachEvent(EventType.MediaPlayerRecordChanged, value);
+            remove => EventManager.DetachEvent(EventType.MediaPlayerRecordChanged, value);
+        }
         #endregion
 
         /// <summary>