comparison libao2/ao_nas.c @ 7449:28785e6e6900

"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 <lksi@cfht.hawaii.edu>
author arpi
date Fri, 20 Sep 2002 18:26:54 +0000
parents 34d5c9a67b94
children 09ccf6147d76
comparison
equal deleted inserted replaced
7448:b464616d40b5 7449:28785e6e6900
106 106
107 int flow_stopped; 107 int flow_stopped;
108 int flow_paused; 108 int flow_paused;
109 109
110 void *client_buffer; 110 void *client_buffer;
111 void *server_buffer;
111 int client_buffer_size; 112 int client_buffer_size;
112 int client_buffer_used; 113 int client_buffer_used;
113 int server_buffer_size; 114 int server_buffer_size;
114 int server_buffer_used; 115 int server_buffer_used;
115 pthread_mutex_t buffer_mutex; 116 pthread_mutex_t buffer_mutex;
146 return 0; 147 return 0;
147 } 148 }
148 if (nas_data->client_buffer_used < num) 149 if (nas_data->client_buffer_used < num)
149 num = nas_data->client_buffer_used; 150 num = nas_data->client_buffer_used;
150 151
151 AuWriteElement(nas_data->aud, nas_data->flow, 0, num, nas_data->client_buffer, AuFalse, &as); 152 /*
153 * It is not appropriate to call AuWriteElement() here because the
154 * buffer is locked and delays writing to the network will cause
155 * other threads to block waiting for buffer_mutex. Instead the
156 * data is copied to "server_buffer" and written it to the network
157 * outside of the locked section of code.
158 *
159 * (Note: Rather than these two buffers, a single circular buffer
160 * could eliminate the memcpy/memmove steps.)
161 */
162 memcpy(nas_data->server_buffer, nas_data->client_buffer, num);
163
164 nas_data->client_buffer_used -= num;
165 nas_data->server_buffer_used += num;
166 memmove(nas_data->client_buffer, nas_data->client_buffer + num, nas_data->client_buffer_used);
167 pthread_mutex_unlock(&nas_data->buffer_mutex);
168
169 /*
170 * Now write the new buffer to the network.
171 */
172 AuWriteElement(nas_data->aud, nas_data->flow, 0, num, nas_data->server_buffer, AuFalse, &as);
152 if (as != AuSuccess) 173 if (as != AuSuccess)
153 nas_print_error(nas_data->aud, "nas_readBuffer(): AuWriteElement", as); 174 nas_print_error(nas_data->aud, "nas_readBuffer(): AuWriteElement", as);
154 else {
155 nas_data->client_buffer_used -= num;
156 nas_data->server_buffer_used += num;
157 memmove(nas_data->client_buffer, nas_data->client_buffer + num, nas_data->client_buffer_used);
158 }
159 pthread_mutex_unlock(&nas_data->buffer_mutex);
160 175
161 if (nas_data->flow_paused) { 176 if (nas_data->flow_paused) {
162 AuPauseFlow(nas_data->aud, nas_data->flow, &as); 177 AuPauseFlow(nas_data->aud, nas_data->flow, &as);
163 if (as != AuSuccess) 178 if (as != AuSuccess)
164 nas_print_error(nas_data->aud, "nas_readBuffer(): AuPauseFlow", as); 179 nas_print_error(nas_data->aud, "nas_readBuffer(): AuPauseFlow", as);
331 } 346 }
332 347
333 nas_data->client_buffer_size = NAS_BUFFER_SIZE; 348 nas_data->client_buffer_size = NAS_BUFFER_SIZE;
334 nas_data->client_buffer = malloc(nas_data->client_buffer_size); 349 nas_data->client_buffer = malloc(nas_data->client_buffer_size);
335 nas_data->server_buffer_size = NAS_BUFFER_SIZE; 350 nas_data->server_buffer_size = NAS_BUFFER_SIZE;
351 nas_data->server_buffer = malloc(nas_data->server_buffer_size);
336 352
337 ao_data.samplerate = rate; 353 ao_data.samplerate = rate;
338 ao_data.channels = channels; 354 ao_data.channels = channels;
339 ao_data.buffersize = NAS_BUFFER_SIZE * 2; 355 ao_data.buffersize = NAS_BUFFER_SIZE * 2;
340 ao_data.outburst = NAS_FRAG_SIZE; 356 ao_data.outburst = NAS_FRAG_SIZE;
401 nas_print_error(nas_data->aud, "uninit(): AuStopFlow", as); 417 nas_print_error(nas_data->aud, "uninit(): AuStopFlow", as);
402 } 418 }
403 AuCloseServer(nas_data->aud); 419 AuCloseServer(nas_data->aud);
404 nas_data->aud = 0; 420 nas_data->aud = 0;
405 free(nas_data->client_buffer); 421 free(nas_data->client_buffer);
422 free(nas_data->server_buffer);
406 } 423 }
407 424
408 // stop playing and empty buffers (for seeking/pause) 425 // stop playing and empty buffers (for seeking/pause)
409 static void reset(){ 426 static void reset(){
410 AuStatus as; 427 AuStatus as;
476 493
477 AuStartFlow(nas_data->aud, nas_data->flow, &as); 494 AuStartFlow(nas_data->aud, nas_data->flow, &as);
478 if (as != AuSuccess) 495 if (as != AuSuccess)
479 nas_print_error(nas_data->aud, "play(): AuStartFlow", as); 496 nas_print_error(nas_data->aud, "play(): AuStartFlow", as);
480 nas_data->flow_stopped = 0; 497 nas_data->flow_stopped = 0;
481 while (!nas_empty_event_queue(nas_data)); // wait for first buffer underrun event 498 /*
499 * Do not continue to wait if there is nothing in the server
500 * buffer. (The event never happens and mplayer can freeze.)
501 */
502 while (nas_data->server_buffer_used > 0 &&
503 !nas_empty_event_queue(nas_data)); // wait for first buffer underrun event
482 } 504 }
483 505
484 pthread_mutex_lock(&nas_data->buffer_mutex); 506 pthread_mutex_lock(&nas_data->buffer_mutex);
485 maxbursts = (nas_data->client_buffer_size - 507 maxbursts = (nas_data->client_buffer_size -
486 nas_data->client_buffer_used) / ao_data.outburst; 508 nas_data->client_buffer_used) / ao_data.outburst;