JonathanC
JonathanC

Reputation: 977

Icecast stream source client iOS

I would like to use an iPhone as the audio source for an ICEcast stream.

1) is the AudioQueueInputCallback where I should be sending this stream?

2) I have been able to identify the protocol for ICEcast Icecast 2: protocol description, streaming to it using C# However, I am not certain how to do this in the callback code (i.e. how to send the binary audio)

UPDATE

static void MyAQInputCallback( void *inUserData, 
  AudioQueueRef inQueue,
  AudioQueueBufferRef inBuffer,
  const AudioTimeStamp *inStartTime,
  UInt32 inNumPackets,
  cont AudioStreamPacketDescription *inPacketDesc)
{

    if (inNumPackets > 0)
    {
       // instead of
       //     AudioFileWritePackets(someFile, FALSE, 
       //           inBuffer->mAudioDataByteSize,
       //           inPacketDesc, recordPacketNumber, 
       //           &inNumPackets, inBuffer->mAudioData);

       // I want to send to http://myicecastserver
       // instead
    }

}

UPDATE

I will open a socket connection to my icecast server to send the data.

Upvotes: 1

Views: 1763

Answers (1)

Tyler Durden
Tyler Durden

Reputation: 11562

This is a non-trivial problem. The "protocol" you mention is just some guy sniffing a few packets and making a few guesses. If you examine the ICES source code you can see the actual methodology for sending to a Icecast server and it is a highly complex, custom streaming protocol. The relevant code is in two files: stream.c and stream_shared.c assuming you have your stream already encoded to PCM. To give a sense for the complexity of this streaming algorithm, here is a small extract from the sender:

   else if (sdsc->enc)
    {
        ogg_page og;
        int be = (sdsc->input->subtype == INPUT_PCM_BE_16)?1:0;
        int ret=1;

        /* We use critical as a flag to say 'start a new stream' */
        if(buffer->critical)
        {
            if(sdsc->resamp) {
                resample_finish(sdsc->resamp);
                encode_data_float(sdsc->enc, sdsc->resamp->buffers,
                        sdsc->resamp->buffill);
                resample_clear(sdsc->resamp);
                sdsc->resamp = resample_initialise (sdsc->stream->channels,
                        sdsc->stream->resampleinrate, sdsc->stream->resampleoutrate);
            }
            encode_finish(sdsc->enc);
            while(encode_flush(sdsc->enc, &og) != 0)
            {
                if ((ret = stream_send_data(sdsc, og.header, og.header_len)) == 0)
                    return 0;
                if ((ret = stream_send_data(sdsc, og.body, og.body_len)) == 0)
                    return 0;
            }
            encode_clear(sdsc->enc);

            if(sdsc->input->metadata_update)
            {
                vorbis_comment_clear(&sdsc->vc);
                vorbis_comment_init(&sdsc->vc);

                sdsc->input->metadata_update(sdsc->input->internal, &sdsc->vc);
            }

As I said, this is only about 10% of the code. There are literally pages and pages of error checking, metadata transmissions, etc etc. If you wanted to create a custom Icecast source client you would have to copy all this code, port it to your program, then encode your input as PCM and then packetize it for delivery to the routines in stream.c and stream_shared.c.

Upvotes: 1

Related Questions