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? _mediaPlayerProgramDeleted; EventHandler? _mediaPlayerProgramSelected; EventHandler? _mediaPlayerProgramUpdated; + EventHandler? _mediaplayerRecordChanged; public MediaPlayerEventManager(IntPtr ptr) : base(ptr) { @@ -174,6 +175,10 @@ protected internal override void AttachEvent(EventType eventType, EventHandle _mediaPlayerProgramSelected += eventHandler as EventHandler; Attach(eventType, OnProgramSelected); break; + case EventType.MediaPlayerRecordChanged: + _mediaplayerRecordChanged += eventHandler as EventHandler; + Attach(eventType, OnRecordChanged); + break; default: OnEventUnhandled(this, eventType); break; @@ -312,6 +317,10 @@ protected internal override void DetachEvent(EventType eventType, EventHandle _mediaPlayerProgramSelected -= eventHandler as EventHandler; Detach(eventType); break; + case EventType.MediaPlayerRecordChanged: + _mediaplayerRecordChanged -= eventHandler as EventHandler; + 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) } } + /// + /// The mediaplayer started or stopped recording + /// + public class MediaPlayerRecordChangedEventArgs : EventArgs + { + /// + /// True if the mediaplayer started recording, + /// false when the mediaplayer stopped recording + /// + public readonly bool IsRecording; + + /// + /// filepath of the recorded file, only valid when is false + /// + 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; + /// + /// Start recording + /// + /// Users should subscribe to beforehand to get the final filepath of the recorded file and + /// monitor the recording state. + /// + /// LibVLC 4.0 and later + /// + /// path of the recording directory or NULL (use default path) + public void StartRecording(string? directory = null) => Native.LibVLCMediaPlayerRecord(NativeReference, enable: true, directory.ToUtf8()); + + /// + /// Stop recording + /// + /// Users should subscribe to beforehand to get the final filepath of the recorded file and + /// monitor the recording state. + /// + /// LibVLC 4.0 and later + /// + public void StopRecording() => Native.LibVLCMediaPlayerRecord(NativeReference, enable: false, IntPtr.Zero); + readonly MediaConfiguration Configuration = new MediaConfiguration(); #if UNITY @@ -3003,6 +3029,15 @@ public event EventHandler ProgramSelected add => EventManager.AttachEvent(EventType.MediaPlayerProgramSelected, value); remove => EventManager.DetachEvent(EventType.MediaPlayerProgramSelected, value); } + + /// + /// The recording state of the mediaplayer changed + /// + public event EventHandler RecordChanged + { + add => EventManager.AttachEvent(EventType.MediaPlayerRecordChanged, value); + remove => EventManager.DetachEvent(EventType.MediaPlayerRecordChanged, value); + } #endregion ///