2011-07-07 37 views
8

Đã đập đầu tôi vào vấn đề này vào buổi sáng.Phát âm thanh từ một luồng dữ liệu liên tục (iOS)

Tôi đã thiết lập kết nối với nguồn dữ liệu trả về dữ liệu âm thanh (Đây là thiết bị ghi, do đó không có độ dài được đặt trên dữ liệu. Dữ liệu chỉ truyền trực tuyến. Như, nếu bạn mở luồng tới đài)

và tôi đã quản lý để nhận tất cả các gói dữ liệu trong mã của mình. Bây giờ tôi chỉ cần chơi nó. Tôi muốn phát dữ liệu đang đến, vì vậy tôi không muốn xếp hàng một vài phút hoặc bất cứ thứ gì, tôi muốn sử dụng dữ liệu tôi đang nhận tại thời điểm chính xác đó và chơi nó.

Bây giờ tôi đã tìm kiếm tất cả các buổi sáng tìm kiếm các ví dụ khác nhau nhưng không có thực sự được phân loại.

trong

  • kết nối (void): (NSURLConnection ) kết nối didReceiveData: (NSData) dữ liệu {

chức năng, các "dữ liệu" gói là gói âm thanh. Tôi đã thử phát trực tiếp nó với AVPlayer, MFVideoPlayer nhưng không có gì đã làm việc cho tôi cho đến nay. Cũng đã cố gắng nhìn vào Audiostreamer của mattgallagher nhưng vẫn không thể đạt được nó.

Bất kỳ ai ở đây đều có thể trợ giúp, có một số ví dụ làm việc (tốt hơn)?

Trả lời

2

Cẩn thận: Câu trả lời dưới đây chỉ hợp lệ nếu bạn nhận dữ liệu PCM từ máy chủ. Đây là tất nhiên không bao giờ xảy ra. Đó là lý do tại sao giữa việc hiển thị âm thanh và nhận dữ liệu bạn cần một bước khác: chuyển đổi dữ liệu.

Tùy thuộc vào định dạng, điều này có thể ít nhiều phức tạp, nhưng nói chung bạn nên sử dụng Dịch vụ chuyển đổi âm thanh cho bước này.

Bạn chỉ nên sử dụng -(void)connection:(NSURLConnection)connection didReceiveData:(NSData)data để lấp đầy bộ đệm có dữ liệu đến từ máy chủ, việc chơi nó không nên liên quan đến phương pháp này.

Bây giờ, để phát dữ liệu bạn đã lưu trữ trong bộ nhớ bằng bộ đệm, bạn cần sử dụng RemoteIO và các đơn vị âm thanh. Here is a good, comprehensive tutorial. Bạn có thể xóa phần "bản ghi" khỏi hướng dẫn vì bạn không thực sự cần nó.

Như bạn có thể thấy, họ xác định một callback để phát lại:

callbackStruct.inputProc = playbackCallback; 
callbackStruct.inputProcRefCon = self; 
status = AudioUnitSetProperty(audioUnit, 
           kAudioUnitProperty_SetRenderCallback, 
           kAudioUnitScope_Global, 
           kOutputBus, 
           &callbackStruct, 
           sizeof(callbackStruct)); 

playbackCallback chức năng trông như thế này:

static OSStatus playbackCallback(void *inRefCon, 
          AudioUnitRenderActionFlags *ioActionFlags, 
          const AudioTimeStamp *inTimeStamp, 
          UInt32 inBusNumber, 
          UInt32 inNumberFrames, 
          AudioBufferList *ioData) { 

    for (int i = 0 ; i < ioData->mNumberBuffers; i++){  
     AudioBuffer buffer = ioData->mBuffers[i]; 
     unsigned char *frameBuffer = buffer.mData; 
     for (int j = 0; j < inNumberFrames*2; j++){ 
      frameBuffer[j] = getNextPacket();//this here is a function you have to make to get the next chunk of bytes available in the stream buffer 
     } 
    } 

    return noErr; 
} 

Về cơ bản những gì nó làm là để lấp đầy bộ đệm ioData với đoạn byte tiếp theo cần được phát. Hãy chắc chắn để không ra (im lặng) bộ đệm ioData nếu không có dữ liệu mới để phát (trình phát bị tắt tiếng nếu không đủ dữ liệu trong bộ đệm luồng).

Ngoài ra, bạn có thể đạt được điều tương tự với OpenAL bằng cách sử dụng alSourceQueueBuffersalSourceUnqueueBuffers để xếp hàng bộ đệm cái khác.

Vậy đó. Happy codding!

+0

cab bạn giải thích cách chơi ausio từ các byte sắp tới như byte đến trong nsinputstream chức năng đọc – sajwan

+0

@valentin Radu tôi đang bối rối để làm cho bộ đệm âm thanh từ tôi đang nhận dữ liệu từ phương pháp này và một điều khác làm thế nào để gọi đó phát lại cuộc gọi ? cảm ơn trước được loại để hữu ích! –

Các vấn đề liên quan