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;
23 namespace Tizen.Multimedia
26 /// Represents a packet for multimedia.
28 public abstract partial class MediaPacket : IDisposable
30 private readonly LockState _lock = new LockState();
33 /// Validates the current object is not locked.
35 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
36 /// <exception cref="InvalidOperationException">The MediaPacket is in use by another module.</exception>
37 private void ValidateNotLocked()
39 ValidateNotDisposed();
43 throw new InvalidOperationException("Can't perform any writing operation." +
44 "The packet is in use, internally.");
49 /// Provides a thread-safe lock state controller.
51 private sealed class LockState
54 const int UNLOCKED = 0;
56 private int _locked = UNLOCKED;
58 internal void SetLock()
60 if (Interlocked.CompareExchange(ref _locked, LOCKED, UNLOCKED) == LOCKED)
62 throw new InvalidOperationException("The packet is already locked.");
66 internal void SetUnlock()
68 if (Interlocked.CompareExchange(ref _locked, UNLOCKED, LOCKED) == UNLOCKED)
70 Debug.Fail("The packet to unlock is not locked. " +
71 "There must be an error somewhere that a lock isn't disposed correctly.");
75 internal bool IsLocked
79 return Interlocked.CompareExchange(ref _locked, 0, 0) == LOCKED;
85 /// Provides a thread-safe lock controller.
88 /// using (var lock = BaseMediaPacket.Lock(mediaPacket))
93 internal sealed class Lock : IDisposable
95 private readonly MediaPacket _packet;
96 private readonly GCHandle _gcHandle;
97 private int _lockCount;
99 internal static Lock Get(MediaPacket packet)
101 Debug.Assert(packet != null);
105 Lock lck = FromHandle(packet._handle);
109 lck = new Lock(packet);
118 private Lock(MediaPacket packet)
120 Debug.Assert(packet != null, "The packet is null!");
122 packet.ValidateNotDisposed();
126 _packet._lock.SetLock();
128 _gcHandle = GCHandle.Alloc(this);
130 SetExtra(GCHandle.ToIntPtr(_gcHandle));
133 internal static Lock FromHandle(IntPtr handle)
135 Debug.Assert(handle != IntPtr.Zero);
137 IntPtr extra = GetExtra(handle);
139 if (extra == IntPtr.Zero)
144 return (Lock)GCHandle.FromIntPtr(extra).Target;
147 private void SetExtra(IntPtr ptr)
149 int ret = Interop.MediaPacket.SetExtra(_packet._handle, ptr);
151 MultimediaDebug.AssertNoError(ret);
154 private static IntPtr GetExtra(IntPtr handle)
158 int ret = Interop.MediaPacket.GetExtra(handle, out value);
160 MultimediaDebug.AssertNoError(ret);
165 internal IntPtr GetHandle()
167 return _packet.GetHandle();
170 internal MediaPacket MediaPacket
178 private bool _isDisposed = false;
180 public void Dispose()
190 SetExtra(IntPtr.Zero);
192 if (_gcHandle.IsAllocated)
197 //We can assure that at this point '_packet' is always locked by this lock.
198 _packet._lock.SetUnlock();