/*
* 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();
}
}