changeset 7626:09ccf6147d76

Small error, the buffer size got set incorrectly. (Now BUFFER_SIZE * 3 instead of BUFFER_SIZE * 2) patch by Tobias Diedrich <td@sim.uni-hannover.de>
author arpi
date Sun, 06 Oct 2002 17:30:38 +0000
parents 0f1691d27d75
children 382b28368402
files libao2/ao_nas.c
diffstat 1 files changed, 47 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/libao2/ao_nas.c	Sun Oct 06 17:18:57 2002 +0000
+++ b/libao2/ao_nas.c	Sun Oct 06 17:30:38 2002 +0000
@@ -10,6 +10,20 @@
  * largely rewritten and used for this
  * plugin by Tobias Diedrich
  *
+ * Theory of operation:
+ *
+ * The NAS consists of two parts, a server daemon and a client.
+ * We setup the server to use a buffer of size NAS_BUFFER_SIZE
+ * with a low watermark of NAS_BUFFER_SIZE - NAS_FRAG_SIZE.
+ * Upon starting the flow the server will generate a buffer underrun
+ * event and the event handler will fill the buffer for the first time.
+ * Now the server will generate a lowwater event when the server buffer
+ * falls below the low watermark value. The event handler gets called
+ * again and refills the buffer by the number of bytes requested by the
+ * server (usually a multiple of 4096). To prevent stuttering on
+ * startup (start of playing, seeks, unpausing) the client buffer should
+ * be bigger than the server buffer. (For debugging we also do some
+ * accounting of what we think how much of the server buffer is filled)
  */
 
 #include <stdio.h>
@@ -106,6 +120,7 @@
 
 	int flow_stopped;
 	int flow_paused;
+	int expect_underrun;
 
 	void *client_buffer;
 	void *server_buffer;
@@ -193,8 +208,6 @@
 	nas_data->client_buffer_used += len;
 
 	pthread_mutex_unlock(&nas_data->buffer_mutex);
-	if (nas_data->server_buffer_used < nas_data->server_buffer_size)
-		nas_readBuffer(nas_data, nas_data->server_buffer_size - nas_data->server_buffer_used);
 }
 
 static int nas_empty_event_queue(struct ao_nas_data *nas_data)
@@ -247,12 +260,13 @@
 
 	switch (ev->type) {
 	case AuEventTypeElementNotify:
-		DPRINTF("ao_nas: event_handler(): kind %s state %s->%s reason %s numbytes %d\n",
+		DPRINTF("ao_nas: event_handler(): kind %s state %s->%s reason %s numbytes %d expect_underrun %d\n",
 			nas_elementnotify_kind(event->kind),
 			nas_state(event->prev_state),
 			nas_state(event->cur_state),
 			nas_reason(event->reason),
-			event->num_bytes);
+			event->num_bytes,
+			nas_data->expect_underrun);
 
 		nas_data->server_buffer_used -= event->num_bytes;
 		if (nas_data->server_buffer_used < 0)
@@ -267,8 +281,15 @@
 				switch (event->reason) {
 				case AuReasonUnderrun:
 					// buffer underrun -> refill buffer
+					if (nas_data->expect_underrun)
+						nas_data->expect_underrun = 0;
+					else
+						fprintf(stderr, "ao_nas: Buffer underrun.\n"
+							"Possible reasons are network congestion or your NAS server is too slow.\n"
+							"Try renicing your nasd to e.g. -15.\n");
 					nas_data->server_buffer_used = 0;
-					nas_readBuffer(nas_data, nas_data->server_buffer_size - nas_data->server_buffer_used);
+					if (nas_readBuffer(nas_data, nas_data->server_buffer_size - nas_data->server_buffer_used) == 0)
+						nas_data->flow_stopped = 1;
 					break;
 				default:
 					break;
@@ -345,14 +366,15 @@
 		return 0;
 	}
 
-	nas_data->client_buffer_size = NAS_BUFFER_SIZE;
+	nas_data->client_buffer_size = NAS_BUFFER_SIZE*2;
 	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;
-	ao_data.buffersize = NAS_BUFFER_SIZE * 2;
+	ao_data.buffersize = nas_data->client_buffer_size +
+			     nas_data->server_buffer_size;
 	ao_data.outburst = NAS_FRAG_SIZE;
 	ao_data.bps = rate * bytes_per_sample;
 
@@ -398,6 +420,7 @@
 				nas_event_handler, (AuPointer) nas_data);
 	AuSetErrorHandler(nas_data->aud, nas_error_handler);
 	nas_data->flow_stopped=1;
+	nas_data->expect_underrun=0;
 
 	pthread_mutex_init(&nas_data->buffer_mutex, NULL);
 	pthread_create(&nas_data->event_thread, NULL, &nas_event_thread_start, nas_data);
@@ -409,6 +432,8 @@
 static void uninit(){
 	AuStatus as;
 
+	DPRINTF("ao_nas: uninit()\n");
+
 	nas_data->stop_thread = 1;
 	pthread_join(nas_data->event_thread, NULL);
 	if (!nas_data->flow_stopped) {
@@ -426,6 +451,8 @@
 static void reset(){
 	AuStatus as;
 
+	DPRINTF("ao_nas: reset()\n");
+
 	pthread_mutex_lock(&nas_data->buffer_mutex);
 	nas_data->client_buffer_used = 0;
 	if (!nas_data->flow_stopped) {
@@ -435,6 +462,7 @@
 		nas_data->flow_stopped = 1;
 	}
 	nas_data->server_buffer_used = 0;
+	AuSync(nas_data->aud, AuTrue);
 	pthread_mutex_unlock(&nas_data->buffer_mutex);
 }
 
@@ -458,6 +486,7 @@
 
 	nas_data->flow_stopped = 0;
 	nas_data->flow_paused = 0;
+	nas_data->expect_underrun = 1;
 	AuStartFlow(nas_data->aud, nas_data->flow, &as);
 	if (as != AuSuccess)
 		nas_print_error(nas_data->aud, "play(): AuStartFlow", as);
@@ -488,21 +517,6 @@
 
 	DPRINTF("ao_nas: play()\n");
 
-	if (nas_data->flow_stopped) {
-		AuEvent ev;
-
-		AuStartFlow(nas_data->aud, nas_data->flow, &as);
-		if (as != AuSuccess)
-			nas_print_error(nas_data->aud, "play(): AuStartFlow", as);
-		nas_data->flow_stopped = 0;
-		/*
-		 * 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);
 	maxbursts = (nas_data->client_buffer_size -
 		     nas_data->client_buffer_used) / ao_data.outburst;
@@ -512,6 +526,17 @@
 	pthread_mutex_unlock(&nas_data->buffer_mutex);
 
 	nas_writeBuffer(nas_data, data, writelen);
+
+	if (nas_data->flow_stopped) {
+		AuEvent ev;
+
+		nas_data->expect_underrun = 1;
+		AuStartFlow(nas_data->aud, nas_data->flow, &as);
+		if (as != AuSuccess)
+			nas_print_error(nas_data->aud, "play(): AuStartFlow", as);
+		nas_data->flow_stopped = 0;
+	}
+
 	return writelen;
 }