2010-04-07 12 views
11

Estoy escribiendo un cliente de escritorio remoto para el iPhone y estoy tratando de implementar la redirección de audio.
El cliente está conectado al servidor a través de una conexión de socket, y el servidor envía 32K fragmentos de datos PCM a la vez.Uso de Audio Queue Services para reproducir datos PCM a través de una conexión de socket

Estoy tratando de usar AQS para reproducir los datos y reproduce los primeros dos segundos (vale 1 buffer). Sin embargo, dado que la siguiente porción de datos aún no ha llegado a través del socket, el siguiente AudioQueueBuffer está vacío. Cuando entran los datos, llenó el siguiente buffer disponible con los datos y los encola con AudioQueueEnqueueBuffer. Sin embargo, nunca juega estos búferes.

¿La cola deja de reproducirse si no hay búferes en la cola, incluso si luego agrega un búfer?

Aquí está la parte correspondiente del código:

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--; 
} 

Gracias!

Respuesta

0

En general, cuando se utiliza buffers de audio circulares, debe impedir que las memorias intermedias de empotre. Si no tiene los datos necesarios (debido, por ejemplo, a la congestión de la red), intente rellenar los datos de audio con silencio o pause la reproducción de audio.

Podría ser que una vez que su cadena de búfer se corra, necesita reiniciar la reproducción. En realidad, nunca he procesado el buffer de AudioQueue, pero recuerdo de la programación de Win32 que este fue el caso, así que no dude en corregirme si me equivoco.

+3

No tiene que rellenar nada con silencio. Si no tiene ningún dato que volver a poner en la cola cuando se llama a su devolución de llamada, simplemente no coloque ningún dato allí. Si su cola se queda sin datos, guardará silencio por sí solo hasta que vuelva a poner los datos en cola. Si todos los buffers están fuera de la cola, su devolución de llamada no se volverá a llamar, pero aún puede poner datos en la cola desde otra función que no sea la devolución de llamada (por ejemplo, tan pronto como los datos vuelvan). Este no es el problema del cartel. Su problema es que solo tiene un buffer en la cola para empezar. Necesita al menos 2. – Mecki

+0

Gracias Mecki, tengo un problema similar, y aunque la solución aún no se ha escrito, al menos esto apunta en la dirección correcta ... – Nick

1

El uso de los servicios de colas de audio de CoreAudio se simplifica enormemente al garantizar que siempre vuelva a poner en cola cada búfer tan pronto como finalice la reproducción haciéndolo en la devolución de llamada que se activa cuando finaliza la reproducción. Los datos de audio deben estar en un búfer circular separado, ya que se recibe de la red para que la red y el código de audio no se acoplen directamente.

Para asegurarse de no dejar caer el audio, ponga en cola una cantidad fija de búferes con datos; esto actúa como un buffer de fluctuación. No inicie la reproducción hasta que todos los búferes estén en cola. Tan pronto como termine de reproducirse cada buffer, vuelva a ponerlo en cola inmediatamente con el siguiente paquete de datos. Si no hay datos disponibles, simplemente ponga en cola un búfer de silencio; dado que los paquetes de audio que llegan eventualmente se pondrán al día, esto solo tiene el efecto de reducir el audio caído a expensas de una latencia adicional.

0

Encuentro estúpido que puedo publicar respuestas pero no comentarios aquí si no tengo suficientes puntos. Solo quería agregar a la siguiente respuesta:

"Podría ser que una vez que su cadena de búfer no funciona correctamente, necesita reiniciar la reproducción. Nunca he bajado realmente el búfer de AudioQueue, pero recuerdo de la programación de Win32 que esto era el caso, así que siéntete libre de corregirme si me equivoco ".

He probado este escenario en mi reproductor de audio que he hecho recientemente. Hice un decodificador FLAC desde cero, y solo admite canciones de 16 bits en este momento. Si me tropiezo con una canción de 24 bits, sigo perdiendo la sincronización con la canción que estoy reproduciendo, no se reproducirá en absoluto, y eso puede tomar cualquier cantidad de tiempo, digamos 30 segundos para hacer un ejemplo, para recuperar. Esto hace que las colas de audio pasen realmente mal, y cuando finalmente empiezo a enviar buffers nuevamente a las colas de audio, lleva 30 segundos de silencio en la próxima canción para que vuelva a sonar.

Esto es solo mi observación, y todavía no he pensado mucho en por qué estoy observando este comportamiento. Tal vez arroje muestras para coincidir con el conteo de muestras. AudioQueue cree que debería estar jugando en ese momento, ¿qué perdió durante la inanición? Mi reproductor de audio parece reproducir rápidamente la canción hasta que llega al punto en que quiere volver a tocar.

EDITAR: Mientras publique un nuevo búfer para cada devolución de llamada, nunca necesitará reiniciar la reproducción ni nada. En mi reproductor, si no he terminado de procesar un búfer cuando el siguiente búfer es "devuelto", el hilo de ese búfer se bloqueará hasta que el primer búfer se complete. Esto se hace con NSLock. Esta es la razón principal por la cual AudioQueues está severamente muerto de hambre cuando pierdo la sincronización cuando mi reproductor aún no comprende los FLAC de 24 bits. NSLock también previene cualquier condición de carrera cuando AudioQueue le da más buffers para llenar. Yo uso 3 búferes con baja latencia. Una latencia demasiado baja produce un silencio total, por lo que debe encontrar un "buen tamaño" para su sistema.

Cuestiones relacionadas