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.
17 using System.Collections.Generic;
18 using System.Collections.ObjectModel;
20 using System.Diagnostics;
21 using Tizen.Internals.Errors;
22 using Native = Tizen.Multimedia.Interop.MediaFormat;
24 namespace Tizen.Multimedia
27 /// Represents an audio media format. This class cannot be inherited.
29 /// <since_tizen> 3 </since_tizen>
30 public sealed class AudioMediaFormat : MediaFormat
33 /// Initializes a new instance of the AudioMediaFormat class with the specified mime type,
34 /// channel, sample rate, bit, and bit rate.
36 /// <param name="mimeType">The mime type of the format.</param>
37 /// <param name="channel">The channel value of the format.</param>
38 /// <param name="sampleRate">The sample rate value of the format.</param>
39 /// <param name="bit">The bit value of the format.</param>
40 /// <param name="bitRate">The bit rate value of the format.</param>
41 /// <exception cref="ArgumentException"><paramref name="mimeType"/> is invalid(i.e. undefined value).</exception>
42 /// <exception cref="ArgumentOutOfRangeException">
43 /// <paramref name="channel"/>, <paramref name="sampleRate"/>, <paramref name="bit"/>, or <paramref name="bitRate"/> is less than zero.
45 /// <since_tizen> 3 </since_tizen>
46 public AudioMediaFormat(MediaFormatAudioMimeType mimeType,
47 int channel, int sampleRate, int bit, int bitRate)
48 : this(mimeType, channel, sampleRate, bit, bitRate, MediaFormatAacType.None)
53 /// Initializes a new instance of the AudioMediaFormat class with the specified mime type,
54 /// channel, sample rate, bit, bit rate, and AAC type.
56 /// <param name="mimeType">The mime type of the format.</param>
57 /// <param name="channel">The channel value of the format.</param>
58 /// <param name="sampleRate">The sample rate value of the format.</param>
59 /// <param name="bit">The bit value of the format.</param>
60 /// <param name="bitRate">The bit rate value of the format.</param>
61 /// <param name="aacType">The AAC bitstream format(ADIF or ADTS).</param>
62 /// <exception cref="ArgumentException">
63 /// <paramref name="mimeType"/> or <paramref name="aacType"/> is invalid (i.e. undefined value).<br/>
65 /// <paramref name="aacType"/> is not <see cref="MediaFormatAacType.None"/>, but <paramref name="mimeType"/> is one of the AAC types.
67 /// <exception cref="ArgumentOutOfRangeException">
68 /// <paramref name="channel"/>, <paramref name="sampleRate"/>, <paramref name="bit"/>, or <paramref name="bitRate"/> is less than zero.
70 /// <since_tizen> 3 </since_tizen>
71 public AudioMediaFormat(MediaFormatAudioMimeType mimeType,
72 int channel, int sampleRate, int bit, int bitRate, MediaFormatAacType aacType)
73 : this(mimeType, channel, sampleRate, bit, bitRate, aacType, 0, null)
78 /// Initializes a new instance of the AudioMediaFormat class with the specified mime type,
79 /// channel, sample rate, bit, bit rate, bit depth, and audio channel map.
82 /// If <paramref name="audioChannelMap"/> contains <see cref="MediaFormatAudioChannelPosition.None"/>,
83 /// <paramref name="channel"/> should be set greater than 0.<br/>
84 /// If <paramref name="audioChannelMap"/> contains <see cref="MediaFormatAudioChannelPosition.Mono"/>,
85 /// <paramref name="channel"/> should be set 1.<br/>
86 /// User can not set <see cref="MediaFormatAudioChannelPosition.None"/> with another channel positions.<br/>
87 /// User can not set <see cref="MediaFormatAudioChannelPosition.Mono"/> with another channel positions.<br/>
88 /// If same channel position is added in <paramref name="audioChannelMap"/> more than once, the duplicaiton will be removed.
90 /// <param name="mimeType">The mime type of the format.</param>
91 /// <param name="channel">The channel value of the format.</param>
92 /// <param name="sampleRate">The sample rate value of the format.</param>
93 /// <param name="bit">The bit value of the format.</param>
94 /// <param name="bitRate">The bit rate value of the format.</param>
95 /// <param name="bitDepth">The bit depth value of the PCM audio format.</param>
96 /// <param name="audioChannelMap">The loudspeaker position in PCM audio format.</param>
97 /// <exception cref="ArgumentException">
98 /// <paramref name="mimeType"/> is invalid (i.e. undefined value).<br/>
100 /// <exception cref="ArgumentException">
101 /// <paramref name="audioChannelMap"/> is invalid or mismatched with <paramref name="channel"/> like the following:<br/>
102 /// <paramref name="audioChannelMap"/> is not matched correctly with <paramref name="channel"/>.
104 /// <paramref name="audioChannelMap"/> is set to <see cref="MediaFormatAudioChannelPosition.Invaild"/>.
106 /// <see cref="MediaFormatAudioChannelPosition.Mono"/> or <see cref="MediaFormatAudioChannelPosition.None"/> is set with another channel position.
108 /// <exception cref="ArgumentOutOfRangeException">
109 /// <paramref name="channel"/>, <paramref name="sampleRate"/>, <paramref name="bit"/>, or <paramref name="bitRate"/>,
110 /// <paramref name="bitDepth"/> is less than zero.
112 /// <since_tizen> 6 </since_tizen>
113 public AudioMediaFormat(MediaFormatAudioMimeType mimeType,
114 int channel, int sampleRate, int bit, int bitRate, int bitDepth, IList<MediaFormatAudioChannelPosition> audioChannelMap)
115 : this(mimeType, channel, sampleRate, bit, bitRate, MediaFormatAacType.None, bitDepth, audioChannelMap)
120 /// Initializes a new instance of the AudioMediaFormat class with the specified mime type,
121 /// channel, sample rate, bit, bit rate, bit depth, and audio channel map.
124 /// If <paramref name="audioChannelMap"/> contains <see cref="MediaFormatAudioChannelPosition.None"/>,
125 /// <paramref name="channel"/> should be set greater than 0.<br/>
126 /// If <paramref name="audioChannelMap"/> contains <see cref="MediaFormatAudioChannelPosition.Mono"/>,
127 /// <paramref name="channel"/> should be set 1.<br/>
128 /// User can not set <see cref="MediaFormatAudioChannelPosition.None"/> with another channel positions.<br/>
129 /// User can not set <see cref="MediaFormatAudioChannelPosition.Mono"/> with another channel positions.<br/>
130 /// If same channel position is added in <paramref name="audioChannelMap"/> more than twice, its duplicaiton will be removed.
132 /// <param name="mimeType">The mime type of the format.</param>
133 /// <param name="channel">The channel value of the format.</param>
134 /// <param name="sampleRate">The sample rate value of the format.</param>
135 /// <param name="bit">The bit value of the format.</param>
136 /// <param name="bitRate">The bit rate value of the format.</param>
137 /// <param name="aacType">The AAC bitstream format(ADIF or ADTS).</param>
138 /// <param name="bitDepth">The bit depth value of the PCM audio format.</param>
139 /// <param name="audioChannelMap">The loudspeaker position in PCM audio format.</param>
140 /// <exception cref="ArgumentException">
141 /// <paramref name="mimeType"/> or <paramref name="aacType"/> is invalid (i.e. undefined value).<br/>
143 /// <paramref name="aacType"/> is not <see cref="MediaFormatAacType.None"/>, but <paramref name="mimeType"/> is one of the AAC types.
145 /// <exception cref="ArgumentException">
146 /// <paramref name="audioChannelMap"/> is invalid or mismatched with <paramref name="channel"/> like the following:<br/>
147 /// <paramref name="audioChannelMap"/> is not matched correctly with <paramref name="channel"/>.
149 /// <paramref name="audioChannelMap"/> is set to <see cref="MediaFormatAudioChannelPosition.Invaild"/>.
151 /// <see cref="MediaFormatAudioChannelPosition.Mono"/> or <see cref="MediaFormatAudioChannelPosition.None"/> is set with another channel position.
153 /// <exception cref="ArgumentOutOfRangeException">
154 /// <paramref name="channel"/>, <paramref name="sampleRate"/>, <paramref name="bit"/>, or <paramref name="bitRate"/>,
155 /// <paramref name="bitDepth"/> is less than zero.
157 /// <since_tizen> 6 </since_tizen>
158 public AudioMediaFormat(MediaFormatAudioMimeType mimeType,
159 int channel, int sampleRate, int bit, int bitRate, MediaFormatAacType aacType, int bitDepth, IList<MediaFormatAudioChannelPosition> audioChannelMap)
160 : base(MediaFormatType.Audio)
162 ValidationUtil.ValidateEnum(typeof(MediaFormatAudioMimeType), mimeType, nameof(mimeType));
166 throw new ArgumentOutOfRangeException(nameof(channel), channel,
167 "Channel value can't be negative.");
171 throw new ArgumentOutOfRangeException(nameof(sampleRate), sampleRate,
172 "Sample rate value can't be negative.");
176 throw new ArgumentOutOfRangeException(nameof(bit), bit,
177 "Bit value can't be negative.");
181 throw new ArgumentOutOfRangeException(nameof(bitRate), bitRate,
182 "Bit rate value can't be negative.");
186 throw new ArgumentOutOfRangeException(nameof(bitDepth), bitDepth,
187 "Bit depth value can't be negative.");
190 ValidationUtil.ValidateEnum(typeof(MediaFormatAacType), aacType, nameof(aacType));
192 if (!IsAacSupportedMimeType(mimeType) && aacType != MediaFormatAacType.None)
194 throw new ArgumentException("Aac is supported only with aac mime types.");
200 SampleRate = sampleRate;
205 if (audioChannelMap != null)
207 audioChannelMap = audioChannelMap.Distinct().OrderBy(p => p).ToList();
209 ValidateAudioChannelMap(audioChannelMap);
211 AudioChannelMap = new ReadOnlyCollection<MediaFormatAudioChannelPosition>(audioChannelMap);
215 private void ValidateAudioChannelMap(IList<MediaFormatAudioChannelPosition> audioChannelMap)
217 if (audioChannelMap.Contains(MediaFormatAudioChannelPosition.Invaild))
219 throw new ArgumentException("Invalid channel position.", nameof(audioChannelMap));
222 if ((audioChannelMap.Contains(MediaFormatAudioChannelPosition.Mono) && audioChannelMap.Count > 1) ||
223 (audioChannelMap.Contains(MediaFormatAudioChannelPosition.None) && audioChannelMap.Count > 1))
225 throw new ArgumentException($"Mono and None can not be set with another channel position.",
226 nameof(audioChannelMap));
229 if (audioChannelMap.Contains(MediaFormatAudioChannelPosition.None))
233 throw new ArgumentException($"Channel should be greater than 0 in {MediaFormatAudioChannelPosition.None}.",
234 nameof(audioChannelMap));
239 if (audioChannelMap.Count != Channel)
241 throw new ArgumentException("Channel should be the same with number of audioChannelMap.",
242 nameof(audioChannelMap));
248 /// Initializes a new instance of the AudioMediaFormat class from a native handle.
250 /// <param name="handle">A native handle.</param>
251 internal AudioMediaFormat(IntPtr handle)
252 : base(MediaFormatType.Audio)
254 Debug.Assert(handle != IntPtr.Zero, "The handle is invalid!");
256 GetInfo(handle, out var mimeType, out var channel, out var sampleRate, out var bit, out var bitRate);
260 SampleRate = sampleRate;
263 AacType = IsAacSupportedMimeType(mimeType) ? GetAacType(handle) : MediaFormatAacType.None;
264 AudioChannelMap = Channel == 0 ? null : GetAudioChannelMap(handle);
267 private static ReadOnlyCollection<MediaFormatAudioChannelPosition> GetAudioChannelMap(IntPtr handle)
269 var ret = Native.GetAudioChannelMask(handle, out ulong mask);
270 MultimediaDebug.AssertNoError(ret);
272 var positions = new MediaFormatAudioChannelPosition[Enum.GetNames(typeof(MediaFormatAudioChannelPosition)).Length];
274 ret = Native.GetChannelPositionFromMask(handle, mask, ref positions);
275 MultimediaDebug.AssertNoError(ret);
277 return positions == null ? null :
278 new ReadOnlyCollection<MediaFormatAudioChannelPosition>(positions.Distinct().OrderBy(p => p).ToList());
282 /// Returns an indication whether a specified mime type is an AAC type.
284 /// <param name="mimeType">A mime type.</param>
285 private static bool IsAacSupportedMimeType(MediaFormatAudioMimeType mimeType)
287 return mimeType == MediaFormatAudioMimeType.AacLC ||
288 mimeType == MediaFormatAudioMimeType.AacHE ||
289 mimeType == MediaFormatAudioMimeType.AacHEPS;
293 /// Retrieves audio properties of the media format from a native handle.
295 /// <param name="handle">A native handle that the properties are retrieved from.</param>
296 /// <param name="mimeType">An out parameter for the mime type.</param>
297 /// <param name="channel">An out parameter for the channel.</param>
298 /// <param name="sampleRate">An out parameter for the sample rate.</param>
299 /// <param name="bit">An out parameter for the bit.</param>
300 /// <param name="bitRate">An out parameter for the bit rate.</param>
301 private static void GetInfo(IntPtr handle, out MediaFormatAudioMimeType mimeType,
302 out int channel, out int sampleRate, out int bit, out int bitRate)
304 Debug.Assert(handle != IntPtr.Zero, "The handle is invalid!");
306 int ret = Native.GetAudioInfo(handle,
307 out mimeType, out channel, out sampleRate, out bit, out bitRate);
309 MultimediaDebug.AssertNoError(ret);
311 Debug.Assert(Enum.IsDefined(typeof(MediaFormatAudioMimeType), mimeType),
312 "Invalid audio mime type!");
316 /// Retrieves the AAC type value from a native handle.
318 /// <param name="handle">A native handle that the properties are retrieved from.</param>
319 private static MediaFormatAacType GetAacType(IntPtr handle)
321 Debug.Assert(handle != IntPtr.Zero, "The handle is invalid!");
323 int ret = Native.GetAudioAacType(handle, out var aacType);
325 MultimediaDebug.AssertNoError(ret);
327 Debug.Assert(Enum.IsDefined(typeof(MediaFormatAacType), aacType), "Invalid aac type!");
332 internal override void AsNativeHandle(IntPtr handle)
334 Debug.Assert(Type == MediaFormatType.Audio);
336 int ret = Native.SetAudioMimeType(handle, MimeType);
337 MultimediaDebug.AssertNoError(ret);
339 ret = Native.SetAudioChannel(handle, Channel);
340 MultimediaDebug.AssertNoError(ret);
342 ret = Native.SetAudioSampleRate(handle, SampleRate);
343 MultimediaDebug.AssertNoError(ret);
345 ret = Native.SetAudioBit(handle, Bit);
346 MultimediaDebug.AssertNoError(ret);
348 ret = Native.SetAudioAverageBps(handle, BitRate);
349 MultimediaDebug.AssertNoError(ret);
351 ret = Native.SetAudioAacType(handle, AacType);
352 MultimediaDebug.AssertNoError(ret);
354 if (AudioChannelMap != null)
356 ret = Native.SetAudioChannelMask(handle, GetAudioChannelMask(handle, AudioChannelMap));
357 MultimediaDebug.AssertNoError(ret);
361 private static ulong GetAudioChannelMask(IntPtr handle, IList<MediaFormatAudioChannelPosition> audioChannelMap)
363 int ret = Native.GetMaskFromChannelPosition(handle, audioChannelMap.ToArray(),
365 MultimediaDebug.AssertNoError(ret);
371 /// Gets the mime type of the current format.
373 /// <since_tizen> 3 </since_tizen>
374 public MediaFormatAudioMimeType MimeType { get; }
377 /// Gets the channel value of the current format.
379 /// <since_tizen> 3 </since_tizen>
380 public int Channel { get; }
383 /// Gets or sets the list of channel position value of PCM audio format.
386 /// The channel mask specifies the mapping of channels to speakers.
387 /// default value is 0.
389 /// <seealso cref="Channel"/>
390 /// <seealso cref="MediaFormatAudioChannelPosition"/>
391 /// <since_tizen> 6 </since_tizen>
392 public ReadOnlyCollection<MediaFormatAudioChannelPosition> AudioChannelMap { get; }
395 /// Gets the sample rate value of the current format.
397 /// <since_tizen> 3 </since_tizen>
398 public int SampleRate { get; }
401 /// Gets the bit value of the current format.
403 /// <since_tizen> 3 </since_tizen>
404 public int Bit { get; }
407 /// Gets the bit rate value of the current format.
409 /// <since_tizen> 3 </since_tizen>
410 public int BitRate { get; }
413 /// Gets the bit depth value of the current format.
415 /// <since_tizen> 6 </since_tizen>
416 public int BitDepth { get; }
419 /// Gets the AAC type of the current format.
421 /// <since_tizen> 3 </since_tizen>
422 public MediaFormatAacType AacType { get; }
425 /// Returns a string that represents the current object.
427 /// <returns>A string that represents the current object.</returns>
428 /// <since_tizen> 3 </since_tizen>
429 public override string ToString()
431 var toString = $@"MimeType={ MimeType.ToString() }, Channel={ Channel.ToString() }, SampleRate={ SampleRate },
432 Bit={ Bit.ToString() }, BitRate={ BitRate.ToString() }, BitDepth={ BitDepth.ToString() }, AacType={ AacType.ToString()}";
434 if (AudioChannelMap != null)
436 toString += ", AudioChannelMap=" + $"{string.Join(",", AudioChannelMap)}";
443 /// Compares an object to an instance of <see cref="AudioMediaFormat"/> for equality.
445 /// <param name="obj">A <see cref="Object"/> to compare.</param>
446 /// <returns>true if the formats are equal; otherwise, false.</returns>
447 /// <since_tizen> 3 </since_tizen>
448 public override bool Equals(object obj)
450 var rhs = obj as AudioMediaFormat;
456 var mapCompare = true;
457 // We don't care the case of both properties are null.
458 if (AudioChannelMap != null && rhs.AudioChannelMap != null)
460 for (int i = 0; i < AudioChannelMap.Count; i++)
462 mapCompare = AudioChannelMap[i].Equals(rhs.AudioChannelMap[i]);
465 else if ((AudioChannelMap == null && rhs.AudioChannelMap != null) ||
466 (AudioChannelMap != null && rhs.AudioChannelMap == null))
471 return MimeType == rhs.MimeType && Channel == rhs.Channel && SampleRate == rhs.SampleRate &&
472 Bit == rhs.Bit && BitRate == rhs.BitRate && BitDepth == rhs.BitDepth && AacType == rhs.AacType && mapCompare;
476 /// Gets the hash code for this instance of <see cref="AudioMediaFormat"/>.
478 /// <returns>The hash code for this instance of <see cref="AudioMediaFormat"/>.</returns>
479 /// <since_tizen> 3 </since_tizen>
480 public override int GetHashCode()
481 => new { MimeType, Channel, SampleRate, Bit, BitRate, BitDepth, AacType, AudioChannelMap }.GetHashCode();