2010-04-07 4 views
11

iPhone 용 원격 데스크톱 클라이언트를 작성 중이므로 오디오 리디렉션을 구현하려고합니다.
클라이언트가 소켓 연결을 통해 서버에 연결되어 있고 서버가 한 번에 32K 개의 PCM 데이터 청크를 보냅니다.오디오 대기열 서비스를 사용하여 소켓 연결을 통해 PCM 데이터 재생

AQS를 사용하여 데이터를 재생하려고하는데 처음 2 초 (1 버퍼 값)를 재생합니다. 그러나 다음 덩어리의 데이터가 아직 소켓을 통해 들어오지 않았으므로 다음 AudioQueueBuffer는 비어 있습니다. 데이터가 들어 오면 데이터로 다음 사용 가능한 버퍼를 채우고 AudioQueueEnqueueBuffer로 큐에 넣습니다. 그러나 이러한 버퍼는 재생되지 않습니다.

나중에 버퍼를 추가하더라도 큐에 버퍼가 없으면 큐 재생이 멈 춥니 다?

여기에 코드의 관련 부분입니다 :

void 
wave_out_write(STREAM s, uint16 tick, uint8 index) 
{ 

    if(items_in_queue == NUM_BUFFERS){ 
     return; 
    } 
    if(!playState.busy){ 
     OSStatus status; 
     status = AudioQueueNewOutput(&playState.dataFormat, AudioOutputCallback, &playState, CFRunLoopGetCurrent(), NULL, 0, &playState.queue); 

     if(status == 0){ 
      for(int i=0; i<NUM_BUFFERS; i++){ 
       AudioQueueAllocateBuffer(playState.queue, 40000, &playState.buffers[i]); 

      } 
      AudioQueueAddPropertyListener(playState.queue, kAudioQueueProperty_IsRunning, MyAudioQueuePropertyListenerProc, &playState); 

      status = AudioQueueStart(playState.queue, NULL); 
      if(status ==0){ 
       playState.busy = True; 
      } 
      else{ 
       return; 
      } 
     } 
     else{ 
      return; 
     } 
    } 
    playState.buffers[queue_hi]->mAudioDataByteSize = s->size; 

    memcpy(playState.buffers[queue_hi]->mAudioData, s->data, s->size); 

    AudioQueueEnqueueBuffer(playState.queue, playState.buffers[queue_hi], 0, 0); 
    queue_hi++; 
    queue_hi = queue_hi % NUM_BUFFERS; 
    items_in_queue++; 
} 


void AudioOutputCallback(void* inUserData, AudioQueueRef outAQ, AudioQueueBufferRef outBuffer) 
{ 
    PlayState *playState = (PlayState *)inUserData; 
    items_in_queue--; 
} 

감사합니다!

답변

0

는 일반적으로, 당신은 underrunning에서 버퍼를 방지해야한다. 네트워크 혼잡 등으로 인해 필요한 데이터가 부족한 경우 오디오 데이터를 무음으로 채우거나 오디오 재생을 일시 중지하십시오.

일단 버퍼 체인이 언더런하면 재생을 다시 시작해야 할 수 있습니다. 필자는 실제로 AudioQueue 버퍼를 축소 한 적이 없지만, Win32 프로그래밍에서 이런 경우가 있음을 기억합니다. 틀렸다고 생각하면 자유롭게 교정 해주십시오.

+3

아무 소리도 들리지 않아도됩니다. 콜백이 호출 될 때 큐에 다시 넣을 데이터가 없다면 데이터를 저장하지 마십시오. 큐에 데이터가 부족한 경우 데이터를 다시 대기열에 넣기 전까지는 자체적으로 무음이 재생됩니다. 모든 버퍼가 대기열에서 벗어난 경우 콜백이 다시 호출되지 않지만 콜백이 아닌 다른 함수 (예 : 데이터가 다시 도착하자마자)에서 대기열에 데이터를 계속 대기열에 넣을 수 있습니다. 이것은 포스터의 문제가 아닙니다. 그의 문제는 큐에 하나의 버퍼 만 가지고 있다는 것입니다. 적어도 2가 필요합니다. – Mecki

+0

감사합니다. Mecki, 비슷한 문제가 있습니다. 솔루션이 아직 작성되지 않았지만, 적어도 올바른 방향으로이 점을 지적하십시오 ... – Nick

1

CoreAudio의 오디오 대기열 서비스는 재생이 끝나면 시작되는 콜백에서 재생이 끝나면 모든 버퍼를 항상 대기열에 두도록하여 간단 해집니다. 오디오 데이터는 네트워크에서 수신되는 별도의 순환 버퍼에 있어야 네트워크와 오디오 코드가 직접 결합되지 않습니다.

오디오를 제거하지 않으려면 고정 된 수의 버퍼를 데이터와 함께 대기열에 두십시오. 이는 지터 버퍼의 역할을합니다. 모든 버퍼가 대기 상태가 될 때까지 재생을 시작하지 마십시오. 각 버퍼의 재생이 끝나면 즉시 다음 데이터 패킷으로 다시 대기열에 넣습니다. 사용할 수있는 데이터가 없으면 무음 버퍼를 대기 상태로 만듭니다. 도착하는 오디오 패킷이 결국 따라 잡을 것이기 때문에 오디오 지연을 줄이면서 오디오를 줄이는 효과 만 있습니다.

0

점수가 충분하지 않은 경우 답변을 게시 할 수 있지만 의견을 게시 할 수 없다는 것을 알게됩니다. 난 그냥 다음 답변을 추가하려면 :

"일단 당신의 버퍼 체인 underruns, 당신은 재생을 다시 시작해야 할 수도 있습니다. 나는 AudioQueue 버퍼를 실제로 underrunned 적이 있지만, 나는 이것이 Win32 프로그래밍에서 기억 해요 케이스, 그래서 내가 틀렸다면 나를 바로 잡아주세요. "

저는 오디오 플레이어에서이 시나리오를 실제로 테스트했습니다. 나는 처음부터 FLAC 디코더를 만들었고, 현재는 16 비트 곡만 지원합니다. 만약 내가 24 비트의 노래에 비틀 거린다면, 나는 연주하고있는 노래와 동기화를 잃지 않습니다. 전혀 재생되지 않을 것이고, 그것은 회복하는데 예를 들자면 30 초가 걸릴 것입니다. 이것은 Audio Queues를 정말로 나쁘게 만듭니다. 그리고 마침내 버퍼를 오디오 대기열로 다시 보내기 시작할 때 30 초 동안 무음을 사용하여 다음 곡을 다시 재생하여 다시 재생할 수 있습니다.

이것은 단지 나의 관찰 일 뿐이며, 나는 왜 내가이 행동을 관찰하고 있는지에 대해 많은 생각을하지 못했습니다. 어쩌면 그것은 Sample Count와 일치하는 샘플을 버릴 수 있습니다. AudioQueue는 현재 재생 중이어야한다고 생각합니다 - 기아 동안 잃어버린 것입니까? 내 오디오 플레이어가 다시 재생하고 싶은 지점에 도달 할 때까지 음악을 빨리 재생하는 것 같습니다.

편집 : 모든 콜백에 대해 새 버퍼를 게시하는 한 재생 또는 기타 사항을 다시 시작할 필요가 없습니다. 내 플레이어에서 다음 버퍼가 '콜백 될'때 버퍼를 처리하지 않으면 첫 번째 버퍼가 채워질 때까지 해당 버퍼의 스레드가 차단됩니다. 이것은 NSLock으로 수행됩니다. 이것은 내 플레이어가 아직 24 비트 FLAC을 이해하지 못할 때 동기화가 끊어 질 때 AudioQueues가 심각하게 굶주리는 주된 이유입니다. NSLock은 또한 AudioQueue가 더 많은 버퍼를 채울 때 경쟁 조건을 방지합니다. 낮은 대기 시간으로 3 개의 버퍼를 사용합니다. 대기 시간이 너무 짧으면 완전한 침묵을 제공하므로 시스템에 적합한 크기를 찾아야합니다.

관련 문제