12

I have to create app that provides online radio streaming (icecast), preferably .ogg format. So I have next questions:

  1. How can I play .ogg format audio stream? Are there any supported classes? Because I can't find any, so I think that it is impossible without many bitwise operations using CFNetwork, CoreAudio, AudioToolbox etc. (I don't look at cocos2d, because it's ridiculous) Am i wrong?
  2. I'm playing mp3 stream for now (no possibility for .ogg for me). I tried to use AVPlayer, MPMovieMediaController, AudioSreaming lib by MattGallagher and by DigitalDJ, and none of these solutions can't provides me metadata access.

For AVPlayer:

   -(void)playButtonPressed:(id)sender
    {
        NSURL *grindURL = [NSURL URLWithString:@"http://radio.goha.ru:8000/grind.fm"];
                    grindFMPlayer = [[AVPlayer alloc] initWithURL:grindURL];
                    [grindFMPlayer.currentItem addObserver:self forKeyPath:@"status" options:0 context:nil]; 
                    AVPlayerItem *item = grindFMPlayer.currentItem;
                    [grindFMPlayer play];
    }

-(void)stopButtonPressed:(id)sender
{
            AVURLAsset *ass = grindFMPlayer.currentItem.asset;
            NSArray *arr = [ass commonMetadata];
            NSArray *it_meta = [grindFMPlayer.currentItem timedMetadata];
            [grindFMPlayer pause];
}

arr and it_meta count always 0, no song\artist\any metadata.
The same for the MPMovieMediaController, metadataUpdate never called

streamAudioPlayer = [[MPMoviePlayerController alloc] 
                                                   initWithContentURL:[NSURL URLWithString:@"http://radio.goha.ru:8000/grind.fm"];
                streamAudioPlayer.movieSourceType = MPMovieSourceTypeStreaming;
                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(MetadataUpdate:) name:MPMoviePlayerTimedMetadataUpdatedNotification object:nil];
[streamAudioPlayer play];

and in stop button method:

timedMeta = [streamAudioPlayer timedMetadata];
            if ([streamAudioPlayer timedMetadata]!=nil && [[streamAudioPlayer timedMetadata] count] > 0) 
            {
                NSLog(@"metadata count = %d", [[streamAudioPlayer timedMetadata] count]);
                for (MPTimedMetadata *metadata in [streamAudioPlayer timedMetadata]) 
                {
                    NSLog(@"description %@", metadata.allMetadata);
                    if ([[metadata.allMetadata valueForKey:@"key"] isEqualToString:@"title"]) 
                    {
                        NSString *text = [metadata.allMetadata valueForKey:@"value"];
                        NSString* filename = text;
                    }
                }
            }

[streamAudioPlayer timedMetadata] always nil.

I've tried

These 2 projects for shoutcast and icecast - http://www.mikejablonski.org/2009/04/17/reading-shoutcast-metadata-from-a-stream/

But still have no luck to get current playing track info, which only obtains in SHOUTcast app as

1st Metadata = 'StreamTitle=',

2nd metadata = '' and bitrate = '128000'
(So I think I have to have deal with bytes from http headers response or something like this? but wtf, it's shoutcast metadata, but my radiostream is icecast. Have no idea)
I would be grateful for any help!

The iOSDev
  • 5,237
  • 7
  • 41
  • 78
Aft3rmath
  • 669
  • 2
  • 12
  • 21
  • 2
    and yes, i saw cocoaWithLove's "mp3 streaming" posts cycle and HTTP Live Streaming Overview – Aft3rmath Mar 22 '12 at 21:10
  • On metadata... This question has been answered at least weekly. Search. Icecast is built to be compatible with SHOUTcast, and returns metadata in the same way. – Brad Mar 31 '12 at 17:41
  • You only get metadata when the metadata is updated. Otherwise the first byte of the block is `0x00`, indicating a 0-byte length... no change. If the first block says that your `StreamTitle` is equal to an empty string, then your server isn't receiving the metadata from the encoder. – Brad Apr 01 '12 at 15:00
  • What you mean by "my server"? My app? btw can u share link to this question that has been answered at least weekly if u have so? thanks anyway ;] – Aft3rmath Apr 01 '12 at 18:33
  • I mean, your SHOUTcast/Icecast server. It doesn't have metadata to send. http://stackoverflow.com/questions/4911062/pulling-track-info-from-an-audio-stream-using-php/4914538#4914538 http://stackoverflow.com/questions/3696208/parsing-shoutcast-server-information-table-with-javascript/4069719#4069719 http://stackoverflow.com/questions/8339698/icy-metadata-support-with-ffmpeg/8342918#8342918 – Brad Apr 01 '12 at 18:49
  • http://stackoverflow.com/questions/8865199/receiving-info-of-a-shoutcast-stream-on-android/8870843#8870843 http://stackoverflow.com/questions/6049128/id3-over-audio-streaming/6049953#6049953 http://stackoverflow.com/questions/8339698/icy-metadata-support-with-ffmpeg/8342918#8342918 http://stackoverflow.com/questions/6115531/is-it-possible-to-get-icecast-metadata-from-html5-audio-element/6125139#6125139 http://stackoverflow.com/questions/6723999/live-audio-streaming-container-formats/6726305#6726305 – Brad Apr 01 '12 at 18:50
  • Thanks for these links! But in android version of this radio app I'm able to get metadata using Scraper library, so icecast server must be sending metadata... anyway thanks for links, now i'll check em – Aft3rmath Apr 01 '12 at 19:45
  • Hm, the problem was that mp3 stream doesn't send any metadata, but ogg does. So i need to play mp3 and parse ogg until i learn how to play ogg. How can – Aft3rmath Apr 19 '12 at 13:26
  • Then you have a problem with the source encoder not sending metadata to the server. – Brad Apr 19 '12 at 14:02
  • @Brad yes,this is how radio does work. Don't you know, can I play mp3 stream via AVPlayer for example, and synchronously parsing ogg stream metadata using AudioStreamer code, without trying to play ogg stream? Because i tried to get headers with NSURLRequest and NSURLConnection, but this doesn't work, biy in AudioStreamer with ASIHTTPRequest it works – Aft3rmath Apr 19 '12 at 15:47
  • `NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease]; [request setURL:[NSURL URLWithString:@"http://radio.goha.ru:8000/grindfm.ogg"]]; [request setHTTPMethod:@"GET"]; NSString *accept = [NSString stringWithFormat:@"1"]; [request addValue:accept forHTTPHeaderField: @"Icy-MetaData"]; NSURLResponse *response; NSError *error; NSData *serverReply = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];` it's freezing on send request and that's all – Aft3rmath Apr 19 '12 at 15:52
  • Have you tried this one? https://github.com/muhku/FreeStreamer It helped me streaming my shoutcast, but I haven't got any oggs to try and see if it works with. – Neeku Jun 27 '12 at 12:00
  • I made this: audio streaming is using AVPlayer (mp3, temporary solution), and metadata is parsing by AudioStreamer library separately (temporary, too). – Aft3rmath Jul 12 '12 at 15:20

3 Answers3

6

Icecast and Shoutcast are compatible with each other. The difference lies in the way they respond to a HTTP GET request. When you send a HTTP GET request to an Icecast server it will reply with a HTTP 200 OK response. The response headers will contain values for the icy-br, icy-metaint, icy-name, icy-genre and icy-url keys.

When you send a HTTP GET request to a Shoutcast server it will respond with a ICY 200 OK response. In this case you'll have to parse the response data because the metadata will not be available in the response headers.

The most important metadata key is the icy-metaint key. This value will tell you how often the metadata is sent in the stream. For more information about parsing this metadata have a look at this website: Shoutcast Metadata Protocol

To play ogg streams you'll need to use the open source FFmpeg library. This library can be compiled for the iOS platform and used to connect and decode ogg streams.

Kemal Taskin
  • 481
  • 4
  • 10
3

To play an ogg formatted audio stream, you would need to supply a codec. iOS does not have native support for the ogg format

Eric
  • 2,045
  • 17
  • 24
3

I think the first thing to do is to "order" the meta data by setting the request header:

CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Icy-MetaData"), CFSTR("1"));

In my case I added this line to Matt Galaghers's Audio Streamer. The result was that I could actually hear the metadata when the stream was playing because it was contained in the stream data. The next step was to filter the meta data out and interpret it. To achieve this all the necessary information are already mentioned here.

Good luck!

benjamin.ludwig
  • 1,575
  • 18
  • 28