2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Diagnostics;
19 using System.Runtime.InteropServices;
20 using System.Threading;
21 using Tizen.Internals.Errors;
22 using Native = Tizen.Multimedia.Interop.MediaPacket;
24 namespace Tizen.Multimedia
27 /// Represents a packet for multimedia.
29 /// <since_tizen> 3 </since_tizen>
30 public abstract partial class MediaPacket : IDisposable
32 private readonly LockState _lock = new LockState();
35 /// Validates the current object is not locked.
37 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
38 /// <exception cref="InvalidOperationException">The MediaPacket is in use by another module.</exception>
39 private void ValidateNotLocked()
41 ValidateNotDisposed();
45 throw new InvalidOperationException("Can't perform any writing operation." +
46 "The packet is in use, internally.");
51 /// Provides a thread-safe lock state controller.
53 private sealed class LockState
56 const int UNLOCKED = 0;
58 private int _locked = UNLOCKED;
60 internal void SetLock()
62 if (Interlocked.CompareExchange(ref _locked, LOCKED, UNLOCKED) == LOCKED)
64 throw new InvalidOperationException("The packet is already locked.");
68 internal void SetUnlock()
70 if (Interlocked.CompareExchange(ref _locked, UNLOCKED, LOCKED) == UNLOCKED)
72 Debug.Fail("The packet to unlock is not locked. " +
73 "There must be an error somewhere that a lock isn't disposed correctly.");
77 internal bool IsLocked => Interlocked.CompareExchange(ref _locked, 0, 0) == LOCKED;
81 /// Provides a thread-safe lock controller.
84 /// using (var lock = BaseMediaPacket.Lock(mediaPacket))
89 internal sealed class Lock : IDisposable
91 private readonly MediaPacket _packet;
92 private readonly GCHandle _gcHandle;
93 private int _lockCount;
95 internal static Lock Get(MediaPacket packet)
97 Debug.Assert(packet != null);
101 Lock lck = FromHandle(packet._handle) ?? new Lock(packet);
109 private Lock(MediaPacket packet)
111 Debug.Assert(packet != null, "The packet is null!");
113 packet.ValidateNotDisposed();
117 _packet._lock.SetLock();
119 _gcHandle = GCHandle.Alloc(this);
121 SetExtra(GCHandle.ToIntPtr(_gcHandle));
124 internal static Lock FromHandle(IntPtr handle)
126 Debug.Assert(handle != IntPtr.Zero);
128 IntPtr extra = GetExtra(handle);
130 if (extra == IntPtr.Zero)
135 return (Lock)GCHandle.FromIntPtr(extra).Target;
138 private void SetExtra(IntPtr ptr)
140 int ret = Native.SetExtra(_packet._handle, ptr);
142 MultimediaDebug.AssertNoError(ret);
145 private static IntPtr GetExtra(IntPtr handle)
147 int ret = Native.GetExtra(handle, out var value);
149 MultimediaDebug.AssertNoError(ret);
154 internal IntPtr GetHandle() => _packet.GetHandle();
156 internal MediaPacket MediaPacket => _packet;
158 private bool _isDisposed = false;
160 public void Dispose()
170 SetExtra(IntPtr.Zero);
172 if (_gcHandle.IsAllocated)
177 // We can assure that at this point '_packet' is always locked by this lock.
178 _packet._lock.SetUnlock();