WindowsAppSDK icon indicating copy to clipboard operation
WindowsAppSDK copied to clipboard

Windows.Media.Playback.MediaPlayer Seeking jumps forward 9 seconds on certain files.

Open EpsiRho opened this issue 6 months ago • 1 comments

Describe the bug

I have a slider bound to an object that updates it as the position of a MediaPlayer changes, and allows it to update the position by dragging along the slider. This works for most songs, but sone of the songs I have will jump forward about 9 seconds from where I click on the slider, or where I set the position programatically. This also only happens once playing. For example, if I pause the playback, then set the time it seems to set properly, but when I start playback again it jumps forward 9 seconds. This is using

  • Microsoft.UI.XAML 2.8.6
  • Microsoft.Windows.SDK.BuildTools 10.0.26100.1
  • Microsoft.WindowsAppSDK 1.5.240627000

The app is being tested unpackaged.

Steps to reproduce the bug

Demo Code adapted from the larger project where I'm experiencing this issue. Note that this code works fine with most files I've tried. If asked I can provide a few of the files that cause the issue for me (one example is the flac file for Hollowheart - Porter Robinson): MainWindow.cs

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();

        InitMediaPlayer();
    }
    public async static void InitMediaPlayer()
    {
        // Setup MediaPlayer/MediaPlaybackList
        StateManager.NowPlayingMediaPlayer = new MediaPlayer();
        StateManager.NowPlayingMediaPlayer.Volume = 0.02;
        StateManager.PlaybackList = new MediaPlaybackList();
        StateManager.PlaybackList.MaxPlayedItemsToKeepOpen = 5;
        StateManager.PlaybackList.AutoRepeatEnabled = false;
        StateManager.NowPlayingMediaPlayer.Source = StateManager.PlaybackList;
        StateManager.NowPlayingMediaPlayer.AutoPlay = true;

        // Get track
        var trackStream = File.OpenRead($"<Music File Path Here>");
        var memoryStream = new MemoryStream();
        await trackStream.CopyToAsync(memoryStream);
        memoryStream.Seek(0, SeekOrigin.Begin);
        var mSource = MediaSource.CreateFromStream(memoryStream.AsRandomAccessStream(), "flac");
        var playbackItem = new MediaPlaybackItem(mSource);
        if (playbackItem == null)
        {
            return;
        }

        // Set track
        StateManager.PlaybackList.Items.Clear();
        StateManager.PlaybackList.Items.Add(playbackItem);
        StateManager.NowPlayingMediaPlayer.Play();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        InitMediaPlayer();
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        StateManager.NowPlayingMediaPlayer.Position = TimeSpan.FromSeconds(20);
    }
}

MainWindow.xaml

<Window
    x:Class="mediaplayer.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:mediaplayer"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
        <Grid.Resources>
            <local:DoubleDurationToTime x:Key="DoubleDurationToTime"/>
        </Grid.Resources>
        <Button Click="Button_Click"
                HorizontalAlignment="Center"
                Margin="0,0,0,400">Restart</Button>
        <Button Click="Button_Click_1"
                HorizontalAlignment="Center"
                Margin="0,0,0,700">Set 20 Seconds</Button>
        <TextBlock Grid.Column="3"
                   Text="{x:Bind local:StateManager.PlaybackInfo.PositionStr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                   Grid.Row="1"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Top"
                   Margin="10,18,0,0"/>
            <TextBlock Grid.Column="3"
                       Text="{x:Bind local:StateManager.PlaybackInfo.DurationStr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                       Grid.Row="1"
                       VerticalAlignment="Top"
                       HorizontalAlignment="Right"
                       Margin="0,18,20,0"/>
        <Slider x:Name="TrackProgress"
                Height="30"
                ThumbToolTipValueConverter="{StaticResource DoubleDurationToTime}"
                Value="{x:Bind local:StateManager.PlaybackInfo.Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                Maximum="{x:Bind local:StateManager.PlaybackInfo.Duration, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                Grid.Column="3"
                Grid.Row="1"
                Margin="9,0,20,10"/>
    </Grid>
</Window>

PlaybackObservables.cs

public class PlaybackObserables : INotifyPropertyChanged
{
    private double _position;
    private double _duration;
    private readonly DispatcherTimer timer;

    public double Position
    {
        get => _position;
        set
        {
            if (_position != value)
            {
                _position = value;
                StateManager.NowPlayingMediaPlayer.PlaybackSession.Position = TimeSpan.FromMilliseconds(value);
                OnPropertyChanged();
                OnPropertyChanged("PositionStr");
            }
        }
    }

    public string PositionStr
    {
        get
        {
            try
            {
                var str = TimeSpan.FromMilliseconds(_position).ToString(@"hh\:mm\:ss");
                return str;
            }
            catch (Exception)
            {
                return "Ukwn";
            }
        }
        set
        {

        }
    }
    public string DurationStr
    {
        get
        {
            try
            {
                var str = TimeSpan.FromMilliseconds(_duration).ToString(@"hh\:mm\:ss");
                return str;
            }
            catch (Exception)
            {
                return "Ukwn";
            }
        }
        set
        {

        }
    }

    public double Duration
    {
        get => _duration;
        set
        {
            if (_duration != value)
            {
                _duration = value;
                OnPropertyChanged();
                OnPropertyChanged("DurationStr");
            }
        }
    }

    public PlaybackObserables()
    {
        Position = 0;
        Duration = 100;
        timer = new DispatcherTimer
        {
            Interval = TimeSpan.FromMilliseconds(100) 
        };
        timer.Tick += Timer_Tick;
        timer.Start();
    }

    private void Timer_Tick(object sender, object e)
    {
        try
        {
            if (_position != StateManager.NowPlayingMediaPlayer.PlaybackSession.Position.TotalMilliseconds)
            {
                Debug.WriteLine($"{StateManager.NowPlayingMediaPlayer.PlaybackSession.Position.TotalMilliseconds}");
                _position = StateManager.NowPlayingMediaPlayer.PlaybackSession.Position.TotalMilliseconds;
                //PlaybackManager.NowPlayingMediaPlayer.PlaybackSession.Position = TimeSpan.FromSeconds(10);
                OnPropertyChanged("Position");
                OnPropertyChanged("PositionStr");
            }
            if (_duration != StateManager.NowPlayingMediaPlayer.PlaybackSession.NaturalDuration.TotalMilliseconds)
            {
                _duration = StateManager.NowPlayingMediaPlayer.PlaybackSession.NaturalDuration.TotalMilliseconds;
                OnPropertyChanged("Duration");
                OnPropertyChanged("DurationStr");
            }
        }
        catch (Exception)
        {

        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

StateManager.cs

internal class StateManager
{
    public static PlaybackObserables PlaybackInfo = new PlaybackObserables() { Duration = 100, Position = 0 };
    public static MediaPlayer NowPlayingMediaPlayer { get; set; }
    public static MediaStreamSource StreamSource;
    public static MediaPlaybackList PlaybackList;
}

DoubleDurationToTime.cs

public class DoubleDurationToTime : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        double duration = (double)value;
        if (duration == null)
        {
            return "00:00:00";
        }

        try
        {
            var str = TimeSpan.FromMilliseconds(duration).ToString(@"hh\:mm\:ss");
            return str;
        }
        catch (Exception)
        {
            return "Ukwn";
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

Expected behavior

Song should not jump forward 9 seconds after being set to a set time. The expected behavior does happen, just inconsistently between files.

Screenshots

BugDemo

NuGet package version

Windows App SDK 1.5.5: 1.5.240627000

Packaging type

Unpackaged

Windows version

Insider Build (xxxxx)

IDE

Visual Studio 2022

Additional context

No response

EpsiRho avatar Aug 13 '24 14:08 EpsiRho