2 * Copyright (c) 2018 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.Threading.Tasks;
18 using System.Runtime.InteropServices;
19 using System.Diagnostics;
21 using System.Threading;
22 using NativeDisplay = Interop.Display;
25 namespace Tizen.Multimedia
28 /// Represents properties for streaming buffering time.
30 /// <since_tizen> 5 </since_tizen>
31 public struct PlayerBufferingTime
34 /// Initializes a new instance of the PlayerBufferingTime struct.
36 /// <param name="preBufferMillisecond">A duration of buffering data that must be prerolled to start playback.</param>
37 /// Except 0 and -1, setting at least 1000 milliseconds is recommended to ensure the normal buffering operation.
38 /// 0 : use platform default value which could be different depending on the streaming type and network status. (the initial value)
39 /// -1 : use current value. (since 5.5)
40 /// <param name="reBufferMillisecond">A duration of buffering data that must be prerolled to resume playback,
41 /// when player is internally paused for buffering.
42 /// Except 0 and -1, setting at least 1000 milliseconds is recommended to ensure the normal buffering operation.
43 /// 0 : use platform default value, which depends on the streaming type and network status. It is set as the initial value of this parameter.
44 /// If the player state is <see cref="PlayerState.Playing"/> or <see cref="PlayerState.Paused"/>,
45 /// this function will return correct time value instead of 0. (since 5.5)
46 /// -1 : use current value. (since 5.5)</param>
47 /// <since_tizen> 5 </since_tizen>
48 public PlayerBufferingTime(int preBufferMillisecond = -1, int reBufferMillisecond = -1)
50 PreBufferMillisecond = preBufferMillisecond;
51 ReBufferMillisecond = reBufferMillisecond;
55 /// Gets or sets the duration of buffering data that must be prerolled to start playback.
57 /// <since_tizen> 5 </since_tizen>
58 public int PreBufferMillisecond
65 /// Gets or sets the duration of buffering data that must be prerolled to resume playback
66 /// if player enters pause state for buffering.
68 /// <since_tizen> 5 </since_tizen>
69 public int ReBufferMillisecond
75 /// <since_tizen> 3 </since_tizen>
76 public partial class Player
79 /// Gets the native handle of the player.
81 /// <value>An IntPtr that contains the native handle of the player.</value>
82 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
83 /// <since_tizen> 3 </since_tizen>
88 ValidateNotDisposed();
89 return _handle.DangerousGetHandle();
93 #region Network configuration
94 private string _cookie = "";
95 private string _userAgent = "";
96 private const int MinBufferingTime = -1;
99 /// Gets or sets the cookie for streaming playback.
101 /// <remarks>To set, the player must be in the <see cref="PlayerState.Idle"/> state.</remarks>
102 /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
103 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
104 /// <exception cref="ArgumentNullException">The value to set is null.</exception>
105 /// <since_tizen> 3 </since_tizen>
114 ValidatePlayerState(PlayerState.Idle);
118 throw new ArgumentNullException(nameof(value), "Cookie can't be null.");
121 NativePlayer.SetStreamingCookie(Handle, value, value.Length).
122 ThrowIfFailed(this, "Failed to set the cookie to the player");
129 /// Gets or sets the user agent for streaming playback.
131 /// <remarks>To set, the player must be in the <see cref="PlayerState.Idle"/> state.</remarks>
132 /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
133 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
134 /// <exception cref="ArgumentNullException">The value to set is null.</exception>
135 /// <since_tizen> 3 </since_tizen>
136 public string UserAgent
144 ValidatePlayerState(PlayerState.Idle);
148 throw new ArgumentNullException(nameof(value), "UserAgent can't be null.");
151 NativePlayer.SetStreamingUserAgent(Handle, value, value.Length).
152 ThrowIfFailed(this, "Failed to set the user agent to the player");
159 /// Gets or sets the streaming buffering time.
161 /// <remarks>To set, the player must be in the <see cref="PlayerState.Idle"/> state.</remarks>
162 /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
163 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
164 /// <exception cref="ArgumentOutOfRangeException">
165 /// <pramref name="PreBufferMillisecond"/> is less than -1.<br/>
167 /// <pramref name="ReBufferMillisecond"/> is less than -1.<br/>
169 /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
170 /// <seealso cref="PlayerBufferingTime"/>
171 /// <since_tizen> 5 </since_tizen>
172 public PlayerBufferingTime BufferingTime
176 ValidateNotDisposed();
178 NativePlayer.GetStreamingBufferingTime(Handle, out var PreBuffMillisecond, out var ReBuffMillisecond).
179 ThrowIfFailed(this, "Failed to get the buffering time of the player");
181 return new PlayerBufferingTime(PreBuffMillisecond, ReBuffMillisecond);
185 ValidatePlayerState(PlayerState.Idle);
187 if (value.PreBufferMillisecond < MinBufferingTime || value.ReBufferMillisecond < MinBufferingTime)
189 throw new ArgumentOutOfRangeException(nameof(value), value,
190 $"invalid range, got { value.PreBufferMillisecond }, { value.ReBufferMillisecond }.");
193 NativePlayer.SetStreamingBufferingTime(Handle, value.PreBufferMillisecond, value.ReBufferMillisecond).
194 ThrowIfFailed(this, "Failed to set the buffering time of the player");
200 /// Gets the state of the player.
202 /// <value>The current state of the player.</value>
203 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
204 /// <since_tizen> 3 </since_tizen>
205 public PlayerState State
209 ValidateNotDisposed();
213 return PlayerState.Preparing;
216 NativePlayer.GetState(Handle, out var state).
217 ThrowIfFailed(this, "Failed to retrieve the state of the player");
219 Debug.Assert(Enum.IsDefined(typeof(PlayerState), state));
221 return (PlayerState)state;
226 /// Gets or sets the audio latency mode.
228 /// <value>A <see cref="AudioLatencyMode"/> that specifies the mode. The default is <see cref="AudioLatencyMode.Mid"/>.</value>
230 /// If the mode is <see cref="AudioLatencyMode.High"/>,
231 /// audio output interval can be increased, so it can keep more audio data to play.
232 /// But, state transition like pause or resume can be more slower than default(<see cref="AudioLatencyMode.Mid"/>).
234 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
235 /// <exception cref="ArgumentException">The value is not valid.</exception>
236 /// <exception cref="NotAvailableException">
237 /// If audio offload is enabled by calling <see cref="AudioOffload.IsEnabled"/>. (Since tizen 6.0)
239 /// <seealso cref="AudioOffload"/>
240 /// <since_tizen> 3 </since_tizen>
241 public AudioLatencyMode AudioLatencyMode
245 AudioOffload.CheckDisabled();
247 NativePlayer.GetAudioLatencyMode(Handle, out var value).
248 ThrowIfFailed(this, "Failed to get the audio latency mode of the player");
254 ValidateNotDisposed();
255 AudioOffload.CheckDisabled();
257 ValidationUtil.ValidateEnum(typeof(AudioLatencyMode), value, nameof(value));
259 NativePlayer.SetAudioLatencyMode(Handle, value).
260 ThrowIfFailed(this, "Failed to set the audio latency mode of the player");
265 /// Gets or sets the looping state.
267 /// <value>true if the playback is looping; otherwise, false. The default value is false.</value>
268 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
269 /// <since_tizen> 3 </since_tizen>
270 public bool IsLooping
274 NativePlayer.IsLooping(Handle, out var value).
275 ThrowIfFailed(this, "Failed to get the looping state of the player");
281 ValidateNotDisposed();
283 NativePlayer.SetLooping(Handle, value).
284 ThrowIfFailed(this, "Failed to set the looping state of the player");
288 #region Display methods
290 private PlayerDisplaySettings _displaySettings;
293 /// Gets the display settings.
295 /// <value>A <see cref="PlayerDisplaySettings"/> that specifies the display settings.</value>
296 /// <since_tizen> 3 </since_tizen>
297 public PlayerDisplaySettings DisplaySettings => _displaySettings;
299 private Display _display;
301 private bool _uiSync;
303 private PlayerErrorCode SetDisplay(Display display)
307 return NativeDisplay.SetDisplay(Handle, PlayerDisplayType.None, IntPtr.Zero);
310 return display.ApplyTo(this);
313 private void ReplaceDisplay(Display newDisplay)
315 _display?.SetOwner(null);
316 _display = newDisplay;
317 _display?.SetOwner(this);
321 /// Gets or sets the display.
323 /// <value>A <see cref="Multimedia.Display"/> that specifies the display.</value>
325 /// The player must be in the <see cref="PlayerState.Idle"/> state.<br/>
326 /// The raw video feature(http://tizen.org/feature/multimedia.raw_video) is required if
327 /// the display is created with <see cref="MediaView"/>.<br/>
328 /// If a user wants to use video and UI sync mode, please use <see cref="Tizen.Multimedia.Display(NUI.Window, bool)"/>.(Since tizen 6.5)<br/>
329 /// But <see cref="Tizen.Multimedia.Player.DisplaySettings"/> is not supported in UI sync mode.
331 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
332 /// <exception cref="ArgumentException">The value has already been assigned to another player.</exception>
333 /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
334 /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
335 /// <since_tizen> 3 </since_tizen>
336 public Display Display
344 ValidatePlayerState(PlayerState.Idle);
346 if (value != null && value.HasMediaView)
348 ValidationUtil.ValidateFeatureSupported(PlayerFeatures.RawVideo);
351 if (value?.Owner != null)
353 if (ReferenceEquals(this, value.Owner))
358 throw new ArgumentException("The display has already been assigned to another.");
361 _uiSync = value?.UiSync ?? false;
363 SetDisplay(value).ThrowIfFailed(this, "Failed to configure display of the player");
365 ReplaceDisplay(value);
369 PlayerErrorCode IDisplayable<PlayerErrorCode>.ApplyEvasDisplay(DisplayType type, ElmSharp.EvasObject evasObject)
371 Debug.Assert(IsDisposed == false);
373 Debug.Assert(Enum.IsDefined(typeof(DisplayType), type));
374 Debug.Assert(type != DisplayType.None);
376 return NativeDisplay.SetDisplay(Handle,
377 type == DisplayType.Overlay ? PlayerDisplayType.Overlay : PlayerDisplayType.Evas, evasObject);
380 PlayerErrorCode IDisplayable<PlayerErrorCode>.ApplyEcoreWindow(IntPtr windowHandle, Rectangle rect, Rotation rotation)
382 Debug.Assert(IsDisposed == false);
384 return NativeDisplay.SetEcoreDisplay(Handle,
385 _uiSync ? PlayerDisplayType.OverlayUISync : PlayerDisplayType.Overlay, windowHandle, rect.X, rect.Y,
386 rotation == Rotation.Rotate0 || rotation == Rotation.Rotate180 ? rect.Height : rect.Width,
387 rotation == Rotation.Rotate0 || rotation == Rotation.Rotate180 ? rect.Width : rect.Height);
391 private PlayerTrackInfo _audioTrack;
394 /// Gets the track info for the audio.
396 /// <value>A <see cref="PlayerTrackInfo"/> for audio.</value>
397 /// <since_tizen> 3 </since_tizen>
398 public PlayerTrackInfo AudioTrackInfo
402 if (_audioTrack == null)
404 _audioTrack = new PlayerTrackInfo(this, StreamType.Audio);
410 private PlayerTrackInfo _subtitleTrackInfo;
413 /// Gets the track info for the subtitle.
415 /// <value>A <see cref="PlayerTrackInfo"/> for the subtitle.</value>
416 /// <since_tizen> 3 </since_tizen>
417 public PlayerTrackInfo SubtitleTrackInfo
421 if (_subtitleTrackInfo == null)
423 _subtitleTrackInfo = new PlayerTrackInfo(this, StreamType.Text);
425 return _subtitleTrackInfo;
429 private StreamInfo _streamInfo;
432 /// Gets the stream information.
434 /// <value>A <see cref="StreamInfo"/> for this player.</value>
435 /// <since_tizen> 3 </since_tizen>
436 public StreamInfo StreamInfo
440 if (_streamInfo == null)
442 _streamInfo = new StreamInfo(this);
448 private AudioEffect _audioEffect;
451 /// Gets the audio effect.
453 /// <feature>http://tizen.org/feature/multimedia.custom_audio_effect</feature>
454 /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
455 /// <since_tizen> 3 </since_tizen>
456 public AudioEffect AudioEffect
460 if (_audioEffect == null)
462 throw new NotSupportedException($"The feature({PlayerFeatures.AudioEffect}) is not supported.");
470 /// Gets or sets the mute state.
472 /// <value>true if the player is muted; otherwise, false.</value>
473 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
474 /// <since_tizen> 3 </since_tizen>
479 NativePlayer.IsMuted(Handle, out var value).
480 ThrowIfFailed(this, "Failed to get the mute state of the player");
482 Log.Info(PlayerLog.Tag, "get mute : " + value);
488 NativePlayer.SetMute(Handle, value).ThrowIfFailed(this, "Failed to set the mute state of the player");
493 /// Gets or sets the current volume.
495 /// <remarks>Valid volume range is from 0 to 1.0, inclusive.</remarks>
496 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
497 /// <exception cref="ArgumentOutOfRangeException">
498 /// <paramref name="value"/> is less than zero.<br/>
500 /// <paramref name="value"/> is greater than 1.0.
502 /// <since_tizen> 3 </since_tizen>
508 NativePlayer.GetVolume(Handle, out value, out value).
509 ThrowIfFailed(this, "Failed to get the volume of the player");
515 if (value < 0F || 1.0F < value)
517 throw new ArgumentOutOfRangeException(nameof(value), value,
518 $"Valid volume range is 0 <= value <= 1.0, but got { value }.");
521 NativePlayer.SetVolume(Handle, value, value).
522 ThrowIfFailed(this, "Failed to set the volume of the player");
527 /// Gets or sets the audio-only state.
529 /// <value>true if the playback is audio-only mode; otherwise, false. The default value is false.</value>
530 /// The <see cref="Player"/> must be in the <see cref="PlayerState.Ready"/>,
531 /// <see cref="PlayerState.Playing"/>, or <see cref="PlayerState.Paused"/> state.
532 /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
533 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
534 /// <since_tizen> 5 </since_tizen>
535 public bool IsAudioOnly
539 ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
540 NativePlayer.IsAudioOnly(Handle, out var value).
541 ThrowIfFailed(this, "Failed to get the audio-only state of the player");
546 ValidateNotDisposed();
547 ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
548 NativePlayer.SetAudioOnly(Handle, value).
549 ThrowIfFailed(this, "Failed to set the audio-only state of the player");
554 /// Gets or sets the player's replaygain state.
556 /// <value>If the replaygain status is true, replaygain is applied (if contents has a replaygain tag);
557 /// otherwise, the replaygain is not affected by tag and properties.</value>
558 /// <remarks>This function could be unavailable depending on the audio codec type.</remarks>
559 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
560 /// <exception cref="InvalidOperationException">
561 /// The player is not in the valid state.
563 /// <exception cref="NotAvailableException">If audio offload is enabled by calling <see cref="AudioOffload.IsEnabled"/>. (Since tizen 6.0)
565 /// The function is not available depending on the audio codec type. (Since tizen 6.0)
567 /// <seealso cref="AudioOffload"/>
568 /// <seealso cref="AudioCodecType"/>
569 /// <since_tizen> 5 </since_tizen>
570 public bool ReplayGain
574 ValidateNotDisposed();
575 AudioOffload.CheckDisabled();
577 NativePlayer.IsReplayGain(Handle, out var value).
578 ThrowIfFailed(this, "Failed to get the replaygain of the player");
583 ValidateNotDisposed();
584 AudioOffload.CheckDisabled();
586 NativePlayer.SetReplayGain(Handle, value).
587 ThrowIfFailed(this, "Failed to set the replaygain of the player");
592 /// Enables or disables controlling the pitch of audio.
593 /// Gets the status of controlling the pitch of audio.
595 /// <value>The value indicating whether or not AudioPitch is enabled. The default is false.</value>
596 /// <remarks>This function is used for audio content only.
597 /// To set, the player must be in the <see cref="PlayerState.Idle"/> state.
598 /// This function could be unavailable depending on the audio codec type.</remarks>
599 /// <exception cref="InvalidOperationException">
600 /// The player is not in the valid state.
602 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
603 /// <exception cref="NotAvailableException">If audio offload is enabled by calling <see cref="AudioOffload.IsEnabled"/>. (Since tizen 6.0)
605 /// The function is not available depending on the audio codec type. (Since tizen 6.0)
607 /// <seealso cref="AudioPitch"/>
608 /// <seealso cref="AudioOffload"/>
609 /// <seealso cref="AudioCodecType"/>
610 /// <since_tizen> 6 </since_tizen>
611 public bool AudioPitchEnabled
615 ValidateNotDisposed();
616 AudioOffload.CheckDisabled();
618 NativePlayer.IsAudioPitchEnabled(Handle, out var value).
619 ThrowIfFailed(this, "Failed to get whether the audio pitch is enabled or not");
625 ValidateNotDisposed();
626 AudioOffload.CheckDisabled();
627 ValidatePlayerState(PlayerState.Idle);
629 NativePlayer.SetAudioPitchEnabled(Handle, value).
630 ThrowIfFailed(this, "Failed to enable the audio pitch of the player");
635 /// Gets or sets the pitch of audio.
637 /// <value>The audio stream pitch value. The default is 1.</value>
638 /// <remarks>Enabling pitch control could increase the CPU usage on some devices.
639 /// This function is used for audio content only.
640 /// This function could be unavailable depending on the audio codec type.</remarks>
641 /// <exception cref="InvalidOperationException">
642 /// A pitch is not enabled.
644 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
645 /// <exception cref="ArgumentOutOfRangeException">
646 /// value is less than 0.5.
648 /// value is greater than 2.0.
650 /// <exception cref="NotAvailableException">If audio offload is enabled by calling <see cref="AudioOffload.IsEnabled"/>. (Since tizen 6.0)
652 /// The function is not available depending on the audio codec type. (Since tizen 6.0)
654 /// <seealso cref="AudioPitchEnabled"/>
655 /// <seealso cref="AudioOffload"/>
656 /// <seealso cref="AudioCodecType"/>
657 /// <since_tizen> 6 </since_tizen>
658 public float AudioPitch
662 ValidateNotDisposed();
663 AudioOffload.CheckDisabled();
665 if (AudioPitchEnabled == false)
667 throw new InvalidOperationException("An audio pitch is not enabled.");
670 NativePlayer.GetAudioPitch(Handle, out var value).
671 ThrowIfFailed(this, "Failed to get the audio pitch");
678 ValidateNotDisposed();
679 AudioOffload.CheckDisabled();
681 if (AudioPitchEnabled == false)
683 throw new InvalidOperationException("An audio pitch is not enabled.");
686 if (value < 0.5F || 2.0F < value)
688 throw new ArgumentOutOfRangeException(nameof(value), value, "Valid value is 0.5 to 2.0");
691 NativePlayer.SetAudioPitch(Handle, value).ThrowIfFailed(this, "Failed to set the audio pitch");
696 /// Gets or sets the default codec type of the audio decoder.
698 /// <value>A <see cref="CodecType"/> specifies the type.
699 /// The default codec type could be different depending on the device capability.</value>
701 /// <para>To set, the player must be in the <see cref="PlayerState.Idle"/> state.</para>
702 /// <para>If H/W audio codec type is not supported in some cases, S/W audio codec type could be used instead.</para>
703 /// <para>The availability could be changed depending on the codec capability.
704 /// If an application wants to use the H/W audio codec type as default,
705 /// The following functions should be called after the codec type is set. :<br/>
706 /// <see cref="AudioEffect.IsAvailable"/><br/>
707 /// <see cref="EnableExportingAudioData"/><br/>
708 /// <see cref="DisableExportingAudioData"/><br/>
709 /// <see cref="ReplayGain"/><br/>
710 /// <see cref="AudioPitch"/><br/>
711 /// <see cref="AudioPitchEnabled"/><br/></para>
713 /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
714 /// <exception cref="ArgumentException">The value is not valid.</exception>
715 /// <exception cref="InvalidOperationException">
716 /// The player is not in the valid state.
718 /// Operation failed; internal error.
720 /// <exception cref="CodecNotSupportedException">The selected codec is not supported.</exception>
721 /// <since_tizen> 6 </since_tizen>
722 public CodecType AudioCodecType
726 ValidateNotDisposed();
728 NativePlayer.GetAudioCodecType(Handle, out var value).
729 ThrowIfFailed(this, "Failed to get the type of the audio codec");
735 ValidateNotDisposed();
736 ValidatePlayerState(PlayerState.Idle);
738 ValidationUtil.ValidateEnum(typeof(CodecType), value, nameof(value));
740 NativePlayer.SetAudioCodecType(Handle, value).
741 ThrowIfFailed(this, "Failed to set the type of the audio codec");
745 private SphericalVideo _sphericalVideo;
748 /// Gets the spherical video settings.
750 /// <since_tizen> 5 </since_tizen>
751 public SphericalVideo SphericalVideo
755 if (_sphericalVideo == null)
757 _sphericalVideo = new SphericalVideo(this);
760 return _sphericalVideo;
764 private AdaptiveVariants _adaptiveVariants;
767 /// Gets the adaptive variants settings.
769 /// <since_tizen> 5 </since_tizen>
770 public AdaptiveVariants AdaptiveVariants
774 if (_adaptiveVariants == null)
776 _adaptiveVariants = new AdaptiveVariants(this);
779 return _adaptiveVariants;
783 private AudioOffload _audioOffload;
786 /// Gets the setting for audio offload.
788 /// <since_tizen> 6 </since_tizen>
789 public AudioOffload AudioOffload
793 if (_audioOffload == null)
795 _audioOffload = new AudioOffload(this);
798 return _audioOffload;