/*
* Copyright (c) 2018 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.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using System.Threading;
using NativeDisplay = Interop.Display;
using static Interop;
namespace Tizen.Multimedia
{
///
/// Represents properties for streaming buffering time.
///
/// 5
public struct PlayerBufferingTime
{
///
/// Initializes a new instance of the PlayerBufferingTime struct.
///
/// A duration of buffering data that must be prerolled to start playback.
/// Except 0 and -1, setting at least 1000 milliseconds is recommended to ensure the normal buffering operation.
/// 0 : use platform default value which could be different depending on the streaming type and network status. (the initial value)
/// -1 : use current value. (since 5.5)
/// A duration of buffering data that must be prerolled to resume playback,
/// when player is internally paused for buffering.
/// Except 0 and -1, setting at least 1000 milliseconds is recommended to ensure the normal buffering operation.
/// 0 : use platform default value, which depends on the streaming type and network status. It is set as the initial value of this parameter.
/// If the player state is or ,
/// this function will return correct time value instead of 0. (since 5.5)
/// -1 : use current value. (since 5.5)
/// 5
public PlayerBufferingTime(int preBufferMillisecond = -1, int reBufferMillisecond = -1)
{
PreBufferMillisecond = preBufferMillisecond;
ReBufferMillisecond = reBufferMillisecond;
}
///
/// Gets or sets the duration of buffering data that must be prerolled to start playback.
///
/// 5
public int PreBufferMillisecond
{
get;
set;
}
///
/// Gets or sets the duration of buffering data that must be prerolled to resume playback
/// if player enters pause state for buffering.
///
/// 5
public int ReBufferMillisecond
{
get;
set;
}
}
/// 3
public partial class Player
{
///
/// Gets the native handle of the player.
///
/// An IntPtr that contains the native handle of the player.
/// The player has already been disposed of.
/// 3
public IntPtr Handle
{
get
{
ValidateNotDisposed();
return _handle.DangerousGetHandle();
}
}
#region Network configuration
private string _cookie = "";
private string _userAgent = "";
private const int MinBufferingTime = -1;
///
/// Gets or sets the cookie for streaming playback.
///
/// To set, the player must be in the state.
/// The player is not in the valid state.
/// The player has already been disposed of.
/// The value to set is null.
/// 3
public string Cookie
{
get
{
return _cookie;
}
set
{
ValidatePlayerState(PlayerState.Idle);
if (value == null)
{
throw new ArgumentNullException(nameof(value), "Cookie can't be null.");
}
NativePlayer.SetStreamingCookie(Handle, value, value.Length).
ThrowIfFailed(this, "Failed to set the cookie to the player");
_cookie = value;
}
}
///
/// Gets or sets the user agent for streaming playback.
///
/// To set, the player must be in the state.
/// The player is not in the valid state.
/// The player has already been disposed of.
/// The value to set is null.
/// 3
public string UserAgent
{
get
{
return _userAgent;
}
set
{
ValidatePlayerState(PlayerState.Idle);
if (value == null)
{
throw new ArgumentNullException(nameof(value), "UserAgent can't be null.");
}
NativePlayer.SetStreamingUserAgent(Handle, value, value.Length).
ThrowIfFailed(this, "Failed to set the user agent to the player");
_userAgent = value;
}
}
///
/// Gets or sets the streaming buffering time.
///
/// To set, the player must be in the state.
/// The player is not in the valid state.
/// The player has already been disposed of.
///
/// is less than -1.
/// -or-
/// is less than -1.
///
/// The required feature is not supported.
///
/// 5
public PlayerBufferingTime BufferingTime
{
get
{
ValidateNotDisposed();
NativePlayer.GetStreamingBufferingTime(Handle, out var PreBuffMillisecond, out var ReBuffMillisecond).
ThrowIfFailed(this, "Failed to get the buffering time of the player");
return new PlayerBufferingTime(PreBuffMillisecond, ReBuffMillisecond);
}
set
{
ValidatePlayerState(PlayerState.Idle);
if (value.PreBufferMillisecond < MinBufferingTime || value.ReBufferMillisecond < MinBufferingTime)
{
throw new ArgumentOutOfRangeException(nameof(value), value,
$"invalid range, got { value.PreBufferMillisecond }, { value.ReBufferMillisecond }.");
}
NativePlayer.SetStreamingBufferingTime(Handle, value.PreBufferMillisecond, value.ReBufferMillisecond).
ThrowIfFailed(this, "Failed to set the buffering time of the player");
}
}
#endregion
///
/// Gets the state of the player.
///
/// The current state of the player.
/// The player has already been disposed of.
/// 3
public PlayerState State
{
get
{
ValidateNotDisposed();
if (IsPreparing())
{
return PlayerState.Preparing;
}
NativePlayer.GetState(Handle, out var state).
ThrowIfFailed(this, "Failed to retrieve the state of the player");
Debug.Assert(Enum.IsDefined(typeof(PlayerState), state));
return (PlayerState)state;
}
}
///
/// Gets or sets the audio latency mode.
///
/// A that specifies the mode. The default is .
///
/// If the mode is ,
/// audio output interval can be increased, so it can keep more audio data to play.
/// But, state transition like pause or resume can be more slower than default().
///
/// The player has already been disposed of.
/// The value is not valid.
/// 3
public AudioLatencyMode AudioLatencyMode
{
get
{
NativePlayer.GetAudioLatencyMode(Handle, out var value).
ThrowIfFailed(this, "Failed to get the audio latency mode of the player");
return value;
}
set
{
ValidateNotDisposed();
ValidationUtil.ValidateEnum(typeof(AudioLatencyMode), value, nameof(value));
NativePlayer.SetAudioLatencyMode(Handle, value).
ThrowIfFailed(this, "Failed to set the audio latency mode of the player");
}
}
///
/// Gets or sets the looping state.
///
/// true if the playback is looping; otherwise, false. The default value is false.
/// The player has already been disposed of.
/// 3
public bool IsLooping
{
get
{
NativePlayer.IsLooping(Handle, out var value).
ThrowIfFailed(this, "Failed to get the looping state of the player");
return value;
}
set
{
ValidateNotDisposed();
NativePlayer.SetLooping(Handle, value).
ThrowIfFailed(this, "Failed to set the looping state of the player");
}
}
#region Display methods
private PlayerDisplaySettings _displaySettings;
///
/// Gets the display settings.
///
/// A that specifies the display settings.
/// 3
public PlayerDisplaySettings DisplaySettings => _displaySettings;
private Display _display;
private PlayerErrorCode SetDisplay(Display display)
{
if (display == null)
{
return NativeDisplay.SetDisplay(Handle, PlayerDisplayType.None, IntPtr.Zero);
}
return display.ApplyTo(this);
}
private void ReplaceDisplay(Display newDisplay)
{
_display?.SetOwner(null);
_display = newDisplay;
_display?.SetOwner(this);
}
///
/// Gets or sets the display.
///
/// A that specifies the display.
///
/// The player must be in the state.
/// The raw video feature(http://tizen.org/feature/multimedia.raw_video) is required if
/// the display is created with .
///
/// The player has already been disposed of.
/// The value has already been assigned to another player.
/// The player is not in the valid state.
/// The required feature is not supported.
/// 3
public Display Display
{
get
{
return _display;
}
set
{
ValidatePlayerState(PlayerState.Idle);
if (value != null && value.HasMediaView)
{
ValidationUtil.ValidateFeatureSupported(PlayerFeatures.RawVideo);
}
if (value?.Owner != null)
{
if (ReferenceEquals(this, value.Owner))
{
return;
}
throw new ArgumentException("The display has already been assigned to another.");
}
SetDisplay(value).ThrowIfFailed(this, "Failed to configure display of the player");
ReplaceDisplay(value);
}
}
PlayerErrorCode IDisplayable.ApplyEvasDisplay(DisplayType type, ElmSharp.EvasObject evasObject)
{
Debug.Assert(IsDisposed == false);
Debug.Assert(Enum.IsDefined(typeof(DisplayType), type));
Debug.Assert(type != DisplayType.None);
return NativeDisplay.SetDisplay(Handle,
type == DisplayType.Overlay ? PlayerDisplayType.Overlay : PlayerDisplayType.Evas, evasObject);
}
PlayerErrorCode IDisplayable.ApplyEcoreWindow(IntPtr windowHandle)
{
Debug.Assert(IsDisposed == false);
return NativeDisplay.SetEcoreDisplay(Handle, PlayerDisplayType.Overlay, windowHandle);
}
#endregion
private PlayerTrackInfo _audioTrack;
///
/// Gets the track info for the audio.
///
/// A for audio.
/// 3
public PlayerTrackInfo AudioTrackInfo
{
get
{
if (_audioTrack == null)
{
_audioTrack = new PlayerTrackInfo(this, StreamType.Audio);
}
return _audioTrack;
}
}
private PlayerTrackInfo _subtitleTrackInfo;
///
/// Gets the track info for the subtitle.
///
/// A for the subtitle.
/// 3
public PlayerTrackInfo SubtitleTrackInfo
{
get
{
if (_subtitleTrackInfo == null)
{
_subtitleTrackInfo = new PlayerTrackInfo(this, StreamType.Text);
}
return _subtitleTrackInfo;
}
}
private StreamInfo _streamInfo;
///
/// Gets the stream information.
///
/// A for this player.
/// 3
public StreamInfo StreamInfo
{
get
{
if (_streamInfo == null)
{
_streamInfo = new StreamInfo(this);
}
return _streamInfo;
}
}
private AudioEffect _audioEffect;
///
/// Gets the audio effect.
///
/// http://tizen.org/feature/multimedia.custom_audio_effect
/// The required feature is not supported.
/// 3
public AudioEffect AudioEffect
{
get
{
if (_audioEffect == null)
{
throw new NotSupportedException($"The feature({PlayerFeatures.AudioEffect}) is not supported.");
}
return _audioEffect;
}
}
///
/// Gets or sets the mute state.
///
/// true if the player is muted; otherwise, false.
/// The player has already been disposed of.
/// 3
public bool Muted
{
get
{
NativePlayer.IsMuted(Handle, out var value).
ThrowIfFailed(this, "Failed to get the mute state of the player");
Log.Info(PlayerLog.Tag, "get mute : " + value);
return value;
}
set
{
NativePlayer.SetMute(Handle, value).ThrowIfFailed(this, "Failed to set the mute state of the player");
}
}
///
/// Gets or sets the current volume.
///
/// Valid volume range is from 0 to 1.0, inclusive.
/// The player has already been disposed of.
///
/// is less than zero.
/// -or-
/// is greater than 1.0.
///
/// 3
public float Volume
{
get
{
float value = 0.0F;
NativePlayer.GetVolume(Handle, out value, out value).
ThrowIfFailed(this, "Failed to get the volume of the player");
return value;
}
set
{
if (value < 0F || 1.0F < value)
{
throw new ArgumentOutOfRangeException(nameof(value), value,
$"Valid volume range is 0 <= value <= 1.0, but got { value }.");
}
NativePlayer.SetVolume(Handle, value, value).
ThrowIfFailed(this, "Failed to set the volume of the player");
}
}
///
/// Gets or sets the audio-only state.
///
/// true if the playback is audio-only mode; otherwise, false. The default value is false.
/// The must be in the ,
/// , or state.
/// The player is not in the valid state.
/// The player has already been disposed of.
/// 5
public bool IsAudioOnly
{
get
{
ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
NativePlayer.IsAudioOnly(Handle, out var value).
ThrowIfFailed(this, "Failed to get the audio-only state of the player");
return value;
}
set
{
ValidateNotDisposed();
ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
NativePlayer.SetAudioOnly(Handle, value).
ThrowIfFailed(this, "Failed to set the audio-only state of the player");
}
}
///
/// Gets or sets the player's replaygain state.
///
/// 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.
/// 5
public bool ReplayGain
{
get
{
ValidateNotDisposed();
NativePlayer.IsReplayGain(Handle, out var value).
ThrowIfFailed(this, "Failed to get the replaygain of the player");
return value;
}
set
{
ValidateNotDisposed();
NativePlayer.SetReplayGain(Handle, value).
ThrowIfFailed(this, "Failed to set the replaygain of the player");
}
}
///
/// Gets or sets the audio pitch.
///
/// 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 has already been disposed of.
///
/// 6
public bool AudioPitchEnabled
{
get
{
ValidateNotDisposed();
NativePlayer.IsAudioPitchEnabled(Handle, out var value).
ThrowIfFailed(this, "Failed to get whether the audio pitch is enabled or not");
return value;
}
set
{
ValidateNotDisposed();
ValidatePlayerState(PlayerState.Idle);
NativePlayer.SetAudioPitchEnabled(Handle, value).
ThrowIfFailed(this, "Failed to enable the audio pitch of the player");
}
}
///
/// Gets or sets the audio pitch value.
///
/// 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.
/// The player has already been disposed of.
///
/// value is less than 0.5.
/// -or-
/// value is greater than 2.0.
///
///
/// 6
public float AudioPitch
{
get
{
ValidateNotDisposed();
if (AudioPitchEnabled == false)
{
throw new InvalidOperationException("An audio pitch is not enabled.");
}
NativePlayer.GetAudioPitch(Handle, out var value).
ThrowIfFailed(this, "Failed to get the audio pitch");
return value;
}
set
{
ValidateNotDisposed();
if (AudioPitchEnabled == false)
{
throw new InvalidOperationException("An audio pitch is not enabled.");
}
if (value < 0.5F || 2.0F < value)
{
throw new ArgumentOutOfRangeException(nameof(value), value, "Valid value is 0.5 to 2.0");
}
NativePlayer.SetAudioPitch(Handle, value).ThrowIfFailed(this, "Failed to set the audio pitch");
}
}
private SphericalVideo _sphericalVideo;
///
/// Gets the spherical video settings.
///
/// 5
public SphericalVideo SphericalVideo
{
get
{
if (_sphericalVideo == null)
{
_sphericalVideo = new SphericalVideo(this);
}
return _sphericalVideo;
}
}
private AdaptiveVariants _adaptiveVariants;
///
/// Gets the adaptive variants settings.
///
/// 5
public AdaptiveVariants AdaptiveVariants
{
get
{
if (_adaptiveVariants == null)
{
_adaptiveVariants = new AdaptiveVariants(this);
}
return _adaptiveVariants;
}
}
}
}