Xamarin 共享项目 - MP3 流

Xamarin Shared Project - MP3 Streaming

我正在 Xamarin 共享项目中编写一个简单的流式 mp3 播放器。我有 this solution which works perfectly with iOS. I can also use the media player solution 和 Android(我猜)来达到同样的效果。关于以正确的方式执行此操作以共享最大代码的任何建议?据我了解,我有以下选项

  1. 写一个摘要 class 共享基本的音频功能,如流式传输、缓冲等,然后在特定平台中实现它们
  2. 在每个平台特定的解决方案中创建用户控件
  3. 写一个可移植的Class库

我已经完成 this,但不确定根据我的要求和手头的情况,哪种方法是最明智的。

我将其用作媒体播放器的界面:

public delegate void StatusChangedEventHandler(object sender, EventArgs e);

public delegate void CoverReloadedEventHandler(object sender, EventArgs e);

public delegate void PlayingEventHandler(object sender, EventArgs e);

public delegate void BufferingEventHandler(object sender, EventArgs e);

/// <summary>
/// The main purpose of this class is to be a controlling unit for all the single MediaItem implementations, who
/// in themselve can play their media, but need a central controling unit, surrounding them
/// </summary>
public interface IMediaPlayer
{
    /// <summary>
    /// Reading the current status of the player (STOPPED, PAUSED, PLAYING, LOADING - initialization and buffering is combined here)
    /// </summary>
    PlayerStatus Status { get; }

    /// <summary>
    /// Raised when the status changes (playing, pause, buffering)
    /// </summary>
    event StatusChangedEventHandler StatusChanged;

    /// <summary>
    /// Raised when the cover on the player changes
    /// </summary>
    event CoverReloadedEventHandler CoverReloaded;

    /// <summary>
    /// Raised at least every second when the player is playing.
    /// </summary>
    event PlayingEventHandler Playing;

    /// <summary>
    /// Raised each time the buffering is updated by the player.
    /// </summary>
    event BufferingEventHandler Buffering;

    /// <summary>
    /// Starts playing from the current position
    /// </summary>
    Task Play();

    /// <summary>
    /// Stops playing
    /// </summary>
    Task Stop();

    /// <summary>
    /// Stops playing but retains position
    /// </summary>
    Task Pause();

    /// <summary>
    /// Gets the players position in milliseconds
    /// </summary>
    int Position { get; }

    /// <summary>
    /// Gets the source duration in milliseconds
    /// If the response is -1, the duration is unknown or the player is still buffering.
    /// </summary>
    int Duration { get; }

    /// <summary>
    /// Gets the buffered time in milliseconds
    /// </summary>
    int Buffered { get; }

    /// <summary>
    /// Gets the current cover. The class for the instance depends on the platform.
    /// Returns NULL if unknown.
    /// </summary>
    object Cover { get; }

    /// <summary>
    /// Changes position to the specified number of milliseconds from zero
    /// </summary>
    Task Seek(int position);

    /// <summary>
    /// Should be the same as calling PlayByPosition(Queue.size()+1)
    /// Maybe you'll want to preload the next song into memory ...
    /// </summary>
    Task PlayNext();

    /// <summary>
    /// Start playing if nothing is playing, otherwise it pauses the current media
    /// </summary>
    Task PlayPause();

    /// <summary>
    /// Should be the same as calling PlayByPosition(Queue.size()-1).
    /// Maybe you'll want to keep the last song in memory ...
    /// </summary>
    Task PlayPrevious();

    /// <summary>
    /// Start playing a track by its position in the Queue
    /// </summary>
    Task PlayByPosition(int index);
}

我还有一个自定义队列,可能对你有帮助:

public interface IQueue : ICollection<Track>, INotifyCollectionChanged, INotifyPropertyChanged
{
    /// <summary>
    /// Activates or deactivates the Repeat option
    /// </summary>
    bool Repeat { get; set; }

    /// <summary>
    /// Activates or deactivates the Shuffle option
    /// </summary>
    bool Shuffle { get; set; }

    /// <summary>
    /// If the Queue has a next track
    /// </summary>
    bool HasNext();

    /// <summary>
    /// If the Queue has a previous track
    /// </summary>
    bool HasPrevious();

    /// <summary>
    /// Get the current track from the Queue
    /// </summary>
    Track Current { get; }

    /// <summary>
    /// Get the current playing index the Queue
    /// </summary>
    int Index { get; }

    void setPreviousAsCurrent();

    void setNextAsCurrent();

    void setIndexAsCurrent(int index);

    void AddRange(IEnumerable<Track> items);
}

我的玩家状态是:

public enum PlayerStatus
{
    STOPPED,
    PAUSED,
    PLAYING,
    LOADING
}