From 8680f58f89802303bace6f20bce35aba2e8b78ec Mon Sep 17 00:00:00 2001 From: arpi Date: Fri, 20 Sep 2002 18:26:54 +0000 Subject: "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 git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@7450 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libao2/ao_nas.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/libao2/ao_nas.c b/libao2/ao_nas.c index 7a37ee82c8..aa95ab6655 100644 --- a/libao2/ao_nas.c +++ b/libao2/ao_nas.c @@ -108,6 +108,7 @@ struct ao_nas_data { 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 @@ static int nas_readBuffer(struct ao_nas_data *nas_data, int num) 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 @@ static int init(int rate,int channels,int format,int flags) 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 @@ static void uninit(){ 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 @@ static int play(void* data,int len,int flags) 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); -- cgit v1.2.3