[MPlayer-dev-eng] [PATCH] ao_nas update

Tobias Diedrich td at sim.uni-hannover.de
Sun Oct 13 02:33:13 CEST 2002


Tobias Diedrich wrote:

> Trying to stuff to return values into one seems to be a bad idea anyway,
> at least it did not work properly... This patch changes this back and
> format to *format so the format we use is passed that way.
> It also fixes a few warnings and one missing check in init(), it did not
> abort when AuSetElements failed because of missing brackets in
> "(nas_data->flow = AuCreateFlow(nas_data->aud, NULL) != 0))".

Seems like this one has not been applied yet.
Here is an update.

diffstat:
 ao_nas.c |  223
 +++++++++++++++++++++++++++++++--------------------------------
  1 files changed, 111 insertions(+), 112 deletions(-)

Fixes:
  missing check in init
  missing brackets causing failure
  nas_aformat_to_auformat not working properly
  fix hang that was finally reproducible with high disk activity
  don't cut of audio on uninit(), wait for buffer to empty

It also simplifies the event_handler, making it more readable and
implements Sidik Isani's suggestion to make the buffer size dependent on
bytes per second. I've been using it for two days and found no further
problems.

-- 
Tobias								PGP: 0x9AC7E0BC
This mail is made of 100% recycled bits
Now playing: hakuchouemiko: -instrumental- - Melodies of Life
-------------- next part --------------
Index: libao2/ao_nas.c
===================================================================
RCS file: /cvsroot/mplayer/main/libao2/ao_nas.c,v
retrieving revision 1.9
diff -u -r1.9 ao_nas.c
--- libao2/ao_nas.c	7 Oct 2002 01:50:49 -0000	1.9
+++ libao2/ao_nas.c	13 Oct 2002 00:49:09 -0000
@@ -13,8 +13,8 @@
  * 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.
+ * We setup the server to use a buffer of size bytes_per_second
+ * with a low watermark of 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
@@ -26,8 +26,10 @@
  * accounting of what we think how much of the server buffer is filled)
  */
 
+#include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <pthread.h>
 #include <audio/audiolib.h>
 
@@ -38,8 +40,6 @@
 #include "afmt.h"
 
 #define NAS_FRAG_SIZE 4096
-#define NAS_FRAG_COUNT 8
-#define NAS_BUFFER_SIZE NAS_FRAG_SIZE * NAS_FRAG_COUNT
 
 static char *nas_event_types[] = {
 	"Undefined",
@@ -110,8 +110,7 @@
 	AuFlowID	flow;
 	AuDeviceID	dev;
 
-	int flow_stopped;
-	int flow_paused;
+	unsigned int state;
 	int expect_underrun;
 
 	void *client_buffer;
@@ -178,12 +177,6 @@
 	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);
-	
-	if (nas_data->flow_paused) {
-		AuPauseFlow(nas_data->aud, nas_data->flow, &as);
-		if (as != AuSuccess)
-			nas_print_error(nas_data->aud, "nas_readBuffer(): AuPauseFlow", as);
-	}
 
 	return num;
 }
@@ -217,13 +210,16 @@
 static void *nas_event_thread_start(void *data)
 {
 	struct ao_nas_data *nas_data = data;
-	AuEvent ev;
-	AuBool result;
 
 	do {
+		mp_msg(MSGT_AO, MSGL_DBG2,
+		       "ao_nas: event thread heartbeat (state=%s)\n",
+		       nas_state(nas_data->state));
 		nas_empty_event_queue(nas_data);
-		usleep(10000);
+		usleep(1000);
 	} while (!nas_data->stop_thread);
+
+	return NULL;
 }
 
 static AuBool nas_error_handler(AuServer* aud, AuErrorEvent* ev)
@@ -245,56 +241,53 @@
 static AuBool nas_event_handler(AuServer *aud, AuEvent *ev, AuEventHandlerRec *hnd)
 {
 	AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
-	AuStatus as;
 	struct ao_nas_data *nas_data = hnd->data;
 
-	switch (ev->type) {
-	case AuEventTypeElementNotify:
-		mp_msg(MSGT_AO, MSGL_DBG2, "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,
-			nas_data->expect_underrun);
-
-		nas_data->server_buffer_used -= event->num_bytes;
-		if (nas_data->server_buffer_used < 0)
-			nas_data->server_buffer_used = 0;
-
-		switch (event->kind) {
-		case AuElementNotifyKindLowWater:
-			nas_readBuffer(nas_data, event->num_bytes);
-			break;
-		case AuElementNotifyKindState:
-			if (event->cur_state == AuStatePause) {
-				switch (event->reason) {
-				case AuReasonUnderrun:
-					// buffer underrun -> refill buffer
-					if (nas_data->expect_underrun)
-						nas_data->expect_underrun = 0;
-					else {
-						mp_msg(MSGT_AO, MSGL_WARN, "ao_nas: Buffer underrun.\n");
-						mp_msg(MSGT_AO, MSGL_HINT, "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;
-					if (nas_readBuffer(nas_data, nas_data->server_buffer_size - nas_data->server_buffer_used) == 0)
-						nas_data->flow_stopped = 1;
-					break;
-				default:
-					break;
-				}
-			}
-			break;
-		default: // silently ignored
+	mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: event_handler(): type %s kind %s state %s->%s reason %s numbytes %d expect_underrun %d\n",
+		nas_event_type(event->type),
+		nas_elementnotify_kind(event->kind),
+		nas_state(event->prev_state),
+		nas_state(event->cur_state),
+		nas_reason(event->reason),
+		event->num_bytes,
+		nas_data->expect_underrun);
+
+	nas_data->server_buffer_used -= event->num_bytes;
+	if (nas_data->server_buffer_used < 0)
+		nas_data->server_buffer_used = 0;
+
+	switch (event->reason) {
+	case AuReasonWatermark:
+		nas_readBuffer(nas_data, event->num_bytes);
+		break;
+	case AuReasonUnderrun:
+		// buffer underrun -> refill buffer
+		nas_data->server_buffer_used = 0;
+		if (nas_data->expect_underrun) {
+			nas_data->expect_underrun = 0;
+		} else {
+			mp_msg(MSGT_AO, MSGL_WARN,
+			       "ao_nas: Buffer underrun.\n");
+			mp_msg(MSGT_AO, MSGL_HINT,
+			       "Possible reasons are:"
+			       "1) Network congestion."
+			       "2) Your NAS server is too slow."
+			       "Try renicing your nasd to e.g. -15.\n");
+		}
+		if (nas_readBuffer(nas_data,
+		                   nas_data->server_buffer_size -
+		                   nas_data->server_buffer_used) != 0) {
+			event->cur_state = AuStateStart;
 			break;
 		}
+		mp_msg(MSGT_AO, MSGL_DBG2,
+			"ao_nas: Can't refill buffer, stopping flow.\n");
+		AuStopFlow(nas_data->aud, nas_data->flow, NULL);
 		break;
-	default: 
-		mp_msg(MSGT_AO, MSGL_WARN, "ao_nas: nas_event_handler(): unhandled event type %d\n", ev->type);
+	default:
 		break;
 	}
+	nas_data->state=event->cur_state;
 	return AuTrue;
 }
 
@@ -311,30 +304,31 @@
 	return AuNone;
 }
 
-static unsigned int nas_aformat_to_auformat(unsigned int format)
+static unsigned int nas_aformat_to_auformat(unsigned int *format)
 {
-	unsigned int res=format << 8;
-	switch (format) {
+	switch (*format) {
 	case	AFMT_U8:
-		return res + AuFormatLinearUnsigned8;
+		return AuFormatLinearUnsigned8;
 	case	AFMT_S8:
-		return res + AuFormatLinearSigned8;
+		return AuFormatLinearSigned8;
 	case	AFMT_U16_LE:
-		return res + AuFormatLinearUnsigned16LSB;
+		return AuFormatLinearUnsigned16LSB;
 	case	AFMT_U16_BE:
-		return res + AuFormatLinearUnsigned16MSB;
+		return AuFormatLinearUnsigned16MSB;
 #ifndef WORDS_BIGENDIAN
 	default:
+		*format=AFMT_S16_LE;
 #endif
 	case	AFMT_S16_LE:
-		return (AFMT_S16_LE << 8) + AuFormatLinearSigned16LSB;
+		return AuFormatLinearSigned16LSB;
 #ifdef WORDS_BIGENDIAN
 	default:
+		*format=AFMT_S16_BE;
 #endif
 	case	AFMT_S16_BE:
-		return (AFMT_S16_BE << 8) + AuFormatLinearSigned16MSB;
+		return AuFormatLinearSigned16MSB;
 	case	AFMT_MU_LAW:
-		return res + AuFormatULAW8;
+		return AuFormatULAW8;
 	}
 }
 
@@ -349,8 +343,9 @@
 {
 	AuElement elms[3];
 	AuStatus as;
-	unsigned char auformat = nas_aformat_to_auformat(format);
+	unsigned char auformat = nas_aformat_to_auformat(&format);
 	int bytes_per_sample = channels * AuSizeofFormat(auformat);
+	int buffer_size;
 	char *server;
 
 	nas_data=malloc(sizeof(struct ao_nas_data));
@@ -359,17 +354,23 @@
 	mp_msg(MSGT_AO, MSGL_V, "ao2: %d Hz  %d chans  %s\n",rate,channels,
 		audio_out_format_name(format));
 
-	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.format = auformat >> 8;
+	ao_data.format = format;
 	ao_data.samplerate = rate;
 	ao_data.channels = channels;
-	ao_data.buffersize = NAS_BUFFER_SIZE * 2;
 	ao_data.outburst = NAS_FRAG_SIZE;
 	ao_data.bps = rate * bytes_per_sample;
+	buffer_size = ao_data.bps; /* buffer 1 second */
+	/*
+	 * round up to multiple of NAS_FRAG_SIZE
+	 * divide by 3 first because of 2:1 split
+	 */
+	buffer_size = (buffer_size/3 + NAS_FRAG_SIZE-1) & ~(NAS_FRAG_SIZE-1);
+	ao_data.buffersize = buffer_size*3;
+
+	nas_data->client_buffer_size = buffer_size*2;
+	nas_data->client_buffer = malloc(nas_data->client_buffer_size);
+	nas_data->server_buffer_size = buffer_size;
+	nas_data->server_buffer = malloc(nas_data->server_buffer_size);
 
 	if (!bytes_per_sample) {
 		mp_msg(MSGT_AO, MSGL_ERR, "ao_nas: init(): Zero bytes per sample -> nosound\n");
@@ -393,7 +394,7 @@
 	while (channels>1) {
 		nas_data->dev = nas_find_device(nas_data->aud, channels);
 		if (nas_data->dev != AuNone &&
-		    (nas_data->flow = AuCreateFlow(nas_data->aud, NULL) != 0))
+		    ((nas_data->flow = AuCreateFlow(nas_data->aud, NULL)) != 0))
 			break;
 		channels--;
 	}
@@ -405,21 +406,25 @@
 		return 0;
 	}
 
-	AuMakeElementImportClient(elms, rate, auformat & 0xff, channels, AuTrue,
-				NAS_BUFFER_SIZE / bytes_per_sample,
-				(NAS_BUFFER_SIZE - NAS_FRAG_SIZE) / bytes_per_sample,
-				0, NULL);
+	AuMakeElementImportClient(elms, rate, auformat, channels, AuTrue,
+				buffer_size / bytes_per_sample,
+				(buffer_size - NAS_FRAG_SIZE) /
+				bytes_per_sample, 0, NULL);
 	AuMakeElementExportDevice(elms+1, 0, nas_data->dev, rate,
 				AuUnlimitedSamples, 0, NULL);
 	AuSetElements(nas_data->aud, nas_data->flow, AuTrue, 2, elms, &as);
-	if (as != AuSuccess)
+	if (as != AuSuccess) {
 		nas_print_error(nas_data->aud, "init(): AuSetElements", as);
+		AuCloseServer(nas_data->aud);
+		nas_data->aud = 0;
+		return 0;
+	}
 	AuRegisterEventHandler(nas_data->aud, AuEventHandlerIDMask |
 				AuEventHandlerTypeMask,
 				AuEventTypeElementNotify, nas_data->flow,
 				nas_event_handler, (AuPointer) nas_data);
 	AuSetErrorHandler(nas_data->aud, nas_error_handler);
-	nas_data->flow_stopped=1;
+	nas_data->state=AuStateStop;
 	nas_data->expect_underrun=0;
 
 	pthread_mutex_init(&nas_data->buffer_mutex, NULL);
@@ -430,17 +435,13 @@
 
 // close audio device
 static void uninit(){
-	AuStatus as;
 
-	mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: uninit()\n");
+	mp_msg(MSGT_AO, MSGL_DBG3, "ao_nas: uninit()\n");
 
+	nas_data->expect_underrun = 1;
+	while (nas_data->state != AuStateStop) usleep(1000);
 	nas_data->stop_thread = 1;
 	pthread_join(nas_data->event_thread, NULL);
-	if (!nas_data->flow_stopped) {
-		AuStopFlow(nas_data->aud, nas_data->flow, &as);
-		if (as != AuSuccess)
-			nas_print_error(nas_data->aud, "uninit(): AuStopFlow", as);
-	}
 	AuCloseServer(nas_data->aud);
 	nas_data->aud = 0;
 	free(nas_data->client_buffer);
@@ -451,45 +452,39 @@
 static void reset(){
 	AuStatus as;
 
-	mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: reset()\n");
+	mp_msg(MSGT_AO, MSGL_DBG3, "ao_nas: reset()\n");
 
 	pthread_mutex_lock(&nas_data->buffer_mutex);
 	nas_data->client_buffer_used = 0;
-	if (!nas_data->flow_stopped) {
+	pthread_mutex_unlock(&nas_data->buffer_mutex);
+	while (nas_data->state != AuStateStop) {
 		AuStopFlow(nas_data->aud, nas_data->flow, &as);
 		if (as != AuSuccess)
 			nas_print_error(nas_data->aud, "reset(): AuStopFlow", as);
-		nas_data->flow_stopped = 1;
+		usleep(1000);
 	}
-	nas_data->server_buffer_used = 0;
-	AuSync(nas_data->aud, AuTrue);
-	pthread_mutex_unlock(&nas_data->buffer_mutex);
 }
 
 // stop playing, keep buffers (for pause)
 static void audio_pause()
 {
 	AuStatus as;
+	mp_msg(MSGT_AO, MSGL_DBG3, "ao_nas: audio_pause()\n");
 
-	mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: audio_pause()\n");
-
-	nas_data->flow_paused = 1;
+	AuStopFlow(nas_data->aud, nas_data->flow, &as);
 }
 
 // resume playing, after audio_pause()
 static void audio_resume()
 {
 	AuStatus as;
-	AuEvent ev;
 
-	mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: audio_resume()\n");
+	mp_msg(MSGT_AO, MSGL_DBG3, "ao_nas: audio_resume()\n");
 
-	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);
+		nas_print_error(nas_data->aud,
+		                "play(): AuStartFlow", as);
 }
 
 
@@ -498,7 +493,7 @@
 {
 	int result;
 	
-	mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: get_space()\n");
+	mp_msg(MSGT_AO, MSGL_DBG3, "ao_nas: get_space()\n");
 
 	pthread_mutex_lock(&nas_data->buffer_mutex);
 	result = nas_data->client_buffer_size - nas_data->client_buffer_used;
@@ -515,7 +510,12 @@
 	int maxbursts, playbursts, writelen;
 	AuStatus as;
 
-	mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: play()\n");
+	mp_msg(MSGT_AO, MSGL_DBG3,
+	       "ao_nas: play(%p, %d, %d)\n",
+	       data, len, flags);
+
+	if (len == 0)
+		return 0;
 
 	pthread_mutex_lock(&nas_data->buffer_mutex);
 	maxbursts = (nas_data->client_buffer_size -
@@ -527,14 +527,13 @@
 
 	nas_writeBuffer(nas_data, data, writelen);
 
-	if (nas_data->flow_stopped) {
-		AuEvent ev;
-
+	if (nas_data->state != AuStateStart &&
+	    maxbursts == playbursts) {
+		mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: play(): Starting flow.\n");
 		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;
@@ -545,7 +544,7 @@
 {
 	float result;
 	
-	mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: get_delay()\n");
+	mp_msg(MSGT_AO, MSGL_DBG3, "ao_nas: get_delay()\n");
 
 	pthread_mutex_lock(&nas_data->buffer_mutex);
 	result = ((float)(nas_data->client_buffer_used +
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/attachments/20021013/fb50fc19/attachment.pgp>


More information about the MPlayer-dev-eng mailing list