1
- (void)openPlayThreadWithRtmpURL:(NSString *)rtmpURL {
spx_int16_t *input_buffer;

do {
    if (self.rtmpDelegate) {
        [self.rtmpDelegate evenCallbackWithEvent:2000];
    }

    //init speex decoder and config;
    speex_bits_init(&dbits);
    dec_state = speex_decoder_init(&speex_wb_mode);

    speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE, &dec_frame_size);

    input_buffer = malloc(dec_frame_size * sizeof(short));

    NSLog(@"Init Speex decoder success frame_size = %d",dec_frame_size);

    //init rtmp
    pPlayRtmp = RTMP_Alloc();
    RTMP_Init(pPlayRtmp);
    NSLog(@"Play RTMP_Init %@\n", rtmpURL);

    if (!RTMP_SetupURL(pPlayRtmp, (char*)[rtmpURL UTF8String])) {
        NSLog(@"Play RTMP_SetupURL error\n");
        if(self.rtmpDelegate) {
            [self.rtmpDelegate evenCallbackWithEvent:2002];
        }
        break;
    }

    if (!RTMP_Connect(pPlayRtmp, NULL) || !RTMP_ConnectStream(pPlayRtmp, 0)) {
        NSLog(@"Play RTMP_Connect or RTMP_ConnectStream error\n");
        if(self.rtmpDelegate) {
            [self.rtmpDelegate evenCallbackWithEvent:2002];
        }
        break;
    }

    if(self.rtmpDelegate) {
        [self.rtmpDelegate evenCallbackWithEvent:2001];
    }
    NSLog(@"Player RTMP_Connected \n");

    RTMPPacket rtmp_pakt = {0};
    isStartPlay = YES;
    while (isStartPlay && RTMP_ReadPacket(pPlayRtmp, &rtmp_pakt)) {
        if (RTMPPacket_IsReady(&rtmp_pakt)) {
            if (!rtmp_pakt.m_nBodySize) {
                continue;
            }
            if (rtmp_pakt.m_packetType == RTMP_PACKET_TYPE_AUDIO) {
                NSLog(@"Audio size = %d head = %d time = %d", rtmp_pakt.m_nBodySize, rtmp_pakt.m_body[0], rtmp_pakt.m_nTimeStamp);
                speex_bits_read_from(&dbits, rtmp_pakt.m_body + 1, rtmp_pakt.m_nBodySize - 1);
                speex_decode_int(dec_state, &dbits, input_buffer);  //audioData in the input_buffer
                //do something...



            } else if (rtmp_pakt.m_packetType == RTMP_PACKET_TYPE_VIDEO) {
                // 处理视频数据包
            } else if (rtmp_pakt.m_packetType == RTMP_PACKET_TYPE_INVOKE) {
                // 处理invoke包
                NSLog(@"RTMP_PACKET_TYPE_INVOKE");
                RTMP_ClientPacket(pPlayRtmp,&rtmp_pakt);
            } else if (rtmp_pakt.m_packetType == RTMP_PACKET_TYPE_INFO) {
                // 处理信息包
                //NSLog(@"RTMP_PACKET_TYPE_INFO");
            } else if (rtmp_pakt.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO) {
                // 其他数据
                int index = 0;
                while (1) {
                    int StreamType; //1-byte
                    int MediaSize; //3-byte
                    int TiMMER; //3-byte
                    int Reserve; //4-byte
                    char* MediaData; //MediaSize-byte
                    int TagLen; //4-byte

                    StreamType = rtmp_pakt.m_body[index];
                    index += 1;
                    MediaSize = bigThreeByteToInt(rtmp_pakt.m_body + index);
                    index += 3;
                    TiMMER = bigThreeByteToInt(rtmp_pakt.m_body + index);
                    index += 3;
                    Reserve = bigFourByteToInt(rtmp_pakt.m_body + index);
                    index += 4;
                    MediaData = rtmp_pakt.m_body + index;
                    index += MediaSize;
                    TagLen = bigFourByteToInt(rtmp_pakt.m_body + index);
                    index += 4;
                    //NSLog(@"bodySize:%d   index:%d",rtmp_pakt.m_nBodySize,index);
                    //LOGI("StreamType:%d MediaSize:%d  TiMMER:%d TagLen:%d\n", StreamType, MediaSize, TiMMER, TagLen);
                    if (StreamType == 0x08) {
                        //音频包
                        //int MediaSize = bigThreeByteToInt(rtmp_pakt.m_body+1);
                        //  LOGI("FLASH audio size:%d  head:%d time:%d\n", MediaSize, MediaData[0], TiMMER);
                        speex_bits_read_from(&dbits, MediaData + 1, MediaSize - 1);
                        speex_decode_int(dec_state, &dbits, input_buffer);

                        //[mAudioPlayer putAudioData:input_buffer];
                        //  putAudioQueue(output_buffer,dec_frame_size);
                    } else if (StreamType == 0x09) {
                        //视频包
                        //  LOGI( "video size:%d  head:%d\n", MediaSize, MediaData[0]);
                    }
                    if (rtmp_pakt.m_nBodySize == index) {
                        break;
                    }
                }
            }
            RTMPPacket_Free(&rtmp_pakt);
        }
    }
    if (isStartPlay) {
        if(self.rtmpDelegate) {
            [self.rtmpDelegate evenCallbackWithEvent:2005];
        }
        isStartPlay = NO;
    }
} while (0);
[mAudioPlayer stopPlay];
if (self.rtmpDelegate) {
    [self.rtmpDelegate evenCallbackWithEvent:2004];
}
if (RTMP_IsConnected(pPlayRtmp)) {
    RTMP_Close(pPlayRtmp);
}
RTMP_Free(pPlayRtmp);
free(input_buffer);
speex_bits_destroy(&dbits);
speex_decoder_destroy(dec_state);

}

This is my custom method. RtmpURL is a NSString'S object, it is a stream server address. Use this method, I can get the encoded of audio stream from the server, after that, I use speex decoder to decode the data that I got, just like this:

//init speex decoder and config;
    speex_bits_init(&dbits);
    dec_state = speex_decoder_init(&speex_wb_mode);

    speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE, &dec_frame_size);

    input_buffer = malloc(dec_frame_size * sizeof(short));

    NSLog(@"Init Speex decoder success frame_size = %d",dec_frame_size);
 if (rtmp_pakt.m_packetType == RTMP_PACKET_TYPE_AUDIO) {
                NSLog(@"Audio size = %d head = %d time = %d", rtmp_pakt.m_nBodySize, rtmp_pakt.m_body[0], rtmp_pakt.m_nTimeStamp);
                speex_bits_read_from(&dbits, rtmp_pakt.m_body + 1, rtmp_pakt.m_nBodySize - 1);
                speex_decode_int(dec_state, &dbits, input_buffer);  //audioData in the input_buffer
                //do something...



            }

Now, decoded of audio data are stored in the input_buffer, and this is my confusion. How do I use the AudioUnit to play the audio data.And this is my playback callback function:

OSStatus playCallback(void                            *inRefCon,
                  AudioUnitRenderActionFlags      *ioActionFlags,
                  const AudioTimeStamp            *inTimeStamp,
                  UInt32                          inBusNumber,
                  UInt32                          inNumberFrames,
                  AudioBufferList                 *ioData){
AudioPlayer *THIS = (__bridge AudioPlayer *)inRefCon;
//How do I use the AudioUnit to play the audio stream from server?

return noErr;

}

I hope some friends to solve my confusion, if you were used the audioUnit, Thank you so much!

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Shen.Xs
  • 13
  • 4

2 Answers2

0

There are some very good resources here link

sandy
  • 344
  • 3
  • 12
0

In your playCallback, you need to copy the audio into the buffer ioData. For example

memcpy (ioData->mBuffers[0].mData,  input_buffer + offset, numBytes );
// increase offset based on how many frames it requests.

The input variable inNumberFrames is the number of frames that it is ready for. This might be less than the number of frames in input_buffer. So you need to keep track of your play position.

I do not know your audio format this specified in your audio stream basic description. You need to calculate how many bytes need copied considering mono/stereo, number of bytes per channel, and of course inNumberFrames.

jaybers
  • 1,991
  • 13
  • 18