From 949c1b6e8f28fc6e0874c249952e89981b76b9a9 Mon Sep 17 00:00:00 2001 From: nam <36914158+aferin@users.noreply.github.com> Date: Mon, 26 Aug 2019 13:39:49 +0900 Subject: [PATCH] [MediaPlayer] add APIs to use AudioOffload (#974) * [MediaPlayer] add APIs to use AudioOffload --- .../Interop/Interop.Player.cs | 15 ++ .../Player/AudioEffect.cs | 78 +++++--- .../Player/AudioOffload.cs | 188 ++++++++++++++++++ .../Player/EqualizerBand.cs | 47 ++++- .../Player/Player.Properties.cs | 52 ++++- .../Player/Player.cs | 8 +- .../Player/PlayerFeatures.cs | 1 + .../Player/PlayerTrackInfo.cs | 28 ++- 8 files changed, 374 insertions(+), 43 deletions(-) create mode 100644 src/Tizen.Multimedia.MediaPlayer/Player/AudioOffload.cs diff --git a/src/Tizen.Multimedia.MediaPlayer/Interop/Interop.Player.cs b/src/Tizen.Multimedia.MediaPlayer/Interop/Interop.Player.cs index fc70274c0..819ce0fde 100644 --- a/src/Tizen.Multimedia.MediaPlayer/Interop/Interop.Player.cs +++ b/src/Tizen.Multimedia.MediaPlayer/Interop/Interop.Player.cs @@ -66,6 +66,9 @@ internal static partial class Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate bool AdaptiveVariantCallback(int bandwidth, int width, int height, IntPtr userData); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate bool SupportedMediaFormatCallback(int format, IntPtr userData); + [DllImport(Libraries.Player, EntryPoint = "player_create")] internal static extern PlayerErrorCode Create(out PlayerHandle player); @@ -363,6 +366,18 @@ internal static partial class Interop [DllImport(Libraries.Player, EntryPoint = "player_audio_pitch_get_value")] internal static extern PlayerErrorCode GetAudioPitch(IntPtr player, out float level); + + [DllImport(Libraries.Player, EntryPoint = "player_audio_offload_set_enabled")] + internal static extern PlayerErrorCode SetAudioOffloadEnabled(IntPtr player, bool value); + + [DllImport(Libraries.Player, EntryPoint = "player_audio_offload_is_enabled")] + internal static extern PlayerErrorCode IsAudioOffloadEnabled(IntPtr player, out bool value); + + [DllImport(Libraries.Player, EntryPoint = "player_audio_offload_is_activated")] + internal static extern PlayerErrorCode IsAudioOffloadActivated(IntPtr player, out bool value); + + [DllImport(Libraries.Player, EntryPoint = "player_audio_offload_foreach_supported_format")] + internal static extern PlayerErrorCode SupportedAudioOffloadFormat(IntPtr player, SupportedMediaFormatCallback callback, IntPtr userData); } internal class PlayerHandle : SafeHandle diff --git a/src/Tizen.Multimedia.MediaPlayer/Player/AudioEffect.cs b/src/Tizen.Multimedia.MediaPlayer/Player/AudioEffect.cs index d7a2e84b1..8cc310d93 100644 --- a/src/Tizen.Multimedia.MediaPlayer/Player/AudioEffect.cs +++ b/src/Tizen.Multimedia.MediaPlayer/Player/AudioEffect.cs @@ -31,31 +31,12 @@ namespace Tizen.Multimedia { Player = owner; - bool available = false; - - Native.EqualizerIsAvailable(Player.Handle, out available). - ThrowIfFailed(Player, "Failed to initialize the AudioEffect"); - - IsAvailable = available; - - if (IsAvailable == false) + if (IsAvailable== false) { return; } - int count = 0; - Native.GetEqualizerBandsCount(Player.Handle, out count). - ThrowIfFailed(Player, "Failed to initialize the AudioEffect"); - - int min = 0; - int max = 0; - Native.GetEqualizerLevelRange(Player.Handle, out min, out max). - ThrowIfFailed(Player, "Failed to initialize the AudioEffect"); - - Count = count; - BandLevelRange = new Range(min, max); - - _bands = new EqualizerBand[count]; + _bands = new EqualizerBand[Count]; } /// @@ -68,12 +49,16 @@ namespace Tizen.Multimedia /// -or-
/// is equal to or greater than . /// + /// + /// If audio offload is enabled by calling . (Since tizen 6.0) + /// /// 3 public EqualizerBand this[int index] { get { Player.ValidateNotDisposed(); + Player.AudioOffload.CheckDisabled(); if (index < 0 || Count <= index) { @@ -94,10 +79,14 @@ namespace Tizen.Multimedia /// Clears the equalizer effect. ///
/// The has already been disposed of. + /// + /// If audio offload is enabled by calling . (Since tizen 6.0) + /// /// 3 public void Clear() { Player.ValidateNotDisposed(); + Player.AudioOffload.CheckDisabled(); Native.EqualizerClear(Player.Handle). ThrowIfFailed(Player, "Failed to clear equalizer effect"); @@ -106,20 +95,61 @@ namespace Tizen.Multimedia /// /// Gets the number of items. /// + /// + /// If audio offload is enabled by calling . (Since tizen 6.0) + /// /// 3 - public int Count { get; } + public int Count + { + get + { + Player.AudioOffload.CheckDisabled(); + + Native.GetEqualizerBandsCount(Player.Handle, out var count). + ThrowIfFailed(Player, "Failed to initialize the AudioEffect"); + + return count; + } + } /// /// Gets the band level range of the bands in the dB. /// + /// + /// If audio offload is enabled by calling . (Since tizen 6.0) + /// /// 3 - public Range BandLevelRange { get; } + public Range BandLevelRange + { + get + { + Player.AudioOffload.CheckDisabled(); + + Native.GetEqualizerLevelRange(Player.Handle, out var min, out var max). + ThrowIfFailed(Player, "Failed to initialize the AudioEffect"); + + return new Range(min, max); + } + } /// /// Gets the value whether the AudioEffect is available or not. /// + /// + /// If audio offload is enabled by calling . (Since tizen 6.0) + /// /// 3 - public bool IsAvailable { get; } + public bool IsAvailable + { + get + { + Player.AudioOffload.CheckDisabled(); + + Native.EqualizerIsAvailable(Player.Handle, out var available). + ThrowIfFailed(Player, "Failed to initialize the AudioEffect"); + return available; + } + } /// /// Gets the player that this AudioEffect belongs to. diff --git a/src/Tizen.Multimedia.MediaPlayer/Player/AudioOffload.cs b/src/Tizen.Multimedia.MediaPlayer/Player/AudioOffload.cs new file mode 100644 index 000000000..30569bfe1 --- /dev/null +++ b/src/Tizen.Multimedia.MediaPlayer/Player/AudioOffload.cs @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2019 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.Diagnostics; +using System.Collections.Generic; +using static Interop; + +namespace Tizen.Multimedia +{ + /// + /// Provides the ability to control the audio offload for . + /// + /// 6 + public class AudioOffload + { + private IList _supportedFormat; + private Player _player { get; } + + /// + /// Provides a means to retrieve audio offload information. + /// + /// 6 + internal AudioOffload(Player player) + { + Debug.Assert(player != null); + _player = player; + } + + private bool _enabled; + internal void CheckDisabled() + { + if (_enabled) + { + throw new InvalidOperationException("the audio offload is enabled."); + } + } + + /// + /// Enables or disables the audio offload. + /// + /// The value indicating whether or not AudioOffload is enabled. The default value is false. + /// The player lets the hardware decode and render the sound if the audio offload is enabled. + /// This will reduce the power consumption, but will disable the ability to handle output PCM. + /// Please check the below list of functions which will not work if offloading is enabled. + /// If audio offload is enabled, the following functions will return + /// and they will not work at all even if they were called before offload is enabled.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// To set, the player must be in the state. + /// The sound stream type of the player should be .
+ /// http://tizen.org/feature/multimedia.player.audio_offload + /// The required feature is not supported. + /// The player has already been disposed of. + /// + /// The player is not in the valid state.
+ /// -or-
+ /// Operation failed; internal error. + ///
+ /// 6 + public bool IsEnabled + { + get + { + ValidationUtil.ValidateFeatureSupported(PlayerFeatures.AudioOffload); + _player.ValidateNotDisposed(); + + NativePlayer.IsAudioOffloadEnabled(_player.Handle, out var value). + ThrowIfFailed(_player, "Failed to get whether the audio offload of the player is enabled or not"); + return value; + } + + set + { + ValidationUtil.ValidateFeatureSupported(PlayerFeatures.AudioOffload); + _player.ValidateNotDisposed(); + _player.ValidatePlayerState(PlayerState.Idle); + + NativePlayer.SetAudioOffloadEnabled(_player.Handle, value). + ThrowIfFailed(_player, "Failed to set the audio offload of the player"); + _enabled = value; + } + } + + /// + /// Get a state whether or not the audio offload is activated. + /// + /// The value indicating whether or not AudioOffload is activated. + /// + /// Audio offload could be inactivated depending on the audio device capability even if the audio offload feature is supported. + /// The that owns this instance must be in the , + /// , or state. + /// + /// http://tizen.org/feature/multimedia.player.audio_offload + /// The required feature is not supported. + /// The player has already been disposed of. + /// + /// The player is not in the valid state.
+ /// -or-
+ /// Operation failed; internal error. + ///
+ /// 6 + public bool IsActivated + { + get + { + ValidationUtil.ValidateFeatureSupported(PlayerFeatures.AudioOffload); + _player.ValidateNotDisposed(); + _player.ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused); + + NativePlayer.IsAudioOffloadActivated(_player.Handle, out var value). + ThrowIfFailed(_player, "Failed to get whether the audio offload of the player is enabled or not"); + return value; + } + } + + /// + /// Retrieves all formats for audio offload. + /// + /// + /// It returns a list contained all formats for audio offload. + /// + /// The supported media format can vary depending on the device capabilities. + /// http://tizen.org/feature/multimedia.player.audio_offload + /// The required feature is not supported. + /// The has already been disposed of. + /// + /// Operation failed; internal error. + /// + /// + /// 6 + public IEnumerable SupportedFormats + { + get + { + if (_supportedFormat == null) + { + _supportedFormat = GetSupportedFormats(); + } + + return _supportedFormat; + } + } + + private IList GetSupportedFormats() + { + List audioFormats = new List(); + + NativePlayer.SupportedMediaFormatCallback callback = (int format, IntPtr userData) => + { + if (!Enum.IsDefined(typeof(MediaFormatAudioMimeType), format)) + { + Log.Warn(PlayerLog.Tag, "not supported : " + format.ToString()); + return false; + } + + Log.Debug(PlayerLog.Tag, "supported : " + ((MediaFormatAudioMimeType)format).ToString()); + audioFormats.Add((MediaFormatAudioMimeType)format); + return true; + }; + + NativePlayer.SupportedAudioOffloadFormat(_player.Handle, callback, IntPtr.Zero). + ThrowIfFailed(_player, "Failed to get the supported formats for audio offload"); + + return audioFormats.AsReadOnly(); + } + } +} diff --git a/src/Tizen.Multimedia.MediaPlayer/Player/EqualizerBand.cs b/src/Tizen.Multimedia.MediaPlayer/Player/EqualizerBand.cs index 86cdc73e1..569572d44 100644 --- a/src/Tizen.Multimedia.MediaPlayer/Player/EqualizerBand.cs +++ b/src/Tizen.Multimedia.MediaPlayer/Player/EqualizerBand.cs @@ -37,15 +37,7 @@ namespace Tizen.Multimedia _owner = owner; _index = index; - Native.GetEqualizerBandFrequency(_owner.Player.Handle, _index, out var frequency). - ThrowIfFailed(_owner.Player, "Failed to initialize equalizer band"); - - Native.GetEqualizerBandFrequencyRange(_owner.Player.Handle, _index, out var range). - ThrowIfFailed(_owner.Player, "Failed to initialize equalizer band"); - - Frequency = frequency; - FrequencyRange = range; - Log.Debug(PlayerLog.Tag, "frequency : " + frequency + ", range : " + range); + Log.Debug(PlayerLog.Tag, "frequency : " + Frequency + ", range : " + FrequencyRange); } /// @@ -56,12 +48,16 @@ namespace Tizen.Multimedia /// /// is not inside of . /// + /// + /// If audio offload is enabled by calling . (Since tizen 6.0) + /// /// 3 public int Level { get { _owner.Player.ValidateNotDisposed(); + _owner.Player.AudioOffload.CheckDisabled(); Native.GetEqualizerBandLevel(_owner.Player.Handle, _index, out var value). ThrowIfFailed(_owner.Player, "Failed to get the level of the equalizer band"); @@ -72,6 +68,7 @@ namespace Tizen.Multimedia set { _owner.Player.ValidateNotDisposed(); + _owner.Player.AudioOffload.CheckDisabled(); if (value < _owner.BandLevelRange.Min || _owner.BandLevelRange.Max < value) { @@ -90,14 +87,42 @@ namespace Tizen.Multimedia /// /// Gets the frequency in the dB. /// + /// + /// If audio offload is enabled by calling . (Since tizen 6.0) + /// /// 3 - public int Frequency { get; } + public int Frequency + { + get + { + _owner.Player.AudioOffload.CheckDisabled(); + + Native.GetEqualizerBandFrequency(_owner.Player.Handle, _index, out var frequency). + ThrowIfFailed(_owner.Player, "Failed to initialize equalizer band"); + + return frequency; + } + } /// /// Gets the frequency range in the dB. /// + /// + /// If audio offload is enabled by calling . (Since tizen 6.0) + /// /// 3 - public int FrequencyRange { get; } + public int FrequencyRange + { + get + { + _owner.Player.AudioOffload.CheckDisabled(); + + Native.GetEqualizerBandFrequencyRange(_owner.Player.Handle, _index, out var frequencyRange). + ThrowIfFailed(_owner.Player, "Failed to initialize equalizer band"); + + return frequencyRange; + } + } } } diff --git a/src/Tizen.Multimedia.MediaPlayer/Player/Player.Properties.cs b/src/Tizen.Multimedia.MediaPlayer/Player/Player.Properties.cs index 6c2c8fc85..fd90eeecb 100644 --- a/src/Tizen.Multimedia.MediaPlayer/Player/Player.Properties.cs +++ b/src/Tizen.Multimedia.MediaPlayer/Player/Player.Properties.cs @@ -233,11 +233,16 @@ namespace Tizen.Multimedia /// /// The player has already been disposed of. /// The value is not valid. + /// + /// If audio offload is enabled by calling . (Since tizen 6.0) + /// /// 3 public AudioLatencyMode AudioLatencyMode { get { + AudioOffload.CheckDisabled(); + NativePlayer.GetAudioLatencyMode(Handle, out var value). ThrowIfFailed(this, "Failed to get the audio latency mode of the player"); @@ -246,6 +251,7 @@ namespace Tizen.Multimedia set { ValidateNotDisposed(); + AudioOffload.CheckDisabled(); ValidationUtil.ValidateEnum(typeof(AudioLatencyMode), value, nameof(value)); @@ -540,13 +546,19 @@ namespace Tizen.Multimedia /// If the replaygain status is true, replaygain is applied (if contents has a replaygain tag); /// otherwise, the replaygain is not affected by tag and properties. /// The player has already been disposed of. - /// The player is not in the valid state. + /// + /// The player is not in the valid state. + /// -or-
+ /// If audio offload is enabled by calling . (Since tizen 6.0) + ///
/// 5 public bool ReplayGain { get { ValidateNotDisposed(); + AudioOffload.CheckDisabled(); + NativePlayer.IsReplayGain(Handle, out var value). ThrowIfFailed(this, "Failed to get the replaygain of the player"); return value; @@ -554,6 +566,8 @@ namespace Tizen.Multimedia set { ValidateNotDisposed(); + AudioOffload.CheckDisabled(); + NativePlayer.SetReplayGain(Handle, value). ThrowIfFailed(this, "Failed to set the replaygain of the player"); } @@ -566,7 +580,11 @@ namespace Tizen.Multimedia /// The value indicating whether or not AudioPitch is enabled. The default is false. /// This function is used for audio content only. /// To set, the player must be in the state. - /// The player is not in the valid state. + /// + /// The player is not in the valid state. + /// -or-
+ /// If audio offload is enabled by calling . (Since tizen 6.0) + ///
/// The player has already been disposed of. /// /// 6 @@ -575,6 +593,8 @@ namespace Tizen.Multimedia get { ValidateNotDisposed(); + AudioOffload.CheckDisabled(); + NativePlayer.IsAudioPitchEnabled(Handle, out var value). ThrowIfFailed(this, "Failed to get whether the audio pitch is enabled or not"); return value; @@ -583,6 +603,7 @@ namespace Tizen.Multimedia set { ValidateNotDisposed(); + AudioOffload.CheckDisabled(); ValidatePlayerState(PlayerState.Idle); NativePlayer.SetAudioPitchEnabled(Handle, value). @@ -596,7 +617,11 @@ namespace Tizen.Multimedia /// The audio stream pitch value. The default is 1. /// Enabling pitch control could increase the CPU usage on some devices. /// This function is used for audio content only. - /// A pitch is not enabled. + /// + /// A pitch is not enabled. + /// -or-
+ /// If audio offload is enabled by calling . (Since tizen 6.0) + ///
/// The player has already been disposed of. /// /// value is less than 0.5. @@ -610,6 +635,7 @@ namespace Tizen.Multimedia get { ValidateNotDisposed(); + AudioOffload.CheckDisabled(); if (AudioPitchEnabled == false) { @@ -625,6 +651,7 @@ namespace Tizen.Multimedia set { ValidateNotDisposed(); + AudioOffload.CheckDisabled(); if (AudioPitchEnabled == false) { @@ -677,5 +704,24 @@ namespace Tizen.Multimedia return _adaptiveVariants; } } + + private AudioOffload _audioOffload; + + /// + /// Gets the setting for audio offload. + /// + /// 6 + public AudioOffload AudioOffload + { + get + { + if (_audioOffload == null) + { + _audioOffload = new AudioOffload(this); + } + + return _audioOffload; + } + } } } diff --git a/src/Tizen.Multimedia.MediaPlayer/Player/Player.cs b/src/Tizen.Multimedia.MediaPlayer/Player/Player.cs index ac1b78f64..5188fcb24 100644 --- a/src/Tizen.Multimedia.MediaPlayer/Player/Player.cs +++ b/src/Tizen.Multimedia.MediaPlayer/Player/Player.cs @@ -767,6 +767,8 @@ namespace Tizen.Multimedia /// The player is not in the valid state.
/// -or-
/// Streaming playback. + /// -or-
+ /// If audio offload is enabled by calling . (Since tizen 6.0) ///
/// /// is less than -5.0.
@@ -783,6 +785,7 @@ namespace Tizen.Multimedia throw new ArgumentOutOfRangeException(nameof(rate), rate, "Valid range is -5.0 to 5.0 (except 0.0)"); } + AudioOffload.CheckDisabled(); ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused); NativePlayer.SetPlaybackRate(Handle, rate).ThrowIfFailed(this, "Failed to set the playback rate."); @@ -975,14 +978,17 @@ namespace Tizen.Multimedia /// Operation failed; internal error. /// -or-
/// The player is not in the valid state. + /// -or-
+ /// If audio offload is enabled by calling . (Since tizen 6.0) ///
/// /// /// 6 public void EnableExportingAudioData(AudioMediaFormat format, PlayerAudioExtractOption option) { - ValidatePlayerState(PlayerState.Idle); ValidationUtil.ValidateEnum(typeof(PlayerAudioExtractOption), option, nameof(option)); + AudioOffload.CheckDisabled(); + ValidatePlayerState(PlayerState.Idle); _audioFrameDecodedCallback = (IntPtr packetHandle, IntPtr userData) => { diff --git a/src/Tizen.Multimedia.MediaPlayer/Player/PlayerFeatures.cs b/src/Tizen.Multimedia.MediaPlayer/Player/PlayerFeatures.cs index eeacff28b..dda3cc229 100644 --- a/src/Tizen.Multimedia.MediaPlayer/Player/PlayerFeatures.cs +++ b/src/Tizen.Multimedia.MediaPlayer/Player/PlayerFeatures.cs @@ -22,5 +22,6 @@ namespace Tizen.Multimedia internal const string RawVideo = "http://tizen.org/feature/multimedia.raw_video"; internal const string OpenGl = "http://tizen.org/feature/opengles.version.2_0"; internal const string SphericalVideo = "http://tizen.org/feature/multimedia.player.spherical_video"; + internal const string AudioOffload = "http://tizen.org/feature/multimedia.player.audio_offload"; } } diff --git a/src/Tizen.Multimedia.MediaPlayer/Player/PlayerTrackInfo.cs b/src/Tizen.Multimedia.MediaPlayer/Player/PlayerTrackInfo.cs index fa88af839..46947569c 100644 --- a/src/Tizen.Multimedia.MediaPlayer/Player/PlayerTrackInfo.cs +++ b/src/Tizen.Multimedia.MediaPlayer/Player/PlayerTrackInfo.cs @@ -48,10 +48,15 @@ namespace Tizen.Multimedia /// , or state. /// /// The that this instance belongs to has been disposed of. - /// The that this instance belongs to is not in the valid state. + /// The that this instance belongs to is not in the valid state. + /// -or-
+ /// If audio offload is enabled by calling . (Since tizen 6.0) + ///
/// 3 public int GetCount() { + _owner.ValidateNotDisposed(); + _owner.AudioOffload.CheckDisabled(); _owner.ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused); NativePlayer.GetTrackCount(_owner.Handle, _streamType, out var count). @@ -73,7 +78,10 @@ namespace Tizen.Multimedia /// The language codes are defined in ISO 639-1. /// /// The that this instance belongs to has been disposed of. - /// The that this instance belongs to is not in the valid state. + /// The that this instance belongs to is not in the valid state. + /// -or-
+ /// If audio offload is enabled by calling . (Since tizen 6.0) + ///
/// /// is less than zero.
/// -or-
@@ -82,7 +90,7 @@ namespace Tizen.Multimedia /// 3 public string GetLanguageCode(int index) { - _owner.ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused); + _owner.ValidateNotDisposed(); if (index < 0 || GetCount() <= index) { @@ -90,6 +98,9 @@ namespace Tizen.Multimedia $"Valid index range is 0 <= x < {nameof(GetCount)}(), but got { index }."); } + _owner.AudioOffload.CheckDisabled(); + _owner.ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused); + IntPtr code = IntPtr.Zero; try @@ -122,7 +133,11 @@ namespace Tizen.Multimedia /// , or state. /// /// The that this instance belongs to has been disposed of. - /// The that this instance belongs to is not in the valid state. + /// + /// The that this instance belongs to is not in the valid state.
+ /// -or-
+ /// If audio offload is enabled by calling . (Since tizen 6.0) + ///
/// /// is less than zero.
/// -or-
@@ -133,6 +148,8 @@ namespace Tizen.Multimedia { get { + _owner.ValidateNotDisposed(); + _owner.AudioOffload.CheckDisabled(); _owner.ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused); NativePlayer.GetCurrentTrack(_owner.Handle, _streamType, out var value). @@ -142,12 +159,15 @@ namespace Tizen.Multimedia } set { + _owner.ValidateNotDisposed(); + if (value < 0 || GetCount() <= value) { throw new ArgumentOutOfRangeException(nameof(value), value, $"Valid index range is 0 <= x < {nameof(GetCount)}(), but got { value }."); } + _owner.AudioOffload.CheckDisabled(); _owner.ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused); NativePlayer.SelectTrack(_owner.Handle, _streamType, value). -- 2.34.1