我正在尝试为基于媒体的应用程序实现锁屏音频控件。
我发现了许多尝试完成相同任务的人,但是我使用插件SimpleAudioPlayer https://github.com/adrianstevens/Xamarin-Plugins/tree/master/SimpleAudioPlayer时,大多数人都在使用Xamarin的MediaPlayer。
当前,我正在尝试遵循本文档,并查看是否可以将其连接到我当前正在使用的插件https://devblogs.microsoft.com/xamarin/lock-screen-music-controls-in-xamarin.android/
有人对如何进行连接有任何建议吗? Xamarin.Forms,Android项目。
当我第一次尝试关注该博客时,我将他们的RemoteControlBroadcastReceiver类信息与共享项目DABPlayer.cs一起放入,但找不到找到方法
StreamingBackgroundService.ActionTogglePlayback; break;
case Keycode.MediaPlay: action = StreamingBackgroundService.ActionPlay; break;
case Keycode.MediaPause: action = StreamingBackgroundService.ActionPause; break;
上班。具体找到可能是我的StreamingBackgroundService。然后,我尝试制作一个单独的StreamingBackgroundService,但他们使用的是MediaPlayer,而我正开始迷失在使我的SimpleAudioPlayer可以使用此代码的方式上。
如果有人对此有任何建议或更好的方法,将不胜感激。如果您需要更多或更少的信息,请告诉我。谢谢。
这是我共享的项目媒体播放器类的大致外观
public class DabPlayerEventArgs : EventArgs
{
public string ChannelTitle;
public string EpisodeTitle;
public double Duration;
public double CurrentPosition;
public DabPlayerEventArgs(DabPlayer player)
{
//Init the object with known values
ChannelTitle = player.ChannelTitle;
EpisodeTitle = player.EpisodeTitle;
Duration = player.Duration;
CurrentPosition = player.CurrentPosition;
}
}
//Class that extends the basic player used by the apps.
public class DabPlayer : ISimpleAudioPlayer, INotifyPropertyChanged
{
private IDabNativePlayer nativePlayer;
private ISimpleAudioPlayer player;
private string _channelTitle = "";
private string _episodeTitle = "";
private double _episodeDuration = 1; //Estimated duration of the episode
private Timer timer = new Timer(500);
private double LastPosition = 0;
//Constructor
public DabPlayer(ISimpleAudioPlayer Player, bool IntegrateWithLockScreen)
{
player = Player; //store reference to the player
//Set up events tied to the player
player.PlaybackEnded += Player_PlaybackEnded;
//Connect the native player interface
nativePlayer = DependencyService.Get<IDabNativePlayer>();
nativePlayer.Init(this, IntegrateWithLockScreen);
//Set up the timer for tracking progress
timer.Elapsed += OnTimerFired;
timer.Enabled = true;
timer.AutoReset = true;
timer.Stop(); //Don't use it till we need it.
}
/* Event Handlers */
public event EventHandler EpisodeDataChanged;
protected virtual void OnEpisodeDataChanged(object sender, DabPlayerEventArgs e)
{
EventHandler handler = EpisodeDataChanged;
handler?.Invoke(this, new DabPlayerEventArgs(this));
}
public event EventHandler EpisodeProgressChanged;
protected virtual void OnEpisodeProgressChanged(object sender, DabPlayerEventArgs e)
{
EventHandler handler = EpisodeProgressChanged;
handler?.Invoke(this, new DabPlayerEventArgs(this));
}
void Player_PlaybackEnded(object sender, EventArgs e)
{
//Handle playback ending (update button image)
OnPropertyChanged("PlayPauseButtonImageBig");
}
public ISimpleAudioPlayer SimpleAudioPlayer
{
get
{
return player;
}
}
/********************************
ISimpleAudioPlayer Implementation
********************************/
public double Duration
{
get
{
//Return the duration of the player, ensuring it's >0
if (player.Duration <= 0)
{
//TODO: Use the episodes total length if possible
return _episodeDuration;
}
else
{
return player.Duration;
}
}
}
//Current position of the player
public double CurrentPosition
{
get
{
return player.CurrentPosition;
}
}
//Remaining time for the player
public double RemainingSeconds
{
get
{
return player.Duration - CurrentPosition;
}
}
//Current position of the player as a percentage
public double CurrentProgressPercentage
{
get
{
if (Duration > 0)
{
return CurrentPosition / Duration;
}
else
{
return 0;
}
}
}
public double Volume
{
get
{
return player.Volume;
}
set
{
player.Volume = value;
OnPropertyChanged("Volume");
}
}
public double Balance
{
get
{
return player.Balance;
}
set
{
player.Balance = value;
OnPropertyChanged("Balance");
}
}
public bool IsPlaying => player.IsPlaying;
public bool Loop
{
get
{
return player.Loop;
}
set
{
player.Loop = value;
OnPropertyChanged("Loop");
}
}
public bool CanSeek => player.CanSeek;
public event EventHandler PlaybackEnded
{
add
{
player.PlaybackEnded += value;
}
remove
{
player.PlaybackEnded -= value;
}
}
public void Dispose()
{
player.Dispose();
}
public bool Load(Stream audioStream)
{
//Load a stream
bool rv = player.Load(audioStream);
OnPropertyChanged("Duration");
OnPropertyChanged("IsReady");
return rv;
}
public bool Load(string fileName)
{
//Load file, determine local or remote first
//If remote, use a stream.
bool rv;
if (fileName.ToLower().StartsWith("http", StringComparison.Ordinal))
{
//Remote file
WebClient wc = new WebClient();
Stream fileStream = wc.OpenRead(fileName);
rv = Load(fileStream);
}
else
{
//Local file
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
rv = Load(fs);
}
return rv;
}
public bool Load(dbEpisodes episode)
{
try
{
//Stop playing the current episode if needed
if (IsPlaying)
{
Pause(); //Have to use PAUSE on Android or it will reset current time to 0.
//Stop();
}
//Load a specific episode (sets text properties as well
EpisodeTitle = episode.title;
ChannelTitle = episode.channel_title;
OnEpisodeDataChanged(this, new DabPlayerEventArgs(this));
return Load(episode.File_name);
}
catch (Exception ex)
{
return false;
}
}
public void Pause()
{
player.Pause();
timer.Stop();
OnPropertyChanged("PlayPauseButtonImageBig");
UpdateEpisodeDataOnStop(); //Episode has been stopped
}
public void Play()
{
if (IsPlaying)
{
//Stop the current episode properly if needed.
Stop();
}
player.Play();
timer.Start();
OnPropertyChanged("PlayPauseButtonImageBig");
}
public void Seek(double position)
{
player.Seek(position);
OnPropertyChanged("CurrentPosition");
OnPropertyChanged("RemainingSeconds");
OnPropertyChanged("CurrentProgressPercentage");
}
public void Stop()
{
player.Stop();
timer.Stop();
OnPropertyChanged("PlayPauseButtonImageBig");
UpdateEpisodeDataOnStop(); //episode has stopped
}
我的Android本机播放器类如下
public class DroidDabNativePlayer : BroadcastReceiver, IDabNativePlayer
{
DabPlayer player;
public string ComponentName { get { return this.Class.Name; } }
public DroidDabNativePlayer(ISimpleAudioPlayer Player, bool IntegrateWithLockScreen)
{
}
public void Init(DabPlayer Player, bool IntegrateWithLockScreen)
{
player = Player;
if (IntegrateWithLockScreen)
{
/* SET UP LOCK SCREEN */
//TODO: Set up lock screen
}
}
}
在将项目移交给我之前,已经设置了iOS锁屏控件,我可以在下面发布该代码,以查看它是否有用。
public class iosDabNativePlayer : IDabNativePlayer
{
DabPlayer player;
MPNowPlayingInfo nowPlayingInfo;
public void Init(DabPlayer Player, bool IntegrateWithLockScreen)
{
player = Player;
AVAudioSession.SharedInstance().SetActive(true);
AVAudioSession.SharedInstance().SetCategory(AVAudioSessionCategory.Playback);
/* SET UP LOCK SCREEN COMPONENTS (if needed) */
if (IntegrateWithLockScreen)
{
//Remote Control (Lock Screen)
UIApplication.SharedApplication.BeginReceivingRemoteControlEvents();
nowPlayingInfo = new MPNowPlayingInfo();
nowPlayingInfo.Artist = "Daily Audio Bible";
player.EpisodeDataChanged += (sender, e) =>
{
//Update the lock screen with new playing info
DabPlayerEventArgs args = (DabPlayerEventArgs)e;
nowPlayingInfo.Title = args.EpisodeTitle;
nowPlayingInfo.AlbumTitle = args.ChannelTitle;
nowPlayingInfo.Artist = "Daily Audio Bible";
nowPlayingInfo.PlaybackDuration = args.Duration;
nowPlayingInfo.ElapsedPlaybackTime = args.CurrentPosition;
MPNowPlayingInfoCenter.DefaultCenter.NowPlaying = nowPlayingInfo;
};
player.EpisodeProgressChanged += (object sender, EventArgs e) =>
{
//Update lock screen with nee position info
DabPlayerEventArgs args = (DabPlayerEventArgs)e;
nowPlayingInfo.Title = args.EpisodeTitle;
nowPlayingInfo.AlbumTitle = args.ChannelTitle;
nowPlayingInfo.Artist = "Daily Audio Bible";
nowPlayingInfo.PlaybackDuration = args.Duration;
nowPlayingInfo.ElapsedPlaybackTime = args.CurrentPosition;
MPNowPlayingInfoCenter.DefaultCenter.NowPlaying = nowPlayingInfo;
};
/* Lock Screen Events */
//Handle play event from lock screen
MPRemoteCommandCenter.Shared.PlayCommand.AddTarget((arg) =>
{
try
{
GlobalResources.playerPodcast.Play();
return MPRemoteCommandHandlerStatus.Success;
}
catch (Exception ex)
{
return MPRemoteCommandHandlerStatus.CommandFailed;
}
});
//Handle pause event from lock scren
MPRemoteCommandCenter.Shared.PauseCommand.AddTarget((arg) =>
{
try
{
GlobalResources.playerPodcast.Pause();
return MPRemoteCommandHandlerStatus.Success;
}
catch (Exception ex)
{
return MPRemoteCommandHandlerStatus.CommandFailed;
}
});
//Handle skip forward command from lock screen
MPRemoteCommandCenter.Shared.SkipForwardCommand.AddTarget((arg) =>
{
try
{
GlobalResources.playerPodcast.Skip(15); //icon says 15 seconds
return MPRemoteCommandHandlerStatus.Success;
}
catch (Exception ex)
{
return MPRemoteCommandHandlerStatus.CommandFailed;
}
});
//Handle skip backward command from lock screen
MPRemoteCommandCenter.Shared.SkipBackwardCommand.AddTarget((arg) =>
{
try
{
GlobalResources.playerPodcast.Skip(-15); //icon says 15 seconds
return MPRemoteCommandHandlerStatus.Success;
}
catch (Exception ex)
{
return MPRemoteCommandHandlerStatus.CommandFailed;
}
});
}
}