Xamarin.Forms Shoutcast CrossPlatform

I am new in Xamarin.Forms and I am working on a ShoutCast Streamer. I create a Class called ShoutCastStream with the code below :
using System;
using System.Text;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;

#if XAM_ANDROID || XAM_IOS
/// <summary>
/// Provides the functionality to receive a shoutcast media stream
/// </summary>
public class ShoutcastStream : Stream
{
    private int metaInt;
    private int receivedBytes;
    private Stream netStream;
    private bool connected = false;

private string streamTitle;

/// <summary>
/// Is fired, when a new StreamTitle is received
/// </summary>
public event EventHandler StreamTitleChanged;

/// <summary>
/// Creates a new ShoutcastStream and connects to the specified Url
/// </summary>
/// <param name="url">Url of the Shoutcast stream</param>
public ShoutcastStream(string url)
{
    HttpWebResponse response;

    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
    request.Headers.Clear();
    request.Headers.Add("Icy-MetaData", "1");
    request.KeepAlive = false;
    request.UserAgent = "VLC media player";

    response = (HttpWebResponse)request.GetResponse();

    metaInt = int.Parse(response.Headers["Icy-MetaInt"]);
    receivedBytes = 0;

    netStream = response.GetResponseStream();

    connected = true;
}

/// <summary>
/// Parses the received Meta Info
/// </summary>
/// <param name="metaInfo"></param>
private void ParseMetaInfo(byte[] metaInfo)
{
    string metaString = Encoding.ASCII.GetString(metaInfo);

    string newStreamTitle = Regex.Match(metaString, "(StreamTitle=')(.*)(';StreamUrl)").Groups[2].Value.Trim();
    if (!newStreamTitle.Equals(streamTitle))
    {
        streamTitle = newStreamTitle;
        OnStreamTitleChanged();
    }
}

/// <summary>
/// Fires the StreamTitleChanged event
/// </summary>
protected virtual void OnStreamTitleChanged()
{
    if (StreamTitleChanged != null)
        StreamTitleChanged(this, EventArgs.Empty);
}

/// <summary>
/// Gets a value that indicates whether the ShoutcastStream supports reading.
/// </summary>
public override bool CanRead
{
    get { return connected; }
}

/// <summary>
/// Gets a value that indicates whether the ShoutcastStream supports seeking.
/// This property will always be false.
/// </summary>
public override bool CanSeek
{
    get { return false; }
}

/// <summary>
/// Gets a value that indicates whether the ShoutcastStream supports writing.
/// This property will always be false.
/// </summary>
public override bool CanWrite
{
    get { return false; }
}

/// <summary>
/// Gets the title of the stream
/// </summary>
public string StreamTitle
{
    get { return streamTitle; }
}

/// <summary>
/// Flushes data from the stream.
/// This method is currently not supported
/// </summary>
public override void Flush()
{
    connected = false;
    netStream.Close();
    return;
}

/// <summary>
/// Gets the length of the data available on the Stream.
/// This property is not currently supported and always thows a <see cref="NotSupportedException"/>.
/// </summary>
public override long Length
{
    get { throw new NotSupportedException(); }
}

/// <summary>
/// Gets or sets the current position in the stream.
/// This property is not currently supported and always thows a <see cref="NotSupportedException"/>.
/// </summary>
public override long Position
{
    get
    {
        throw new NotSupportedException();
    }
    set
    {
        throw new NotSupportedException();
    }
}

/// <summary>
/// Reads data from the ShoutcastStream.
/// </summary>
/// <param name="buffer">An array of bytes to store the received data from the ShoutcastStream.</param>
/// <param name="offset">The location in the buffer to begin storing the data to.</param>
/// <param name="count">The number of bytes to read from the ShoutcastStream.</param>
/// <returns>The number of bytes read from the ShoutcastStream.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
    try
    {
        if (receivedBytes == metaInt)
        {
            int metaLen = netStream.ReadByte();
            if (metaLen > 0)
            {
                byte[] metaInfo = new byte[metaLen * 16];
                int len = 0;
                while ((len += netStream.Read(metaInfo, len, metaInfo.Length - len)) < metaInfo.Length) ;
                ParseMetaInfo(metaInfo);
            }
            receivedBytes = 0;
        }

        int bytesLeft = ((metaInt - receivedBytes) > count) ? count : (metaInt - receivedBytes);
        int result = netStream.Read(buffer, offset, bytesLeft);
        receivedBytes += result;
        return result;
    }
    catch (Exception e)
    {
        connected = false;
        Console.WriteLine(e.Message);
        return -1;
    }
}
/// <summary>
/// Closes the ShoutcastStream.
/// </summary>
public override void Close()
{
    connected = false;
    netStream.Close();
}
/// <summary>
/// Sets the current position of the stream to the given value.
/// This Method is not currently supported and always throws a <see cref="NotSupportedException"/>.
/// </summary>
/// <param name="offset"></param>
/// <param name="origin"></param>
/// <returns></returns>
public override long Seek(long offset, SeekOrigin origin)
{
    throw new NotSupportedException();
}

/// <summary>
/// Sets the length of the stream.
/// This Method always throws a <see cref="NotSupportedException"/>.
/// </summary>
/// <param name="value"></param>
public override void SetLength(long value)
{
    throw new NotSupportedException();
}

/// <summary>
/// Writes data to the ShoutcastStream.
/// This method is not currently supported and always throws a <see cref="NotSupportedException"/>.
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
public override void Write(byte[] buffer, int offset, int count)
{
    throw new NotSupportedException();
}
}
#endif

Then I used a NuGet called SimpleAudioPlayer to stream this source in this way .
ISimpleAudioPlayer player = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current;
var shoutcast = new ShoutcastStream("https://stream2.rjvnlive.com/");
var res = player.Load(shoutcast);
player.Play();
shoutcast.StreamTitleChanged += Shoutcast_StreamTitleChanged;

But unfortunately unable to play this stream. Is there any way to play this Stream implemented in ShoutcastStream class for Xamarin.Forms ?

Answers

  • jeffgraujeffgrau Member

    Did you ever get this working? I am in the process of writing the same thing. Mine is based on a working Android version, but the metadata parsing and byte by byte read is uglier in mine and mine is not yet working.

  • jeffgraujeffgrau Member

    It looks like you are trying to play the metadata stream, rather than the sound stream. The sound stream is usually HLS. The metadata stream supplies the title, artist, etc., but not the sound.

  • carlosancarlosan Member ✭✭

    Im using MediaManager with this code:

    MediaFile mediaFile = new MediaFile();
    MediaFileMetadata metaData = new MediaFileMetadata();
    
    mediaFile.Url = "Stream URL";
    mediaFile.Type = MediaFileType.Audio;
    mediaFile.Availability = ResourceAvailability.Remote;
    mediaFile.Metadata = metaData;
    
    metaData.DisplayTitle = SongNameLbl.Text;
    metaData.DisplaySubtitle = ArtistNameLbl.Text;
    metaData.Title = SongNameLbl.Text;
    metaData.Artist = ArtistNameLbl.Text;
    
  • IVANLABRADORIVANLABRADOR USMember ✭✭

    @carlosan said:
    Im using MediaManager with this code:

    MediaFile mediaFile = new MediaFile();
    MediaFileMetadata metaData = new MediaFileMetadata();
    
    mediaFile.Url = "Stream URL";
    mediaFile.Type = MediaFileType.Audio;
    mediaFile.Availability = ResourceAvailability.Remote;
    mediaFile.Metadata = metaData;
    
    metaData.DisplayTitle = SongNameLbl.Text;
    metaData.DisplaySubtitle = ArtistNameLbl.Text;
    metaData.Title = SongNameLbl.Text;
    metaData.Artist = ArtistNameLbl.Text;
    

    What nutget did you use to do that?

Sign In or Register to comment.