/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Diagnostics; using Tizen.Internals.Errors; using Native = Tizen.Multimedia.Interop.MediaFormat; namespace Tizen.Multimedia { /// /// Represents an audio media format. This class cannot be inherited. /// /// 3 public sealed class AudioMediaFormat : MediaFormat { /// /// Initializes a new instance of the AudioMediaFormat class with the specified mime type, /// channel, sample rate, bit, and bit rate. /// /// The mime type of the format. /// The channel value of the format. /// The sample rate value of the format. /// The bit value of the format. /// The bit rate value of the format. /// is invalid(i.e. undefined value). /// /// , , , or is less than zero. /// /// 3 public AudioMediaFormat(MediaFormatAudioMimeType mimeType, int channel, int sampleRate, int bit, int bitRate) : this(mimeType, channel, sampleRate, bit, bitRate, MediaFormatAacType.None) { } /// /// Initializes a new instance of the AudioMediaFormat class with the specified mime type, /// channel, sample rate, bit, bit rate, and AAC type. /// /// The mime type of the format. /// The channel value of the format. /// The sample rate value of the format. /// The bit value of the format. /// The bit rate value of the format. /// The AAC bitstream format(ADIF or ADTS). /// /// or is invalid (i.e. undefined value).
/// -or-
/// is not , but is one of the AAC types. ///
/// /// , , , or is less than zero. /// /// 3 public AudioMediaFormat(MediaFormatAudioMimeType mimeType, int channel, int sampleRate, int bit, int bitRate, MediaFormatAacType aacType) : this(mimeType, channel, sampleRate, bit, bitRate, aacType, 0, null) { } /// /// Initializes a new instance of the AudioMediaFormat class with the specified mime type, /// channel, sample rate, bit, bit rate, bit depth, and audio channel map. /// /// /// If contains , /// should be set greater than 0.
/// If contains , /// should be set 1.
/// User can not set with another channel positions.
/// User can not set with another channel positions.
/// If same channel position is added in more than once, the duplicaiton will be removed. ///
/// The mime type of the format. /// The channel value of the format. /// The sample rate value of the format. /// The bit value of the format. /// The bit rate value of the format. /// The bit depth value of the PCM audio format. /// The loudspeaker position in PCM audio format. /// /// is invalid (i.e. undefined value).
///
/// /// is invalid or mismatched with like the following:
/// is not matched correctly with . /// -or-
/// is set to . /// -or-
/// or is set with another channel position. ///
/// /// , , , or , /// is less than zero. /// /// 6 public AudioMediaFormat(MediaFormatAudioMimeType mimeType, int channel, int sampleRate, int bit, int bitRate, int bitDepth, IList audioChannelMap) : this(mimeType, channel, sampleRate, bit, bitRate, MediaFormatAacType.None, bitDepth, audioChannelMap) { } /// /// Initializes a new instance of the AudioMediaFormat class with the specified mime type, /// channel, sample rate, bit, bit rate, bit depth, and audio channel map. /// /// /// If contains , /// should be set greater than 0.
/// If contains , /// should be set 1.
/// User can not set with another channel positions.
/// User can not set with another channel positions.
/// If same channel position is added in more than twice, its duplicaiton will be removed. ///
/// The mime type of the format. /// The channel value of the format. /// The sample rate value of the format. /// The bit value of the format. /// The bit rate value of the format. /// The AAC bitstream format(ADIF or ADTS). /// The bit depth value of the PCM audio format. /// The loudspeaker position in PCM audio format. /// /// or is invalid (i.e. undefined value).
/// -or-
/// is not , but is one of the AAC types. ///
/// /// is invalid or mismatched with like the following:
/// is not matched correctly with . /// -or-
/// is set to . /// -or-
/// or is set with another channel position. ///
/// /// , , , or , /// is less than zero. /// /// 6 public AudioMediaFormat(MediaFormatAudioMimeType mimeType, int channel, int sampleRate, int bit, int bitRate, MediaFormatAacType aacType, int bitDepth, IList audioChannelMap) : base(MediaFormatType.Audio) { ValidationUtil.ValidateEnum(typeof(MediaFormatAudioMimeType), mimeType, nameof(mimeType)); if (channel < 0) { throw new ArgumentOutOfRangeException(nameof(channel), channel, "Channel value can't be negative."); } if (sampleRate < 0) { throw new ArgumentOutOfRangeException(nameof(sampleRate), sampleRate, "Sample rate value can't be negative."); } if (bit < 0) { throw new ArgumentOutOfRangeException(nameof(bit), bit, "Bit value can't be negative."); } if (bitRate < 0) { throw new ArgumentOutOfRangeException(nameof(bitRate), bitRate, "Bit rate value can't be negative."); } if (bitDepth < 0) { throw new ArgumentOutOfRangeException(nameof(bitDepth), bitDepth, "Bit depth value can't be negative."); } ValidationUtil.ValidateEnum(typeof(MediaFormatAacType), aacType, nameof(aacType)); if (!IsAacSupportedMimeType(mimeType) && aacType != MediaFormatAacType.None) { throw new ArgumentException("Aac is supported only with aac mime types."); } MimeType = mimeType; AacType = aacType; Channel = channel; SampleRate = sampleRate; Bit = bit; BitRate = bitRate; BitDepth = bitDepth; if (audioChannelMap != null) { audioChannelMap = audioChannelMap.Distinct().OrderBy(p => p).ToList(); ValidateAudioChannelMap(audioChannelMap); AudioChannelMap = new ReadOnlyCollection(audioChannelMap); } } private void ValidateAudioChannelMap(IList audioChannelMap) { if (audioChannelMap.Contains(MediaFormatAudioChannelPosition.Invaild)) { throw new ArgumentException("Invalid channel position.", nameof(audioChannelMap)); } if ((audioChannelMap.Contains(MediaFormatAudioChannelPosition.Mono) && audioChannelMap.Count > 1) || (audioChannelMap.Contains(MediaFormatAudioChannelPosition.None) && audioChannelMap.Count > 1)) { throw new ArgumentException($"Mono and None can not be set with another channel position.", nameof(audioChannelMap)); } if (audioChannelMap.Contains(MediaFormatAudioChannelPosition.None)) { if (Channel <= 0) { throw new ArgumentException($"Channel should be greater than 0 in {MediaFormatAudioChannelPosition.None}.", nameof(audioChannelMap)); } } else { if (audioChannelMap.Count != Channel) { throw new ArgumentException("Channel should be the same with number of audioChannelMap.", nameof(audioChannelMap)); } } } /// /// Initializes a new instance of the AudioMediaFormat class from a native handle. /// /// A native handle. internal AudioMediaFormat(IntPtr handle) : base(MediaFormatType.Audio) { Debug.Assert(handle != IntPtr.Zero, "The handle is invalid!"); GetInfo(handle, out var mimeType, out var channel, out var sampleRate, out var bit, out var bitRate); MimeType = mimeType; Channel = channel; SampleRate = sampleRate; Bit = bit; BitRate = bitRate; AacType = IsAacSupportedMimeType(mimeType) ? GetAacType(handle) : MediaFormatAacType.None; AudioChannelMap = Channel == 0 ? null : GetAudioChannelMap(handle); } private static ReadOnlyCollection GetAudioChannelMap(IntPtr handle) { var ret = Native.GetAudioChannelMask(handle, out ulong mask); MultimediaDebug.AssertNoError(ret); var positions = new MediaFormatAudioChannelPosition[Enum.GetNames(typeof(MediaFormatAudioChannelPosition)).Length]; ret = Native.GetChannelPositionFromMask(handle, mask, ref positions); MultimediaDebug.AssertNoError(ret); return positions == null ? null : new ReadOnlyCollection(positions.Distinct().OrderBy(p => p).ToList()); } /// /// Returns an indication whether a specified mime type is an AAC type. /// /// A mime type. private static bool IsAacSupportedMimeType(MediaFormatAudioMimeType mimeType) { return mimeType == MediaFormatAudioMimeType.AacLC || mimeType == MediaFormatAudioMimeType.AacHE || mimeType == MediaFormatAudioMimeType.AacHEPS; } /// /// Retrieves audio properties of the media format from a native handle. /// /// A native handle that the properties are retrieved from. /// An out parameter for the mime type. /// An out parameter for the channel. /// An out parameter for the sample rate. /// An out parameter for the bit. /// An out parameter for the bit rate. private static void GetInfo(IntPtr handle, out MediaFormatAudioMimeType mimeType, out int channel, out int sampleRate, out int bit, out int bitRate) { Debug.Assert(handle != IntPtr.Zero, "The handle is invalid!"); int ret = Native.GetAudioInfo(handle, out mimeType, out channel, out sampleRate, out bit, out bitRate); MultimediaDebug.AssertNoError(ret); Debug.Assert(Enum.IsDefined(typeof(MediaFormatAudioMimeType), mimeType), "Invalid audio mime type!"); } /// /// Retrieves the AAC type value from a native handle. /// /// A native handle that the properties are retrieved from. private static MediaFormatAacType GetAacType(IntPtr handle) { Debug.Assert(handle != IntPtr.Zero, "The handle is invalid!"); int ret = Native.GetAudioAacType(handle, out var aacType); MultimediaDebug.AssertNoError(ret); Debug.Assert(Enum.IsDefined(typeof(MediaFormatAacType), aacType), "Invalid aac type!"); return aacType; } internal override void AsNativeHandle(IntPtr handle) { Debug.Assert(Type == MediaFormatType.Audio); int ret = Native.SetAudioMimeType(handle, MimeType); MultimediaDebug.AssertNoError(ret); ret = Native.SetAudioChannel(handle, Channel); MultimediaDebug.AssertNoError(ret); ret = Native.SetAudioSampleRate(handle, SampleRate); MultimediaDebug.AssertNoError(ret); ret = Native.SetAudioBit(handle, Bit); MultimediaDebug.AssertNoError(ret); ret = Native.SetAudioAverageBps(handle, BitRate); MultimediaDebug.AssertNoError(ret); ret = Native.SetAudioAacType(handle, AacType); MultimediaDebug.AssertNoError(ret); if (AudioChannelMap != null) { ret = Native.SetAudioChannelMask(handle, GetAudioChannelMask(handle, AudioChannelMap)); MultimediaDebug.AssertNoError(ret); } } private static ulong GetAudioChannelMask(IntPtr handle, IList audioChannelMap) { int ret = Native.GetMaskFromChannelPosition(handle, audioChannelMap.ToArray(), out ulong mask); MultimediaDebug.AssertNoError(ret); return mask; } /// /// Gets the mime type of the current format. /// /// 3 public MediaFormatAudioMimeType MimeType { get; } /// /// Gets the channel value of the current format. /// /// 3 public int Channel { get; } /// /// Gets or sets the list of channel position value of PCM audio format. /// /// /// The channel mask specifies the mapping of channels to speakers. /// default value is 0. /// /// /// /// 6 public ReadOnlyCollection AudioChannelMap { get; } /// /// Gets the sample rate value of the current format. /// /// 3 public int SampleRate { get; } /// /// Gets the bit value of the current format. /// /// 3 public int Bit { get; } /// /// Gets the bit rate value of the current format. /// /// 3 public int BitRate { get; } /// /// Gets the bit depth value of the current format. /// /// 6 public int BitDepth { get; } /// /// Gets the AAC type of the current format. /// /// 3 public MediaFormatAacType AacType { get; } /// /// Returns a string that represents the current object. /// /// A string that represents the current object. /// 3 public override string ToString() { var toString = $@"MimeType={ MimeType.ToString() }, Channel={ Channel.ToString() }, SampleRate={ SampleRate }, Bit={ Bit.ToString() }, BitRate={ BitRate.ToString() }, BitDepth={ BitDepth.ToString() }, AacType={ AacType.ToString()}"; if (AudioChannelMap != null) { toString += ", AudioChannelMap=" + $"{string.Join(",", AudioChannelMap)}"; } return toString; } /// /// Compares an object to an instance of for equality. /// /// A to compare. /// true if the formats are equal; otherwise, false. /// 3 public override bool Equals(object obj) { var rhs = obj as AudioMediaFormat; if (rhs == null) { return false; } var mapCompare = true; // We don't care the case of both properties are null. if (AudioChannelMap != null && rhs.AudioChannelMap != null) { for (int i = 0; i < AudioChannelMap.Count; i++) { mapCompare = AudioChannelMap[i].Equals(rhs.AudioChannelMap[i]); } } else if ((AudioChannelMap == null && rhs.AudioChannelMap != null) || (AudioChannelMap != null && rhs.AudioChannelMap == null)) { mapCompare = false; } return MimeType == rhs.MimeType && Channel == rhs.Channel && SampleRate == rhs.SampleRate && Bit == rhs.Bit && BitRate == rhs.BitRate && BitDepth == rhs.BitDepth && AacType == rhs.AacType && mapCompare; } /// /// Gets the hash code for this instance of . /// /// The hash code for this instance of . /// 3 public override int GetHashCode() => new { MimeType, Channel, SampleRate, Bit, BitRate, BitDepth, AacType, AudioChannelMap }.GetHashCode(); } }