Search code examples
c#.netms-media-foundationshoutcasticecast

Media Foundation .NET: How to get song title from shoutcast


I try to get song title from shoutcast stream, but the events: MENewStream, MEEndOfStream, MESourceMetadataChanged are never triggered, nothing is updated.

This is how I create media source:

hr = sourceResolver.CreateObjectFromURL(
   mediaURL, MFResolution.ByteStream, properties, out mediaStream
);
hr = sourceResolver.CreateObjectFromByteStream(
   mediaStream, mediaURL, MFResolution.MediaSource, properties, out objectType, out mediaSource
);

And this is how I get metadata:

hr = MFExtern.MFGetService(
mediaSource, MFServices.MF_METADATA_PROVIDER_SERVICE, typeof(IMFMetadataProvider).GUID, out obj
);
IMFMetadataProvider metadataProvider = obj as IMFMetadataProvider;
hr = mediaSource.CreatePresentationDescriptor(out descriptor);
hr = metadataProvider.GetMFMetadata(descriptor, 0, 0, out metadata);

and somewhere in the app I call:

Display(stream.Metadata);

which returns only these:

"Bitrate"       : 128
"Title"         : ...(station name)
"WM/Genre"      : ... 
"WM/PromotionURL": ...

The question is: how could I get the updates from the shoutcast with Media Foundation .NET, what I need to implement to trigger the above events?

Thank you in advance for your time and benevolence.


Solution

  • There are several answers to this question, depending on your circumstances. For example,

    Windows 7

    • If the server you are connecting to uses ICY 200 OK to identify itself as an ICY server, you can use c# code like the shoutcast.zip code here. Adding support for song titles is a fairly trivial change to the existing samples.
    • If the server you are connecting to can be coaxed into responding with ICY 200 OK by sending an Icy-Metadata: 1, then explicitly using the UrlMonSchemePlugin instead of allowing the SourceResolver to resolve the URL can help.

    Note: If the server cannot be convinced to respond with ICY 200 OK (for example if it just uses 200 OK), there is no way to convince MF to automatically parse titles for you (although it may be possible to do the parsing yourself - maybe an MFT?).

    In fact, if a server sends song titles after having responded with 200 OK, MF will try to 'play' the titles. These beeps/buzzes can be very annoying (except with disco music since how could you tell?).

    I thought about trying to create such an MFT, but then I realized that:

    Windows 8

    Instead of 'fixing' MF to allow for any stream that specifies icy-metaint to provide song titles (a seemingly minor fix), MS went a different way.

    They have completely broken the ability to stream mpeg audio using MF.

    The same program (above) that works fine on W7 now gives MF_E_BYTESTREAM_NOT_SEEKABLE errors on W8. This seems weird, since such streams weren't seekable in W7 either, but apparently now that is a fatal error.

    There may be some new approach that MS expects people to use, but I don't know what it might be.


    Update:

    It bothered me that this didn't work on Windows 8. So I created my own Scheme handler (also written in c#). In addition to handling streams that use ICY 200 OK, this one also handles just 200 OK (as well as a few other features). And, it supports (just) enough seeking to work with W8's SourceResolver. So (nearly) the same player app works for both W7 & W8.

    There are a couple caveats:

    1. While the sample still works on Windows 7, the new Scheme handler that supports 200 OK only works on Windows 8 and (presumably) later.
    2. It requires a beta version of MediaFoundation .Net.

    There is a pre-built version of the library using .Net 4.5.2 included in the ShoutCast-2015 sample. The library source is checked into cvs.

    This is not "commercial-ready" code, but it does show the basic concepts. And the (commented) source is included if anyone wants to make it better. In particular, it doesn't handle non-ascii song titles, and I'm pretty sure the stream handling could be more efficient to avoid audio gaps (or failing that, communicating the gap to MF and doing a better job of 'buffering' to avoid the next gap).