...
 
Commits (5)
......@@ -2,6 +2,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using LibVLCSharp.Shared;
using NUnit.Framework;
......@@ -76,5 +77,84 @@ namespace LibVLCSharp.Tests
Assert.True(called);
Assert.True(mp.IsPlaying);
}
int callCountRegisterOne = 0;
int callCountRegisterTwo = 0;
[Test]
public async Task EventFireOnceForeachRegistration()
{
try
{
var libVLC = new LibVLC();
var media = new Media(libVLC, "http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4", Media.FromType.FromLocation);
var mp = new MediaPlayer(media);
mp.Playing += Mp_Playing;
mp.Playing += Mp_Playing1;
Debug.WriteLine("first play");
mp.Play();
await Task.Delay(2000);
Assert.AreEqual(callCountRegisterOne, 1);
Assert.AreEqual(callCountRegisterTwo, 1);
callCountRegisterOne = 0;
callCountRegisterTwo = 0;
mp.Stop();
mp.Playing -= Mp_Playing;
Debug.WriteLine("second play");
mp.Play();
await Task.Delay(2000);
Assert.AreEqual(callCountRegisterOne, 0);
Assert.AreEqual(callCountRegisterTwo, 1);
// mp.Stop();
mp.Playing -= Mp_Playing1; // native crash in detach?
callCountRegisterOne = 0;
callCountRegisterTwo = 0;
Debug.WriteLine("third play");
mp.Play();
await Task.Delay(500);
Assert.AreEqual(callCountRegisterOne, 0);
Assert.AreEqual(callCountRegisterTwo, 0);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
void Mp_Playing1(object sender, EventArgs e)
{
callCountRegisterTwo++;
Debug.WriteLine($"Mp_Playing1 called with {callCountRegisterTwo}");
}
void Mp_Playing(object sender, EventArgs e)
{
callCountRegisterOne++;
Debug.WriteLine($"Mp_Playing called with {callCountRegisterOne}");
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
......@@ -29,7 +30,7 @@ namespace LibVLCSharp.Shared
NativeReference = ptr;
}
protected void AttachNativeEvent(EventType eventType, EventCallback eventCallback)
private void AttachNativeEvent(EventType eventType, EventCallback eventCallback)
{
_callbacks.Add(eventCallback);
if (Internal.LibVLCEventAttach(NativeReference, eventType, eventCallback, IntPtr.Zero) != 0)
......@@ -39,13 +40,39 @@ namespace LibVLCSharp.Shared
}
}
protected void DetachNativeEvent(EventType eventType, EventCallback eventCallback)
private void DetachNativeEvent(EventType eventType, EventCallback eventCallback)
{
_callbacks.Remove(eventCallback);
Internal.LibVLCEventDetach(NativeReference, eventType, eventCallback, IntPtr.Zero);
}
protected void Attach(EventType eventType, ref int registrationCount, Action managedSubscribe, Func<EventCallback> setCallback)
{
managedSubscribe();
if (registrationCount == 0)
{
AttachNativeEvent(eventType, setCallback());
}
registrationCount++;
}
protected void Detach(EventType eventType, ref int registrationCount, Action managedUnsubscribe, ref EventCallback eventCallback)
{
if (registrationCount == 0) return;
registrationCount--;
managedUnsubscribe();
if (registrationCount == 0)
{
Debug.Assert(eventCallback != null);
DetachNativeEvent(eventType, eventCallback);
eventCallback = null;
}
}
#if IOS
internal protected static LibVLCEvent RetrieveEvent(IntPtr eventPtr) => MarshalUtils.PtrToStructure<LibVLCEvent>(eventPtr);
#else
......
......@@ -12,6 +12,13 @@ namespace LibVLCSharp.Shared
EventHandler<EventArgs> _mediaDiscovererStarted;
EventHandler<EventArgs> _mediaDiscovererStopped;
#endif
int _discovererStartedRegistrationCount;
int _discovererStoppedRegistrationCount;
EventCallback _discovererStartedCallback;
EventCallback _discovererStoppedCallback;
public MediaDiscovererEventManager(IntPtr ptr) : base(ptr)
{
}
......@@ -23,12 +30,16 @@ namespace LibVLCSharp.Shared
switch (eventType)
{
case EventType.MediaDiscovererStarted:
_mediaDiscovererStarted += eventHandler as EventHandler<EventArgs>;
AttachNativeEvent(eventType, OnStarted);
Attach(eventType,
ref _discovererStartedRegistrationCount,
() => _mediaDiscovererStarted += eventHandler as EventHandler<EventArgs>,
() => _discovererStartedCallback = OnStarted);
break;
case EventType.MediaDiscovererStopped:
_mediaDiscovererStopped += eventHandler as EventHandler<EventArgs>;
AttachNativeEvent(eventType, OnStopped);
Attach(eventType,
ref _discovererStoppedRegistrationCount,
() => _mediaDiscovererStopped += eventHandler as EventHandler<EventArgs>,
() => _discovererStoppedCallback = OnStopped);
break;
default:
OnEventUnhandled(this, eventType);
......@@ -44,12 +55,16 @@ namespace LibVLCSharp.Shared
switch (eventType)
{
case EventType.MediaDiscovererStarted:
_mediaDiscovererStarted -= eventHandler as EventHandler<EventArgs>;
DetachNativeEvent(eventType, OnStarted);
Detach(eventType,
ref _discovererStartedRegistrationCount,
() => _mediaDiscovererStarted -= eventHandler as EventHandler<EventArgs>,
ref _discovererStartedCallback);
break;
case EventType.MediaDiscovererStopped:
_mediaDiscovererStopped -= eventHandler as EventHandler<EventArgs>;
DetachNativeEvent(eventType, OnStopped);
Detach(eventType,
ref _discovererStoppedRegistrationCount,
() => _mediaDiscovererStopped -= eventHandler as EventHandler<EventArgs>,
ref _discovererStoppedCallback);
break;
default:
OnEventUnhandled(this, eventType);
......
......@@ -22,6 +22,23 @@ namespace LibVLCSharp.Shared
EventHandler<MediaStateChangedEventArgs> _mediaStateChanged;
EventHandler<MediaSubItemTreeAddedEventArgs> _mediaSubItemTreeAdded;
#endif
int _mediaMetaChangedRegistrationCount;
int _mediaParsedChangedRegistrationCount;
int _mediaSubItemChangedRegistrationCount;
int _mediaDurationChangedRegistrationCount;
int _mediaFreedRegistrationCount;
int _mediaStateChangedRegistrationCount;
int _mediaSubitemTreeAddedRegistrationCount;
EventCallback _mediaMetaChangedCallback;
EventCallback _mediaParsedChangedCallback;
EventCallback _mediaSubItemChangedCallback;
EventCallback _mediaDurationChangedCallback;
EventCallback _mediaFreedCallback;
EventCallback _mediaStateChangedCallback;
EventCallback _mediaSubitemTreeAddedCallback;
public MediaEventManager(IntPtr ptr) : base(ptr)
{
}
......@@ -33,32 +50,46 @@ namespace LibVLCSharp.Shared
switch (eventType)
{
case EventType.MediaMetaChanged:
_mediaMetaChanged += eventHandler as EventHandler<MediaMetaChangedEventArgs>;
AttachNativeEvent(eventType, OnMetaChanged);
Attach(eventType,
ref _mediaMetaChangedRegistrationCount,
() => _mediaMetaChanged += eventHandler as EventHandler<MediaMetaChangedEventArgs>,
() => _mediaMetaChangedCallback = OnMetaChanged);
break;
case EventType.MediaParsedChanged:
_mediaParsedChanged += eventHandler as EventHandler<MediaParsedChangedEventArgs>;
AttachNativeEvent(eventType, OnParsedChanged);
Attach(eventType,
ref _mediaParsedChangedRegistrationCount,
() => _mediaParsedChanged += eventHandler as EventHandler<MediaParsedChangedEventArgs>,
() => _mediaParsedChangedCallback = OnParsedChanged);
break;
case EventType.MediaSubItemAdded:
_mediaSubItemAdded += eventHandler as EventHandler<MediaSubItemAddedEventArgs>;
AttachNativeEvent(eventType, OnSubItemAdded);
Attach(eventType,
ref _mediaSubItemChangedRegistrationCount,
() => _mediaSubItemAdded += eventHandler as EventHandler<MediaSubItemAddedEventArgs>,
() => _mediaSubItemChangedCallback = OnSubItemAdded);
break;
case EventType.MediaDurationChanged:
_mediaDurationChanged += eventHandler as EventHandler<MediaDurationChangedEventArgs>;
AttachNativeEvent(eventType, OnDurationChanged);
Attach(eventType,
ref _mediaDurationChangedRegistrationCount,
() => _mediaDurationChanged += eventHandler as EventHandler<MediaDurationChangedEventArgs>,
() => _mediaDurationChangedCallback = OnDurationChanged);
break;
case EventType.MediaFreed:
_mediaFreed += eventHandler as EventHandler<MediaFreedEventArgs>;
AttachNativeEvent(eventType, OnMediaFreed);
Attach(eventType,
ref _mediaFreedRegistrationCount,
() => _mediaFreed += eventHandler as EventHandler<MediaFreedEventArgs>,
() => _mediaFreedCallback = OnMediaFreed);
break;
case EventType.MediaStateChanged:
_mediaStateChanged += eventHandler as EventHandler<MediaStateChangedEventArgs>;
AttachNativeEvent(eventType, OnMediaStateChanged);
Attach(eventType,
ref _mediaStateChangedRegistrationCount,
() => _mediaStateChanged += eventHandler as EventHandler<MediaStateChangedEventArgs>,
() => _mediaStateChangedCallback = OnMediaStateChanged);
break;
case EventType.MediaSubItemTreeAdded:
_mediaSubItemTreeAdded += eventHandler as EventHandler<MediaSubItemTreeAddedEventArgs>;
AttachNativeEvent(eventType, OnSubItemTreeAdded);
Attach(eventType,
ref _mediaSubitemTreeAddedRegistrationCount,
() => _mediaSubItemTreeAdded += eventHandler as EventHandler<MediaSubItemTreeAddedEventArgs>,
() => _mediaSubitemTreeAddedCallback = OnSubItemTreeAdded);
break;
default:
OnEventUnhandled(this, eventType);
......@@ -74,32 +105,46 @@ namespace LibVLCSharp.Shared
switch (eventType)
{
case EventType.MediaMetaChanged:
_mediaMetaChanged -= eventHandler as EventHandler<MediaMetaChangedEventArgs>;
DetachNativeEvent(eventType, OnMetaChanged);
Detach(eventType,
ref _mediaMetaChangedRegistrationCount,
() => _mediaMetaChanged -= eventHandler as EventHandler<MediaMetaChangedEventArgs>,
ref _mediaMetaChangedCallback);
break;
case EventType.MediaParsedChanged:
_mediaParsedChanged -= eventHandler as EventHandler<MediaParsedChangedEventArgs>;
DetachNativeEvent(eventType, OnParsedChanged);
Detach(eventType,
ref _mediaParsedChangedRegistrationCount,
() => _mediaParsedChanged -= eventHandler as EventHandler<MediaParsedChangedEventArgs>,
ref _mediaParsedChangedCallback);
break;
case EventType.MediaSubItemAdded:
_mediaSubItemAdded -= eventHandler as EventHandler<MediaSubItemAddedEventArgs>;
DetachNativeEvent(eventType, OnSubItemAdded);
Detach(eventType,
ref _mediaSubItemChangedRegistrationCount,
() => _mediaSubItemAdded -= eventHandler as EventHandler<MediaSubItemAddedEventArgs>,
ref _mediaSubItemChangedCallback);
break;
case EventType.MediaDurationChanged:
_mediaDurationChanged -= eventHandler as EventHandler<MediaDurationChangedEventArgs>;
DetachNativeEvent(eventType, OnDurationChanged);
Detach(eventType,
ref _mediaDurationChangedRegistrationCount,
() => _mediaDurationChanged -= eventHandler as EventHandler<MediaDurationChangedEventArgs>,
ref _mediaDurationChangedCallback);
break;
case EventType.MediaFreed:
_mediaFreed -= eventHandler as EventHandler<MediaFreedEventArgs>;
DetachNativeEvent(eventType, OnMediaFreed);
Detach(eventType,
ref _mediaFreedRegistrationCount,
() => _mediaFreed -= eventHandler as EventHandler<MediaFreedEventArgs>,
ref _mediaFreedCallback);
break;
case EventType.MediaStateChanged:
_mediaStateChanged -= eventHandler as EventHandler<MediaStateChangedEventArgs>;
DetachNativeEvent(eventType, OnMediaStateChanged);
Detach(eventType,
ref _mediaStateChangedRegistrationCount,
() => _mediaStateChanged -= eventHandler as EventHandler<MediaStateChangedEventArgs>,
ref _mediaStateChangedCallback);
break;
case EventType.MediaSubItemTreeAdded:
_mediaSubItemTreeAdded -= eventHandler as EventHandler<MediaSubItemTreeAddedEventArgs>;
DetachNativeEvent(eventType, OnSubItemTreeAdded);
Detach(eventType,
ref _mediaSubitemTreeAddedRegistrationCount,
() => _mediaSubItemTreeAdded -= eventHandler as EventHandler<MediaSubItemTreeAddedEventArgs>,
ref _mediaSubitemTreeAddedCallback);
break;
default:
OnEventUnhandled(this, eventType);
......
......@@ -19,6 +19,19 @@ namespace LibVLCSharp.Shared
EventHandler<EventArgs> _mediaListEndReached;
#endif
int _mediaListItemAddedRegistrationCount;
int _mediaListWillAddItemdRegistrationCount;
int _mediaListItemDeletedRegistrationCount;
int _mediaListWillDeleteItemRegistrationCount;
int _mediaListEndReachedRegistrationCount;
EventCallback _mediaListItemAddedCallback;
EventCallback _mediaListWillAddItemdCallback;
EventCallback _mediaListItemDeletedCallback;
EventCallback _mediaListWillDeleteItemCallback;
EventCallback _mediaListEndReachedCallback;
public MediaListEventManager(IntPtr ptr) : base(ptr)
{
}
......@@ -30,24 +43,34 @@ namespace LibVLCSharp.Shared
switch (eventType)
{
case EventType.MediaListItemAdded:
_mediaListItemAdded += eventHandler as EventHandler<MediaListItemAddedEventArgs>;
AttachNativeEvent(eventType, OnItemAdded);
Attach(eventType,
ref _mediaListItemAddedRegistrationCount,
() => _mediaListItemAdded += eventHandler as EventHandler<MediaListItemAddedEventArgs>,
() => _mediaListItemAddedCallback = OnItemAdded);
break;
case EventType.MediaListWillAddItem:
_mediaListWillAddItem += eventHandler as EventHandler<MediaListWillAddItemEventArgs>;
AttachNativeEvent(eventType, OnWillAddItem);
Attach(eventType,
ref _mediaListWillAddItemdRegistrationCount,
() => _mediaListWillAddItem += eventHandler as EventHandler<MediaListWillAddItemEventArgs>,
() => _mediaListWillAddItemdCallback = OnWillAddItem);
break;
case EventType.MediaListItemDeleted:
_mediaListItemDeleted += eventHandler as EventHandler<MediaListItemDeletedEventArgs>;
AttachNativeEvent(eventType, OnItemDeleted);
Attach(eventType,
ref _mediaListItemDeletedRegistrationCount,
() => _mediaListItemDeleted += eventHandler as EventHandler<MediaListItemDeletedEventArgs>,
() => _mediaListItemDeletedCallback = OnItemDeleted);
break;
case EventType.MediaListViewWillDeleteItem:
_mediaListWillDeleteItem += eventHandler as EventHandler<MediaListWillDeleteItemEventArgs>;
AttachNativeEvent(eventType, OnWillDeleteItem);
Attach(eventType,
ref _mediaListWillDeleteItemRegistrationCount,
() => _mediaListWillDeleteItem += eventHandler as EventHandler<MediaListWillDeleteItemEventArgs>,
() => _mediaListWillDeleteItemCallback = OnWillDeleteItem);
break;
case EventType.MediaListEndReached:
_mediaListEndReached += eventHandler as EventHandler<EventArgs>;
AttachNativeEvent(eventType, OnEndReached);
Attach(eventType,
ref _mediaListEndReachedRegistrationCount,
() => _mediaListEndReached += eventHandler as EventHandler<EventArgs>,
() => _mediaListEndReachedCallback = OnEndReached);
break;
default:
OnEventUnhandled(this, eventType);
......@@ -63,24 +86,34 @@ namespace LibVLCSharp.Shared
switch (eventType)
{
case EventType.MediaListItemAdded:
_mediaListItemAdded -= eventHandler as EventHandler<MediaListItemAddedEventArgs>;
DetachNativeEvent(eventType, OnItemAdded);
Detach(eventType,
ref _mediaListItemAddedRegistrationCount,
() => _mediaListItemAdded -= eventHandler as EventHandler<MediaListItemAddedEventArgs>,
ref _mediaListItemAddedCallback);
break;
case EventType.MediaListWillAddItem:
_mediaListWillAddItem -= eventHandler as EventHandler<MediaListWillAddItemEventArgs>;
DetachNativeEvent(eventType, OnWillAddItem);
Detach(eventType,
ref _mediaListWillAddItemdRegistrationCount,
() => _mediaListWillAddItem -= eventHandler as EventHandler<MediaListWillAddItemEventArgs>,
ref _mediaListWillAddItemdCallback);
break;
case EventType.MediaListItemDeleted:
_mediaListItemDeleted -= eventHandler as EventHandler<MediaListItemDeletedEventArgs>;
DetachNativeEvent(eventType, OnItemDeleted);
Detach(eventType,
ref _mediaListItemDeletedRegistrationCount,
() => _mediaListItemDeleted -= eventHandler as EventHandler<MediaListItemDeletedEventArgs>,
ref _mediaListItemDeletedCallback);
break;
case EventType.MediaListViewWillDeleteItem:
_mediaListWillDeleteItem -= eventHandler as EventHandler<MediaListWillDeleteItemEventArgs>;
DetachNativeEvent(eventType, OnWillDeleteItem);
Detach(eventType,
ref _mediaListWillDeleteItemRegistrationCount,
() => _mediaListWillDeleteItem -= eventHandler as EventHandler<MediaListWillDeleteItemEventArgs>,
ref _mediaListWillDeleteItemCallback);
break;
case EventType.MediaListEndReached:
_mediaListEndReached -= eventHandler as EventHandler<EventArgs>;
DetachNativeEvent(eventType, OnEndReached);
Detach(eventType,
ref _mediaListEndReachedRegistrationCount,
() => _mediaListEndReached -= eventHandler as EventHandler<EventArgs>,
ref _mediaListEndReachedCallback);
break;
default:
OnEventUnhandled(this, eventType);
......
......@@ -12,6 +12,13 @@ namespace LibVLCSharp.Shared
EventHandler<RendererDiscovererItemAddedEventArgs> _itemAdded;
EventHandler<RendererDiscovererItemDeletedEventArgs> _itemDeleted;
#endif
int _itemAddedRegistrationCount;
int _itemDeletedRegistrationCount;
EventCallback _itemAddedCallback;
EventCallback _itemDeletedCallback;
internal RendererDiscovererEventManager(IntPtr ptr) : base(ptr)
{
}
......@@ -23,12 +30,16 @@ namespace LibVLCSharp.Shared
switch(eventType)
{
case EventType.RendererDiscovererItemAdded:
_itemAdded += eventHandler as EventHandler<RendererDiscovererItemAddedEventArgs>;
AttachNativeEvent(eventType, OnItemAdded);
Attach(eventType,
ref _itemAddedRegistrationCount,
() => _itemAdded += eventHandler as EventHandler<RendererDiscovererItemAddedEventArgs>,
() => _itemAddedCallback = OnItemAdded);
break;
case EventType.RendererDiscovererItemDeleted:
_itemDeleted += eventHandler as EventHandler<RendererDiscovererItemDeletedEventArgs>;
AttachNativeEvent(eventType, OnItemDeleted);
Attach(eventType,
ref _itemDeletedRegistrationCount,
() => _itemDeleted += eventHandler as EventHandler<RendererDiscovererItemDeletedEventArgs>,
() => _itemDeletedCallback = OnItemDeleted);
break;
default:
OnEventUnhandled(this, eventType);
......@@ -44,12 +55,16 @@ namespace LibVLCSharp.Shared
switch (eventType)
{
case EventType.RendererDiscovererItemAdded:
_itemAdded -= eventHandler as EventHandler<RendererDiscovererItemAddedEventArgs>;
DetachNativeEvent(eventType, OnItemAdded);
Detach(eventType,
ref _itemAddedRegistrationCount,
() => _itemAdded -= eventHandler as EventHandler<RendererDiscovererItemAddedEventArgs>,
ref _itemAddedCallback);
break;
case EventType.RendererDiscovererItemDeleted:
_itemDeleted -= eventHandler as EventHandler<RendererDiscovererItemDeletedEventArgs>;
DetachNativeEvent(eventType, OnItemDeleted);
Detach(eventType,
ref _itemDeletedRegistrationCount,
() => _itemDeleted -= eventHandler as EventHandler<RendererDiscovererItemDeletedEventArgs>,
ref _itemDeletedCallback);
break;
default:
OnEventUnhandled(this, eventType);
......