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 /// <since_tizen> 3 </since_tizen>
29 public abstract partial class MediaPacket : IDisposable
31 private readonly LockState _lock = new LockState();
34 /// Validates the current object is not locked.
36 /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
37 /// <exception cref="InvalidOperationException">The MediaPacket is in use by another module.</exception>
38 private void ValidateNotLocked()
40 ValidateNotDisposed();
44 throw new InvalidOperationException("Can't perform any writing operation." +
45 "The packet is in use, internally.");
50 /// Provides a thread-safe lock state controller.
52 private sealed class LockState
55 const int UNLOCKED = 0;
57 private int _locked = UNLOCKED;
59 internal void SetLock()
61 if (Interlocked.CompareExchange(ref _locked, LOCKED, UNLOCKED) == LOCKED)
63 throw new InvalidOperationException("The packet is already locked.");
67 internal void SetUnlock()
69 if (Interlocked.CompareExchange(ref _locked, UNLOCKED, LOCKED) == UNLOCKED)
71 Debug.Fail("The packet to unlock is not locked. " +
72 "There must be an error somewhere that a lock isn't disposed correctly.");
76 internal bool IsLocked => Interlocked.CompareExchange(ref _locked, 0, 0) == LOCKED;
80 /// Provides a thread-safe lock controller.
83 /// using (var lock = BaseMediaPacket.Lock(mediaPacket))
88 internal sealed class Lock : IDisposable
90 private readonly MediaPacket _packet;
91 private readonly GCHandle _gcHandle;
92 private int _lockCount;
94 internal static Lock Get(MediaPacket packet)
96 Debug.Assert(packet != null);
100 Lock lck = FromHandle(packet._handle) ?? new Lock(packet);
108 private Lock(MediaPacket packet)
110 Debug.Assert(packet != null, "The packet is null!");
112 packet.ValidateNotDisposed();
116 _packet._lock.SetLock();
118 _gcHandle = GCHandle.Alloc(this);
120 SetExtra(GCHandle.ToIntPtr(_gcHandle));
123 internal static Lock FromHandle(IntPtr handle)
125 Debug.Assert(handle != IntPtr.Zero);
127 IntPtr extra = GetExtra(handle);
129 if (extra == IntPtr.Zero)
134 return (Lock)GCHandle.FromIntPtr(extra).Target;
137 private void SetExtra(IntPtr ptr)
139 int ret = Interop.MediaPacket.SetExtra(_packet._handle, ptr);
141 MultimediaDebug.AssertNoError(ret);
144 private static IntPtr GetExtra(IntPtr handle)
146 int ret = Interop.MediaPacket.GetExtra(handle, out var value);
148 MultimediaDebug.AssertNoError(ret);
153 internal IntPtr GetHandle() => _packet.GetHandle();
155 internal MediaPacket MediaPacket => _packet;
157 private bool _isDisposed = false;
159 public void Dispose()
169 SetExtra(IntPtr.Zero);
171 if (_gcHandle.IsAllocated)
176 // We can assure that at this point '_packet' is always locked by this lock.
177 _packet._lock.SetUnlock();