Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
EpsiRho opened this issue Aug 13, 2024 · 1 comment
Labels
area-External area-Media Support for media playback or encoding

Comments

@EpsiRho
Copy link

EpsiRho commented Aug 13, 2024

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

@codendone codendone added area-Media Support for media playback or encoding area-External and removed needs-triage labels Sep 13, 2024
@patnels
Copy link

patnels commented Sep 16, 2024

Sometimes this happens when the file has a bad index, or no index at all. We end up making a 'best guess' of translating seek position in 'time' to seek position in bytes.

If you can provide a 'Simple' trace, we can investigate to determine the issue. https://github.com/microsoft/media-foundation/blob/master/tracing/tracing.md

Please note that the tool will collect some data about file paths and machine configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-External area-Media Support for media playback or encoding
Projects
None yet
Development

No branches or pull requests

3 participants