This project has moved. For the latest updates, please go here.

Test radios Shoutcast

Oct 27, 2014 at 10:10 PM
Here are 2 cases I can't get working

http://www.hiper.fm/emissao/playlist_hiper96.pls
http://www.radio.noite.pt/WMP.asx

Any ideas on how to get them working ???
Coordinator
Oct 28, 2014 at 9:40 AM
Edited Oct 28, 2014 at 1:06 PM
The first stream points to a station that returns an "ICY 200 OK" response. I have some changes that lets that stream play, at least when "HttpConnectionWebReaderManager" is configured. I should have those changes pushed to codeplex within the next day or so.

The second case has a URL that points to the URL for the actual stream. You could hard code the target URL or do something like this to translate it,
            var ext = source.GetExtension();

            if (null != ext && string.Equals(ext, ".asx", StringComparison.OrdinalIgnoreCase))
            {
                using (var hc = new HttpClient())
                {
                    var x = await hc.GetStringAsync(source);

                    Uri newSource;
                    if (Uri.TryCreate(source, x, out newSource))
                        source = newSource;
                }
            }
That's not a general solution, but it works in this case. (Note that the .GetExtension() is an extension method from SM.Media.Web.UriExtensions.)

If you want to add that as a format to phonesm, take a look at how PlsSegmentManagerFactory is integrated. You will need to create your own ISegmentManagerFactoryInstance implementation and the register it with Autofac.

The below example takes the first line that looks like a URL and tries to play it. The code was able to play the stream on HlsView.WP81; it should work on the other platforms as well.

Register it like this,
using System.Linq;
using Autofac;
using SM.Media.Builder;
using SM.Media.Content;
using SM.Media.Segments;
   ...
    _mediaStreamFacade = MediaStreamFacadeSettings.Parameters.Create();

    var builderBase = (BuilderBase)_mediaStreamFacade.Builder;

    var builder = builderBase.ContainerBuilder;

    builder.RegisterType<YourSegmentManagerFactory>().As<ISegmentManagerFactoryInstance>().SingleInstance().PreserveExistingDefaults();
    builder.RegisterInstance(new ContentTypeDetector(ContentTypes.AllTypes.Union(new [] {YourSegmentManagerFactory.Asx}))).As<IContentTypeDetector>();
Where the YourSegmentManagerFactory implementation should look something like this:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SM.Media.Content;
using SM.Media.Segments;
using SM.Media.Web;
   ...
    public class YourSegmentManagerFactory : ISegmentManagerFactoryInstance
    {
        public static ContentType Asx = new ContentType("ASX", ContentKind.Playlist, "video/x-ms-asf", ".asx");
        static readonly ICollection<ContentType> Types = new[] { Asx };
        readonly IWebReaderManager _webReaderManager;

        public YourSegmentManagerFactory(IWebReaderManager webReaderManager)
        {
            _webReaderManager = webReaderManager;
        }

        #region ISegmentManagerFactoryInstance Members

        public ICollection<ContentType> KnownContentTypes
        {
            get { return Types; }
        }

        public async Task<ISegmentManager> CreateAsync(ISegmentManagerParameters parameters, ContentType contentType, CancellationToken cancellationToken)
        {
            foreach (var url in parameters.Source)
            {
                var localUrl = url;

                var webReader = _webReaderManager.CreateReader(localUrl, Asx.Kind, contentType: Asx);

                try
                {
                    using (var webStream = await webReader.GetWebStreamAsync(localUrl, false, cancellationToken).ConfigureAwait(false))
                    {
                        if (!webStream.IsSuccessStatusCode)
                        {
                            webReader.Dispose();
                            continue;
                        }

                        using (var stream = await webStream.GetStreamAsync(cancellationToken).ConfigureAwait(false))
                        {
                            var segmentManager = await ReadPlaylistAsync(webReader, webStream.ActualUrl, stream, cancellationToken).ConfigureAwait(false);

                            if (null != segmentManager)
                                return segmentManager;
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Log me...?
                    webReader.Dispose();
                }
            }

            return null;
        }

        #endregion

        async Task<ISegmentManager> ReadPlaylistAsync(IWebReader webReader, Uri url, Stream stream, CancellationToken cancellationToken)
        {
            Uri track = null;

            using (var tr = new StreamReader(stream))
            {
                for (; ; )
                {
                    var line = await tr.ReadLineAsync().ConfigureAwait(false);

                    if (null == line)
                        return null;

                    if (string.IsNullOrWhiteSpace(line))
                        continue;

                    if (Uri.TryCreate(url, line.Trim(), out track))
                        break;
                }
            }

            if (null == track)
                return null;

            var contentType = await webReader.DetectContentTypeAsync(track, ContentKind.AnyMedia, cancellationToken).ConfigureAwait(false);

            if (null == contentType)
            {
                Debug.WriteLine("Unable to detect type for " + track);
                return null;
            }

            return new SimpleSegmentManager(webReader, new[] { track }, contentType);
        }
    }
Oct 28, 2014 at 10:43 PM
Edited Oct 28, 2014 at 10:43 PM
Strange I've used your solution (radio n2)

like this
   _mediaStreamFacade = MediaStreamFacadeSettings.Parameters.Create();
                   
            _mediaStreamFacade.SetParameter(_bufferingPolicy);

            var builderBase = (BuilderBase)_mediaStreamFacade.Builder;

            var builder = builderBase.ContainerBuilder;

            builder.RegisterType<myTunerSegmentAsx>().As<ISegmentManagerFactoryInstance>().SingleInstance().PreserveExistingDefaults();
            builder.RegisterInstance(new ContentTypeDetector(ContentTypes.AllTypes.Union(new[] { myTunerSegmentAsx.Asx }))).As<IContentTypeDetector>();
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SM.Media.Content;
using SM.Media.Segments;
using SM.Media.Web;
namespace SM.Media.Pls
{


    public class myTunerSegmentAsx : ISegmentManagerFactoryInstance
    {
        public static ContentType Asx = new ContentType("ASX", ContentKind.Playlist, "video/x-ms-asf", ".asx");
        static readonly ICollection<ContentType> Types = new[] { Asx };
        readonly IWebReaderManager _webReaderManager;

        public myTunerSegmentAsx(IWebReaderManager webReaderManager)
        {
            _webReaderManager = webReaderManager;
        }

        #region ISegmentManagerFactoryInstance Members

        public ICollection<ContentType> KnownContentTypes
        {
            get { return Types; }
        }

        public async Task<ISegmentManager> CreateAsync(ISegmentManagerParameters parameters, ContentType contentType, CancellationToken cancellationToken)
        {
            foreach (var url in parameters.Source)
            {
                var localUrl = url;

                var webReader = _webReaderManager.CreateReader(localUrl, Asx.Kind, contentType: Asx);

                try
                {
                    using (var webStream = await webReader.GetWebStreamAsync(localUrl, false, cancellationToken).ConfigureAwait(false))
                    {
                        if (!webStream.IsSuccessStatusCode)
                        {
                            webReader.Dispose();
                            continue;
                        }

                        using (var stream = await webStream.GetStreamAsync(cancellationToken).ConfigureAwait(false))
                        {
                            var segmentManager = await ReadPlaylistAsync(webReader, webStream.ActualUrl, stream, cancellationToken).ConfigureAwait(false);

                            if (null != segmentManager)
                                return segmentManager;
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Log me...?
                    webReader.Dispose();
                }
            }

            return null;
        }

        #endregion

        async Task<ISegmentManager> ReadPlaylistAsync(IWebReader webReader, Uri url, Stream stream, CancellationToken cancellationToken)
        {
            Uri track = null;

            using (var tr = new StreamReader(stream))
            {
                for (; ; )
                {
                    var line = await tr.ReadLineAsync().ConfigureAwait(false);

                    if (null == line)
                        return null;

                    if (string.IsNullOrWhiteSpace(line))
                        continue;

                    if (Uri.TryCreate(url, line.Trim(), out track))
                        break;
                }
            }

            if (null == track)
                return null;

            var contentType = await webReader.DetectContentTypeAsync(track, ContentKind.AnyMedia, cancellationToken).ConfigureAwait(false);

            if (null == contentType)
            {
                Debug.WriteLine("Unable to detect type for " + track);
                return null;
            }

            return new SimpleSegmentManager(webReader, new[] { track }, contentType);
        }
    }
}
and it doesn't work :(
I've also pulled the latest sources ... :(((
Coordinator
Oct 29, 2014 at 8:06 AM
Do you have trouble compiling it? Does it not seem to be doing anything or is it crashing? Which platform are you using (e.g., WP8, WP8.1 or Win8.1)? Have you tried with HlsView.*, SamplePlayer.*, or BackgroundAudio.*? In which file did you make the change to how _mediaStreamFacade is created? Do you see any new warnings in the Output window when doing a build?

Thanks.
Oct 29, 2014 at 9:37 AM
Hi!

It compiles and run properly

I'm using my own background player because most of my streams work with the SDK's mediaelement.

What I see on the output window is:
MediaStreamFacadeBase.OpenMediaAsync(http://www.radio.noite.pt/WMP.asx)
'Windows.Media.BackgroundPlayback.exe' (CoreCLR: .): Loaded 'C:\Data\SharedData\PhoneTools\AppxLayouts\XXXXXXXXXXXXXXXXXXXXXXXXXXXX.Debug_ARM.Crist_v_o\SM.TsParser.DLL'. Symbols loaded.
'Windows.Media.BackgroundPlayback.exe' (CoreCLR: .): Loaded 'C:\windows\system32\SYSTEM.IO.NI.DLL'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Windows.Media.BackgroundPlayback.exe' (CoreCLR: .): Loaded 'C:\windows\system32\SYSTEM.XML.XDOCUMENT.NI.DLL'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Windows.Media.BackgroundPlayback.exe' (CoreCLR: .): Loaded 'C:\windows\system32\SYSTEM.XML.LINQ.NI.DLL'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Windows.Media.BackgroundPlayback.exe' (CoreCLR: .): Loaded 'C:\windows\system32\SYSTEM.XML.NI.DLL'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Windows.Media.BackgroundPlayback.exe' (CoreCLR: .): Loaded 'C:\windows\system32\SYSTEM.TEXT.ENCODING.NI.DLL'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
TsMediaManager.OpenMedia()
TsMediaManager.OpenMedia() handler
MediaStreamFacadeBase.MediaManagerOnStateChange() to OpenMedia: 
Media manager state in background agent: OpenMedia, message: 
TsMediaManager.OpenMediaAsync() state OpenMedia
MediaStreamFacadeBase.MediaManagerOnStateChange() to Opening: 
Media manager state in background agent: Opening, message: 
HttpClientWebReaderManager.DetectContentTypeAsync() url ext "http://www.radio.noite.pt/WMP.asx" type ASX (video/x-ms-asf)
The thread 0xee0 has exited with code 259 (0x103).
The thread 0xe64 has exited with code 259 (0x103).
'Windows.Media.BackgroundPlayback.exe' (CoreCLR: .): Loaded 'C:\windows\system32\System.Net.Http.ni.DLL'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Windows.Media.BackgroundPlayback.exe' (CoreCLR: .): Loaded 'C:\windows\system32\System.Net.Http.Phone.ni.DLL'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
A first chance exception of type 'System.Exception' occurred in mscorlib.ni.dll
A first chance exception of type 'System.Exception' occurred in mscorlib.ni.dll
HttpClientWebReaderManager.DetectContentTypeAsync() url header "http://live.noite.fm:8080/" unknown type
The thread 0xddc has exited with code 0 (0x0).
Unable to detect asx type for http://live.noite.fm:8080/
A first chance exception of type 'System.IO.FileNotFoundException' occurred in SM.Media.DLL
A first chance exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.ni.dll
TsMediaManager.OpenMediaAsync failed: Unable to create playlist
MediaStreamFacadeBase.MediaManagerOnStateChange() to Error: Unable to play media
Media manager state in background agent: Error, message: Unable to play media
MediaStreamFacadeBase.CloseMediaAsync()
A first chance exception of type 'System.AggregateException' occurred in SM.Media.DLL
MediaStreamFacadeBase.CloseMediaAsync() calling mediaManager.CloseAsync()
A first chance exception of type 'System.AggregateException' occurred in mscorlib.ni.dll
WinRtMediaStreamConfigurator.ReportError(): Unable to play media
AsyncFifoWorker.WorkHandle.RunAsync() work should not throw exceptions: System.AggregateException: Unable to create playlist
   System.IO.FileNotFoundException: Unable to create playlist
   System.IO.FileNotFoundException: Unable to create playlist

TsMediaManager.CloseAsync()
MediaStreamFacadeBase.MediaManagerOnStateChange() to Closing: 
TsMediaManager.CloseAsync() calling _mediaStreamSource.CloseAsync()
Media manager state in background agent: Closing, message: 
WinRtMediaStreamConfigurator.CloseAsync()
MediaStreamFacadeBase.MediaManagerOnStateChange() to Closed: 
Media manager state in background agent: Closed, message: 
TsMediaManager.CloseAsync() completed
MediaStreamFacadeBase.CloseMediaAsync() returned from mediaManager.CloseAsync()
MediaStreamFacadeBase.CleanupMediaManager()
TsMediaManager.Dispose()
TsMediaManager.CloseAsync()
TsMediaManager.CloseAsync() completed by other caller
TsMediaManager.Dispose()
WinRtMediaStreamConfigurator.Dispose()
ValidateEvent Invalid state transition: state Idle event DisposeCalled
MediaStreamFacadeBase.CleanupMediaManager() completed
MediaStreamFacadeBase.CloseMediaAsync() completed
MediaStreamFacadeBase.OpenMediaAsync(http://www.radio.noite.pt/WMP.asx)
TsMediaManager.OpenMedia()
TsMediaManager.OpenMedia() handler
TsMediaManager.OpenMediaAsync() state OpenMedia
HttpClientWebReaderManager.DetectContentTypeAsync() url ext "http://www.radio.noite.pt/WMP.asx" type ASX (video/x-ms-asf)
MediaStreamFacadeBase.MediaManagerOnStateChange() to OpenMedia: 
Media manager state in background agent: OpenMedia, message: 
MediaStreamFacadeBase.MediaManagerOnStateChange() to Opening: 
Media manager state in background agent: Opening, message: 
A first chance exception of type 'System.Exception' occurred in mscorlib.ni.dll
A first chance exception of type 'System.Exception' occurred in mscorlib.ni.dll
HttpClientWebReaderManager.DetectContentTypeAsync() url header "http://live.noite.fm:8080/" unknown type
Unable to detect asx type for http://live.noite.fm:8080/
A first chance exception of type 'System.IO.FileNotFoundException' occurred in SM.Media.DLL
A first chance exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.ni.dll
TsMediaManager.OpenMediaAsync failed: Unable to create playlist
MediaStreamFacadeBase.MediaManagerOnStateChange() to Error: Unable to play media
Media manager state in background agent: Error, message: Unable to play media
A first chance exception of type 'System.AggregateException' occurred in SM.Media.DLL
WinRtMediaStreamConfigurator.ReportError(): Unable to play media
A first chance exception of type 'System.AggregateException' occurred in mscorlib.ni.dll
AsyncFifoWorker.WorkHandle.RunAsync() work should not throw exceptions: System.AggregateException: Unable to create playlist
   System.IO.FileNotFoundException: Unable to create playlist
   System.IO.FileNotFoundException: Unable to create playlist
Oct 29, 2014 at 10:55 PM
And more challenging are rtmp streams :S rtmp://wowza07.sharp-stream.com/clyde1aac/clyde1aac

streaming radios world is complex!
Coordinator
Oct 30, 2014 at 1:52 AM
If you switch to HttpConnection (the quickest way if you are building from source is to uncomment HttpConnectionModule in TsMediaManagerBuilder) and use code with f584a59a7c03, then there is a good chance your first stream will work.

I'll take a look at the second stream and the code you pasted in a bit.
Marked as answer by cmorgado on 10/30/2014 at 1:29 AM
Oct 30, 2014 at 9:29 AM
EUREKA!

With the lastest source and with your suggestion both radios work!

THANK YOU!