Skip to content

Instantly share code, notes, and snippets.

@pictos
Created August 13, 2021 00:07
Show Gist options
  • Save pictos/49e11ea4546d3bb351b50f9b182be23d to your computer and use it in GitHub Desktop.
Save pictos/49e11ea4546d3bb351b50f9b182be23d to your computer and use it in GitHub Desktop.
VLCService
using LibVLCSharp.Shared;
using static MediaPlayerX.Helpers.GlobalResources;
using MediaPlayerX.Models;
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
using MediaPlayerX.Helpers;
using System.Collections.ObjectModel;
#nullable enable
namespace MediaPlayerX.Services
{
public sealed class MediaPlayerService
{
static readonly Lazy<MediaPlayerService> mediaPlayerService =
new Lazy<MediaPlayerService>(() => new MediaPlayerService());
public static MediaPlayerService Current => mediaPlayerService.Value;
readonly LibVLC libVLC;
readonly MediaPlayer mp;
public MediaFile CurrentMedia { get; private set; }
public ObservableRangeCollection<MediaFile> MediaFiles { get; } = new ObservableRangeCollection<MediaFile>();
public bool IsPlaying => mp.IsPlaying;
MediaPlayerService()
{
Core.Initialize();
libVLC = new LibVLC();
random = new Random();
mp = new MediaPlayer(libVLC);
}
public Action<TimeSpan>? OnTimeChanged { get; set; }
public Action? OnMediaChanged { get; set; }
public Action<float>? OnPositionChanged { get; set; }
public Action? OnFinished { get; set; }
public Action<TimeSpan>? OnMediaInfo { get; set; }
public Action<bool>? OnIsPlayingChanged { get; set; }
//TODO improve this
public string TotalDuration => TimeSpan.FromMilliseconds(mp.Media?.Duration ?? 0).ToStringTime();
public bool IsRandomMode { get; set; }
public bool IsRepeateMode { get; set; }
bool isInit;
readonly Random random;
void Init()
{
// Utils.WhatThreadAmI();
if (!isInit)
{
isInit = true;
mp.TimeChanged += TimeChanged;
mp.PositionChanged += PositionChanged;
mp.LengthChanged += LengthChanged;
mp.EndReached += EndReached;
mp.Playing += Playing;
mp.Paused += Paused;
mp.MediaChanged += OnMpMediaChanged;
}
}
public void SetSong(ref MediaFile media)
{
// Utils.WhatThreadAmI();
if (!(mp.Media is null))
Stop();
mp.Media = new Media(libVLC, media.Path, GetType(media.IsLocal));
mp.Media.AddOption(":no-video");
mp.Play();
CurrentMedia = media;
if (media.IsLocal && MediaFiles.Count == 0)
MediaFiles.AddRange(LocalMedias);
else if (!media.IsLocal && MediaFiles.Count == 0)
MediaFiles.Add(CurrentMedia);
Init();
DependencyService.Get<INotification>().ShowNotification();
static FromType GetType(bool isLocal)
{
if (isLocal)
return FromType.FromPath;
else
return FromType.FromLocation;
}
}
public void Play()
{
if (!IsPlaying)
mp.Play();
else
mp.Pause();
}
public void Forward(long offSet) =>
mp.Time += offSet;
public void Rewind(long offSet) =>
mp.Time -= offSet;
public void SetMediaTime(long time) =>
mp.Time = time;
void Paused(object sender, EventArgs e) =>
Task.Run(() => OnIsPlayingChanged?.Invoke(false));
void Playing(object sender, EventArgs e) =>
Task.Run(() => OnIsPlayingChanged?.Invoke(true));
void EndReached(object sender, EventArgs e) =>
Task.Run(() =>
{
OnFinished?.Invoke();
NextMusic();
});
void LengthChanged(object sender, MediaPlayerLengthChangedEventArgs e) =>
Task.Run(() =>
{
if (e.Length > 0)
{
var duration = TimeSpan.FromMilliseconds(e.Length);
OnMediaInfo?.Invoke(duration);
mp.LengthChanged -= LengthChanged;
CurrentMedia = new MediaFile(CurrentMedia.Title, CurrentMedia.Path, duration, CurrentMedia.ArtUrl, CurrentMedia.IsLocal);
}
});
void PositionChanged(object sender, MediaPlayerPositionChangedEventArgs e) =>
Task.Run(() => OnPositionChanged?.Invoke(e.Position));
void TimeChanged(object sender, MediaPlayerTimeChangedEventArgs e) =>
Task.Run(() => OnTimeChanged?.Invoke(TimeSpan.FromMilliseconds(e.Time)));
void OnMpMediaChanged(object sender, MediaPlayerMediaChangedEventArgs e) =>
Task.Run(() =>
{
mp.LengthChanged -= LengthChanged;
mp.LengthChanged += LengthChanged;
OnMediaChanged?.Invoke();
});
public void Stop()
{
//TODO Refactore this to the Dispose method
//mp.TimeChanged -= TimeChanged;
//mp.PositionChanged -= PositionChanged;
//mp.LengthChanged -= LengthChanged;
//mp.EndReached -= EndReached;
//mp.Playing -= Playing;
//mp.Paused -= Paused;
//mp.MediaChanged -= OnMpMediaChanged;
//isInit = false;
mp.Stop();
mp.Media?.Dispose();
mp.Media = null;
}
public void NextMusic()
{
if (CurrentMedia == default)
return;
var index = MediaFiles.IndexOf(CurrentMedia);
index = index == -1 ? 0 : index;
if (!IsRepeateMode)
index = IsRandomMode
? random.Next(0, MediaFiles.Count - 1)
: ++index;
if (index > MediaFiles.Count)
index = MediaFiles.Count;
SetCurrentMusic(ref index);
}
MediaFile SetCurrentMusic(ref int index)
{
var totalMedia = MediaFiles.Count;
if (totalMedia == 0)
return CurrentMedia;
if (index < 0)
index = totalMedia - 1;
index %= totalMedia;
var music = MediaFiles[index];
SetSong(ref music);
return music;
}
public MediaFile PreviousMusic()
{
if (CurrentMedia == default)
return default;
var index = MediaFiles.IndexOf(CurrentMedia);
index--;
return SetCurrentMusic(ref index);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment