# HG changeset patch # User arpi # Date 1032546414 0 # Node ID 28785e6e6900a93a2a1a26e6dc1a3a99bce2e4e1 # Parent b464616d40b51b381e941f1ac6768216806aca7f "One can cause a permanent hang on a seek, and the other just causes general jerkiness because the writer thread was holding a lock during the time it was writing to the network." patch by Sidik Isani diff -r b464616d40b5 -r 28785e6e6900 libao2/ao_nas.c --- a/libao2/ao_nas.c Fri Sep 20 15:46:13 2002 +0000 +++ b/libao2/ao_nas.c Fri Sep 20 18:26:54 2002 +0000 @@ -108,6 +108,7 @@ int flow_paused; void *client_buffer; + void *server_buffer; int client_buffer_size; int client_buffer_used; int server_buffer_size; @@ -148,15 +149,29 @@ if (nas_data->client_buffer_used < num) num = nas_data->client_buffer_used; - AuWriteElement(nas_data->aud, nas_data->flow, 0, num, nas_data->client_buffer, AuFalse, &as); + /* + * It is not appropriate to call AuWriteElement() here because the + * buffer is locked and delays writing to the network will cause + * other threads to block waiting for buffer_mutex. Instead the + * data is copied to "server_buffer" and written it to the network + * outside of the locked section of code. + * + * (Note: Rather than these two buffers, a single circular buffer + * could eliminate the memcpy/memmove steps.) + */ + memcpy(nas_data->server_buffer, nas_data->client_buffer, num); + + nas_data->client_buffer_used -= num; + nas_data->server_buffer_used += num; + memmove(nas_data->client_buffer, nas_data->client_buffer + num, nas_data->client_buffer_used); + pthread_mutex_unlock(&nas_data->buffer_mutex); + + /* + * Now write the new buffer to the network. + */ + AuWriteElement(nas_data->aud, nas_data->flow, 0, num, nas_data->server_buffer, AuFalse, &as); if (as != AuSuccess) nas_print_error(nas_data->aud, "nas_readBuffer(): AuWriteElement", as); - else { - nas_data->client_buffer_used -= num; - nas_data->server_buffer_used += num; - memmove(nas_data->client_buffer, nas_data->client_buffer + num, nas_data->client_buffer_used); - } - pthread_mutex_unlock(&nas_data->buffer_mutex); if (nas_data->flow_paused) { AuPauseFlow(nas_data->aud, nas_data->flow, &as); @@ -333,6 +348,7 @@ nas_data->client_buffer_size = NAS_BUFFER_SIZE; nas_data->client_buffer = malloc(nas_data->client_buffer_size); nas_data->server_buffer_size = NAS_BUFFER_SIZE; + nas_data->server_buffer = malloc(nas_data->server_buffer_size); ao_data.samplerate = rate; ao_data.channels = channels; @@ -403,6 +419,7 @@ AuCloseServer(nas_data->aud); nas_data->aud = 0; free(nas_data->client_buffer); + free(nas_data->server_buffer); } // stop playing and empty buffers (for seeking/pause) @@ -478,7 +495,12 @@ if (as != AuSuccess) nas_print_error(nas_data->aud, "play(): AuStartFlow", as); nas_data->flow_stopped = 0; - while (!nas_empty_event_queue(nas_data)); // wait for first buffer underrun event + /* + * Do not continue to wait if there is nothing in the server + * buffer. (The event never happens and mplayer can freeze.) + */ + while (nas_data->server_buffer_used > 0 && + !nas_empty_event_queue(nas_data)); // wait for first buffer underrun event } pthread_mutex_lock(&nas_data->buffer_mutex);