コード例 #1
0
ファイル: audio_nas.c プロジェクト: AzagraMac/PS2_SDK
static
int init(struct audio_init *init)
{
  char const *servername;
  char *message;

  servername = init->path;
  if (servername && *servername == 0)
    servername = 0;

  server = AuOpenServer(servername, 0, 0, 0, 0, &message);
  if (server == 0) {
    audio_error = message ? message : _("AuOpenServer() failed");
    /* N.B. AuFree(message) never called */
    return -1;
  }

  flow = AuCreateFlow(server, 0);
  if (flow == 0) {
    AuCloseServer(server);
    audio_error = _("could not create flow");
    return -1;
  }

  return 0;
}
コード例 #2
0
static int nas_open(WINE_WAVEOUT* wwo) {
    AuElement elements[3];

    if (!wwo->AuServ)
       return 0;

    if (!nas_finddev(wwo))
       return 0;

    if (!(wwo->AuFlow = AuCreateFlow(wwo->AuServ, NULL)))
       return 0;

    wwo->BufferSize = FRAG_SIZE * FRAG_COUNT;

    AuMakeElementImportClient(&elements[0], wwo->format.wf.nSamplesPerSec,
           wwo->format.wBitsPerSample == 16 ? AuFormatLinearSigned16LSB : AuFormatLinearUnsigned8,
           wwo->format.wf.nChannels, AuTrue, wwo->BufferSize, wwo->BufferSize / 2, 0, NULL);

    AuMakeElementExportDevice(&elements[1], 0, wwo->AuDev, wwo->format.wf.nSamplesPerSec,
                              AuUnlimitedSamples, 0, NULL);

    AuSetElements(wwo->AuServ, wwo->AuFlow, AuTrue, 2, elements, NULL);

    AuRegisterEventHandler(wwo->AuServ, AuEventHandlerIDMask, 0, wwo->AuFlow,
                           event_handler, (AuPointer) wwo);


    wwo->PlayedTotal = 0;
    wwo->WrittenTotal = 0;
    wwo->open = 1;

    wwo->BufferUsed = 0;
    wwo->writeBytes = 0;
    wwo->freeBytes = 0;
    wwo->sendBytes = 0;
    wwo->SoundBuffer = NULL;
    wwo->FlowStarted = 0;

    AuStartFlow(wwo->AuServ, wwo->AuFlow, NULL);
    AuPauseFlow(wwo->AuServ, wwo->AuFlow, NULL);
    wwo->FlowStarted = 1;

    return 1;
}
コード例 #3
0
ファイル: SDL_nasaudio.c プロジェクト: bohwaz/ozex
static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
	AuElement elms[3];
	int buffer_size;
	Uint16 test_format, format;

	this->hidden->mixbuf = NULL;

	/* Try for a closest match on audio format */
	format = 0;
	for ( test_format = SDL_FirstAudioFormat(spec->format);
						! format && test_format; ) {
		format = sdlformat_to_auformat(test_format);

		if (format == AuNone) {
			test_format = SDL_NextAudioFormat();
		}
	}
	if ( format == 0 ) {
		SDL_SetError("Couldn't find any hardware audio formats");
		return(-1);
	}
	spec->format = test_format;

	this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
	if (this->hidden->aud == 0)
	{
		SDL_SetError("Couldn't open connection to NAS server");
		return (-1);
	}
	
	this->hidden->dev = find_device(this, spec->channels);
	if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
		AuCloseServer(this->hidden->aud);
		this->hidden->aud = 0;
		SDL_SetError("Couldn't find a fitting playback device on NAS server");
		return (-1);
	}
	
	buffer_size = spec->freq;
	if (buffer_size < 4096)
		buffer_size = 4096; 

	if (buffer_size > 32768)
		buffer_size = 32768; /* So that the buffer won't get unmanageably big. */

	/* Calculate the final parameters for this audio specification */
	SDL_CalculateAudioSpec(spec);

	this2 = this->hidden;

	AuMakeElementImportClient(elms, spec->freq, format, spec->channels, AuTrue,
				buffer_size, buffer_size / 4, 0, NULL);
	AuMakeElementExportDevice(elms+1, 0, this->hidden->dev, spec->freq,
				AuUnlimitedSamples, 0, NULL);
	AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
	AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow,
				event_handler, (AuPointer) NULL);

	AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);

	/* Allocate mixing buffer */
	this->hidden->mixlen = spec->size;
	this->hidden->mixbuf = (Uint8 *)SDL_AllocAudioMem(this->hidden->mixlen);
	if ( this->hidden->mixbuf == NULL ) {
		return(-1);
	}
	memset(this->hidden->mixbuf, spec->silence, spec->size);

	/* Get the parent process id (we're the parent of the audio thread) */
	this->hidden->parent = getpid();

	/* We're ready to rock and roll. :-) */
	return(0);
}
コード例 #4
0
static int init(struct xmp_context *ctx)
{
	struct xmp_options *o = &ctx->o;
	int channels, rate, format, buf_samples;
	int duration, gain, watermark;
	char *server;
	AuDeviceID device = AuNone;
	AuElement element[2];
	char *token, **parm;
	int i;

	duration = 2;
	gain = 100;
	server = NULL;
	watermark = 10;
	channels = 2;
	rate = o->freq;

	parm_init();
	chkparm1("duration", duration = atoi(token));
	chkparm1("gain", gain = atoi(token));
	chkparm1("server", server = token);
	chkparm1("watermark", watermark = atoi(token));
	parm_end();

	if (o->resol == 8) {
		format = o->outfmt & XMP_FMT_UNS ?
		    AuFormatLinearUnsigned8 : AuFormatLinearSigned8;
	} else {
		if (o->big_endian) {
			format = o->outfmt & XMP_FMT_UNS ?
				AuFormatLinearUnsigned16MSB :
				AuFormatLinearSigned16MSB;
		} else {
			format = o-> outfmt & XMP_FMT_UNS ?
				AuFormatLinearUnsigned16LSB :
				AuFormatLinearSigned16LSB;
		}
	}

	if (o->outfmt & XMP_FMT_MONO)
		channels = 1;

	info.aud = AuOpenServer(server, 0, NULL, 0, NULL, NULL);
	if (!info.aud) {
		fprintf(stderr, "xmp: drv_nas: can't connect to server %s\n",
			server ? server : "");
		return XMP_ERR_DINIT;
	}

	for (i = 0; i < AuServerNumDevices(info.aud); i++) {
		if (((AuDeviceKind(AuServerDevice(info.aud, i)) ==
		     AuComponentKindPhysicalOutput) &&
		     AuDeviceNumTracks(AuServerDevice(info.aud, i)) ==
		     channels)) {
			device =
			    AuDeviceIdentifier(AuServerDevice(info.aud, i));
			break;
		}
	}

	info.da = AuGetDeviceAttributes(info.aud, device, NULL);
	if (!info.da) {
		fprintf(stderr, "xmp: drv_nas: can't get device attributes\n");
		AuCloseServer(info.aud);
		return XMP_ERR_DINIT;
	}

	AuDeviceGain(info.da) = AuFixedPointFromSum(gain, 0);
	AuSetDeviceAttributes(info.aud, AuDeviceIdentifier(info.da),
			      AuCompDeviceGainMask, info.da, NULL);

	info.flow = AuCreateFlow(info.aud, NULL);
	if (!info.flow) {
		fprintf(stderr, "xmp: drv_nas: can't create flow\n");
		AuCloseServer(info.aud);
		return XMP_ERR_DINIT;
	}

	buf_samples = rate * duration;

	AuMakeElementImportClient(&element[0], rate, format, channels, AuTrue,
				  buf_samples,
				  (AuUint32) (buf_samples * watermark / 100), 0,
				  NULL);

	AuMakeElementExportDevice(&element[1], 0, device, rate,
				  AuUnlimitedSamples, 0, NULL);

	AuSetElements(info.aud, info.flow, AuTrue, 2, element, NULL);

	AuRegisterEventHandler(info.aud, AuEventHandlerIDMask, 0, info.flow,
			       nas_event, (AuPointer) & info);

	info.buf_size = buf_samples * channels * AuSizeofFormat(format);
	info.buf = (char *)malloc(info.buf_size);
	info.buf_cnt = 0;
	info.data_sent = AuFalse;
	info.finished = AuFalse;

	AuStartFlow(info.aud, info.flow, NULL);

	return xmp_smix_on(ctx);
}
コード例 #5
0
/* StartRecording: open the device for recording.

   XXX this routine is almost identical to snd_Start().  The two should
   be factored into a single function!
*/
static int sound_StartRecording(int desiredSamplesPerSec, int stereo0, int semaIndex0)
{
  AuElement elements[2];  /* elements for the NAS flow to assemble:
   			        element 0 = physical input
			        element 1 = client export */
  AuDeviceID device;      /* physical device ID to use */
  
  DPRINTF("StartRecording\n");
  
  sound_Stop();

  DPRINTF("opening server\n");
  server = AuOpenServer(NULL, 0, NULL, 0, NULL, NULL);
  if(server == NULL) {
    DPRINTF("failed to open audio server\n");
    return false;
  }

  /* XXX check protocol version of the server */

  semaIndex= semaIndex0;
  stereo= stereo0;
  sampleRate= desiredSamplesPerSec;

  device= choose_nas_device(server, desiredSamplesPerSec, stereo, 1);
  if(device == AuNone) {
    DPRINTF("no available device on the server!\n");
    AuCloseServer(server);
    server = NULL;
    return false;
  }

  /* record format info */
  fmtBytes=2;
  fmtSigned=1;
  fmtStereo=stereo;
  fmtIsBigendian=0;
  recording=1;


  

  /* create a flow to read from */
  DPRINTF("creating flow\n");
  flow = AuCreateFlow(server, NULL);


  /* create client and device elements to record with */
  DPRINTF("creating elements\n");

  
  AuMakeElementImportDevice(&elements[0],
			    desiredSamplesPerSec,  /* XXX should use the actual sampling rate of device */
			    device,
			    AuUnlimitedSamples,
			    0, NULL);

  AuMakeElementExportClient(&elements[1],
			    0,
			    desiredSamplesPerSec,
			    AuFormatLinearSigned16LSB,  /* XXX this should be chosen based on the platform */
			    stereo ? 2 : 1,
			    AuTrue,
			    1000000,  /* was AuUnlimitedSamples */
			    1000, /* water mark: go ahead and send frequently! */
			    0, NULL);
	


  /* set up the flow with these elements */
  AuSetElements(server,	flow,
		AuTrue,
		2, elements,
		NULL);

  /* start her up */
  DPRINTF("starting flow\n");
  AuStartFlow(server, flow, NULL);
  AuFlush(server);
  

  /* initialize the space indication */
  bytesAvail = 0;

  
  /* arrange to be informed when events come in from the server */
  aioEnable(AuServerConnectionNumber(server), NULL, AIO_EXT);
  aioHandle(AuServerConnectionNumber(server), handleAudioEvents, AIO_W);

  return true;
}
コード例 #6
0
static int sound_Start(int frameCount, int samplesPerSec, int stereo0, int semaIndex0)
{
  AuElement elements[2];  /* first is a client element, second is
			     a device output element */
  AuDeviceID device;        /* ID of the device to play to */
  

  /* open the server */
  DPRINTF("opening server\n");
  server = AuOpenServer(NULL, 0, NULL, 0, NULL, NULL);
  if(server == NULL) {
    DPRINTF("failed to open audio server\n");
    return false;
  }

  /* XXX should check the protocol version! */

  /* record requested info */
  semaIndex = semaIndex0;
  stereo = stereo0;
  sampleRate= samplesPerSec;
  
  /* pick a device to play to */ 
  device = choose_nas_device(server, samplesPerSec, stereo, 0);
  if(device == AuNone) {
    DPRINTF("no available device on the server!\n");
    AuCloseServer(server);
    server = NULL;
    return false;
  }

  /* set up output parameters */
  fmtBytes=2;
  fmtSigned=1;
  fmtStereo=stereo;
  fmtIsBigendian=0;
  recording=0;
  


  /* create a flow to write on */
  DPRINTF("creating flow\n");
  flow = AuCreateFlow(server, NULL);


  /* create client and device elements to play with */
  DPRINTF("creating elements(%d,%d)\n",
	 frameCount, frameCount / 4);
  AuMakeElementImportClient(&elements[0],
			    samplesPerSec,
			    AuFormatLinearSigned16LSB,  /* XXX this should be chosen based on the platform */
			    stereo ? 2 : 1,
			    AuTrue,
			    2*frameCount,   /* max: 2 buffers */
			    frameCount,   /* low */
			    0, NULL);
	
  AuMakeElementExportDevice(&elements[1],
			    0,
			    device,
			    samplesPerSec,
			    AuUnlimitedSamples,
			    0, NULL);

  /* set up the flow with these elements */
  AuSetElements(server,	flow,
		AuTrue,
		2, elements,
		NULL);

  /* start her up */
  DPRINTF("starting flow\n");
  AuStartFlow(server, flow, NULL);
  AuFlush(server);
  

  /* initialize the space indication */
  bytesAvail = 0;

  
  /* arrange to be informed when events come in from the server */
  aioEnable(AuServerConnectionNumber(server), 0, AIO_EXT);
  aioHandle(AuServerConnectionNumber(server), handleAudioEvents, AIO_R);



  return true;
}
コード例 #7
0
ファイル: ao_nas.c プロジェクト: has207/libao
int ao_plugin_open(ao_device *device, ao_sample_format *format)
{
    ao_nas_internal *internal = (ao_nas_internal *) device->internal;
    unsigned char nas_format;
    AuElement elms[2];

    /* get format */
    switch (format->bits)
    {
    case 8  :
        nas_format = AuFormatLinearUnsigned8;
        break;
    case 16 :
        if (device->machine_byte_format == AO_FMT_BIG)
            nas_format = AuFormatLinearSigned16MSB;
        else
            nas_format = AuFormatLinearSigned16LSB;
        break;
    default :
        return 0;
    }

    /* open server */
    internal->aud = AuOpenServer(internal->host, 0, 0, 0, 0, 0);
    if (!internal->aud)
        return 0; /* Could not contact NAS server */

    /* find physical output device */
    {
        int i;
        for (i = 0; i < AuServerNumDevices(internal->aud); i++)
            if ((AuDeviceKind(AuServerDevice(internal->aud, i)) ==
                    AuComponentKindPhysicalOutput) &&
                    (AuDeviceNumTracks(AuServerDevice(internal->aud, i)) ==
                     device->output_channels))
                break;

        if ((i == AuServerNumDevices(internal->aud)) ||
                (!(internal->flow = AuCreateFlow(internal->aud, 0)))) {
            /* No physical output device found or flow creation failed. */
            AuCloseServer(internal->aud);
            return 0;
        }
        internal->dev = AuDeviceIdentifier(AuServerDevice(internal->aud, i));
    }

    /* set up flow */
    AuMakeElementImportClient(&elms[0], format->rate,
                              nas_format, device->output_channels, AuTrue,
                              internal->buf_size, internal->buf_size / 2,
                              0, 0);
    AuMakeElementExportDevice(&elms[1], 0, internal->dev,
                              format->rate, AuUnlimitedSamples, 0, 0);
    AuSetElements(internal->aud, internal->flow, AuTrue, 2, elms, 0);
    AuStartFlow(internal->aud, internal->flow, 0);

    device->driver_byte_format = AO_FMT_NATIVE;

    if(!device->inter_matrix) {
        /* set up out matrix such that users are warned about > stereo playback */
        if(device->output_channels<=2)
            device->inter_matrix=strdup("L,R");
        //else no matrix, which results in a warning
    }

    return 1;
}
コード例 #8
0
ファイル: nas.c プロジェクト: dirker/mpg123
/* 0 on error */
static int nas_createFlow(out123_handle *ao)
{
    AuDeviceID      device = AuNone;
    AuElement       elements[2];
    unsigned char   format;
    AuUint32        buf_samples;
    int             i;
 

    switch(ao->format) {
    case MPG123_ENC_SIGNED_16:
    default:
		if (((char) *(short *)"x")=='x') /* ugly, but painless */
			format = AuFormatLinearSigned16LSB; /* little endian */
		else
		format = AuFormatLinearSigned16MSB; /* big endian */
        break;
    case MPG123_ENC_UNSIGNED_8:
        format = AuFormatLinearUnsigned8;
        break;
    case MPG123_ENC_SIGNED_8:
        format = AuFormatLinearSigned8;
        break;
    case MPG123_ENC_ULAW_8:
        format = AuFormatULAW8;
        break;
    }
    /* look for an output device */
    for (i = 0; i < AuServerNumDevices(info.aud); i++)
       if (((AuDeviceKind(AuServerDevice(info.aud, i)) ==
              AuComponentKindPhysicalOutput) &&
             AuDeviceNumTracks(AuServerDevice(info.aud, i))
             ==  ao->channels )) {
            device = AuDeviceIdentifier(AuServerDevice(info.aud, i));
            break;
       }
    if (device == AuNone) {
       error1("Couldn't find an output device providing %d channels.", ao->channels);
       return 0;
    }

    /* set gain */
    if(ao->gain >= 0) {
        info.da = AuGetDeviceAttributes(info.aud, device, NULL);
        if ((info.da)!=NULL) {
            AuDeviceGain(info.da) = AuFixedPointFromSum(ao->gain, 0);
            AuSetDeviceAttributes(info.aud, AuDeviceIdentifier(info.da),
                                  AuCompDeviceGainMask, info.da, NULL);
        }
        else
            error("audio/gain: setable Volume/PCM-Level not supported");
    }
    
    if (!(info.flow = AuCreateFlow(info.aud, NULL))) {
        error("Couldn't create flow");
        return 0;
    }

    buf_samples = ao->rate * NAS_SOUND_PORT_DURATION;

    AuMakeElementImportClient(&elements[0],        /* element */
                              (unsigned short) ao->rate,
                                                   /* rate */
                              format,              /* format */
                              ao->channels,        /* channels */
                              AuTrue,              /* ??? */
                              buf_samples,         /* max samples */
                              (AuUint32) (buf_samples / 100
                                  * NAS_SOUND_LOW_WATER_MARK),
                                                   /* low water mark */
                              0,                   /* num actions */
                              NULL);               /* actions */
    AuMakeElementExportDevice(&elements[1],        /* element */
                              0,                   /* input */
                              device,              /* device */
                              (unsigned short) ao->rate,
                                                   /* rate */
                              AuUnlimitedSamples,  /* num samples */
                              0,                   /* num actions */
                              NULL);               /* actions */
    AuSetElements(info.aud,                        /* Au server */
                  info.flow,                       /* flow ID */
                  AuTrue,                          /* clocked */
                  2,                               /* num elements */
                  elements,                        /* elements */
                  NULL);                           /* return status */

    AuRegisterEventHandler(info.aud,               /* Au server */
                           AuEventHandlerIDMask,   /* value mask */
                           0,                      /* type */
                           info.flow,              /* id */
                           nas_eventHandler,       /* callback */
                           (AuPointer) &info);     /* data */

    info.buf_size = buf_samples * ao->channels * AuSizeofFormat(format);
    info.buf = (char *) malloc(info.buf_size);
    if (info.buf == NULL) {
        error1("Unable to allocate input/output buffer of size %ld",
             (long)info.buf_size);
        return 0;
    }
    info.buf_cnt = 0;
    info.data_sent = AuFalse;
    info.finished = AuFalse;
    
    AuStartFlow(info.aud,                          /* Au server */
                info.flow,                         /* id */
                NULL);                             /* status */
    return 1; /* success */
}
コード例 #9
0
ファイル: sound-nas.c プロジェクト: hroptatyr/sxemacs
static int
sound_nas_play(audio_job_t aj)
{
	/* stream stuff */
	Lisp_Media_Stream *ms;
	media_substream *mss;
	/* thread stuff */
	media_thread_play_state mtp;
	/* device stuff */
	Lisp_Object device;
	Lisp_Audio_Device *lad = NULL;
	sound_nas_data_t *snd = NULL;
	/* nas stuff */
	AuElement elms[3];
	AuStatus as;
	int bsize = 0;
	/* subthread stuff */
	sound_nas_aj_data_t _snsd, *snsd = &_snsd;
	sxe_mse_volume_args _volargs, *volargs = &_volargs;
	sxe_mse_rerate_args _rrargs, *rrargs = &_rrargs;
	/* cache stuff */
	int alloced_myself = 0;

	SOUND_UNPACK_MT(aj, device, ms, mss, lad, snd, snsd->mtap);

	/* refuse to do anything if the AuServer pointer is not set */
	if (snd->aud == NULL) {
		NAS_DEBUG_C("b0rked connection, gute Nacht!\n");
		return 0;
	}

	/* install error handlers before anything else */
	AuSetErrorHandler(snd->aud, nas_error_handler);
	AuSetIOErrorHandler(snd->aud, nas_IOerror_handler);

	/* find physical output device */
	snsd->dev = nas_find_device(snd->aud, snsd->mtap->channels);

	if (snsd->dev == AuNone ||
	    !(snsd->flow = AuCreateFlow(snd->aud, NULL))) {
		/* No physical output device found or flow creation failed. */
		NAS_DEBUG_C("no physical devices for this stream\n");
		return 0;
	}

	/* A system call interrupted with a SIGALRM or SIGIO
	   comes back here */
	if (SETJMP(nas_server_sig)) {
		NAS_CRITICAL("Caught the lethal signal.\n");
		snd->aud = NULL;
		sound_nas_finish(snd);
		goto uhoh;
	}

	/* init the snsd */
	snsd->samplerate = 0;
	snsd->framesize = (snsd->channels = snsd->mtap->channels)
		* sizeof(int16_t);
	snsd->msf = MEDIA_SAMPLE_FORMAT(sxe_msf_S16);
	snsd->coe_ch_cnt = 0;
	snsd->resolution =
		(snsd->mtap->samplerate * MTPSTATE_REACT_TIME) / 1000000;
	bsize = (snsd->resolution + NAS_FRAG_SIZE - 1) & ~(NAS_FRAG_SIZE-1);

	snsd->snd = snd;
	snsd->buffer_size = bsize;
	snsd->writepos = snsd->readpos = 0;
	snsd->overfill = snsd->underrun = 0;

	/* set up flow */
	AuMakeElementImportClient(elms+0, snsd->mtap->samplerate,
				  AuFormatLinearSigned16LSB,
				  snsd->mtap->channels,
				  AuTrue,
				  bsize, bsize / 2,
				  0, NULL);
	snsd->gain = AuFixedPointFromFraction(1, 1);
	AuMakeElementMultiplyConstant(elms+1, 0, snsd->gain);
	AuMakeElementExportDevice(elms+2, 0, snsd->dev,
				  snsd->mtap->samplerate,
				  AuUnlimitedSamples, 0, NULL);
	AuSetElements(snd->aud, snsd->flow, AuTrue, 3, elms, &as);

	if (as != AuSuccess) {
		NAS_DEBUG_C("play(): AuSetElements failed\n");
		return 0;
	}

#if 0				/* atm we insist on having stereo access */
	/* the channel effect */
	ADD_MEDIA_SAMPLE_EFFECT(
		snsd->coe_chain, snsd->coe_ch_cnt,
		MEDIA_SAMPLE_EFFECT(sxe_mse_2ch_to_1ch), NULL);
#endif

	/* the volume effect */
	ADD_MEDIA_SAMPLE_EFFECT(
		snsd->coe_chain, snsd->coe_ch_cnt,
		MEDIA_SAMPLE_EFFECT(sxe_mse_volume), volargs);
	volargs->num_channels = snsd->channels;
	snsd->volargs = volargs;

	/* the rerate effect */
	ADD_MEDIA_SAMPLE_EFFECT(
		snsd->coe_chain, snsd->coe_ch_cnt,
		MEDIA_SAMPLE_EFFECT(sxe_mse_rerate), rrargs);
	rrargs->num_channels = snsd->channels;
	rrargs->srcrate = rrargs->tgtrate = 1;
	snsd->rrargs = rrargs;

	AuRegisterEventHandler(snd->aud, AuEventHandlerIDMask |
			       AuEventHandlerTypeMask,
			       AuEventTypeElementNotify, snsd->flow,
			       nas_event_handler, (AuPointer)aj);

	/* rewind the stream */
	media_stream_meth(ms, rewind)(mss);

	/* play chunks of the stream */
	SXE_MUTEX_LOCK(&aj->mtx);
	if (aj->buffer_alloc_size < SOUND_MAX_AUDIO_FRAME_SIZE) {
		alloced_myself = 1;
		aj->buffer = xmalloc_atomic(SOUND_MAX_AUDIO_FRAME_SIZE);
		aj->buffer_alloc_size = SOUND_MAX_AUDIO_FRAME_SIZE;
	}
	SXE_MUTEX_UNLOCK(&aj->mtx);
	snsd->mtp = MTPSTATE_STOP;
	snsd->volume = -1;
	audio_job_device_data(aj) = snsd;

	/* prefill the buffer */
	NAS_DEBUG_S("prefill the buffer: %d\n", 4*bsize);
	if (!nas_fill(aj, 4*bsize))
		goto uhoh;

	while (aj->play_state != MTPSTATE_STOP) {

#if 0
		if (aj->volume != snsd->volume) {
			AuElementParameters aep;
			NAS_DEBUG_S("Setting volume.\n");
			snsd->volume = aj->volume;
			snsd->gain = AU_FIXED_POINT_SCALE*(snsd->volume)/127;
			aep.parameters[AuParmsMultiplyConstantConstant] =
				snsd->gain;
			aep.flow = snd->flow;
			aep.element_num = 1;
			aep.num_parameters = AuParmsMultiplyConstant;

			AuSetElementParameters(snd->aud, 1, &aep, &as);
			if (as != AuSuccess) {
				NAS_DEBUG_S("Setting volume failed.\n");
			}
		}
#endif

#ifdef EF_USE_ASYNEQ
		/* events for me audio-job? */
		if (audio_job_queue(aj)) {
			sound_nas_handle_aj_events(aj);
		}
#endif

		SXE_MUTEX_LOCK(&aj->mtx);
		mtp = aj->play_state;
		SXE_MUTEX_UNLOCK(&aj->mtx);
		switch (mtp) {
		case MTPSTATE_RUN:
			if (snsd->mtp != mtp) {
				NAS_DEBUG("ah, gotta work again\n");
				AuStartFlow(snd->aud, snsd->flow, &as);
				if (as != AuSuccess) {
					NAS_DEBUG_C("play(): "
						    "AuStartFlow failed\n");
					aj->play_state = MTPSTATE_STOP;
				}
			}
			nas_empty_event_queue(snsd);
			usleep(snsd->resolution);
			break;
		case MTPSTATE_PAUSE:
			if (snsd->mtp != mtp) {
				NAS_DEBUG("sleeping for %d\n",
					  snsd->resolution);
				AuStopFlow(snd->aud, snsd->flow, &as);
			}
			usleep(snsd->resolution);
			break;

		case MTPSTATE_UNKNOWN:
		case MTPSTATE_STOP:
		case NUMBER_OF_MEDIA_THREAD_PLAY_STATES:
		default:
			NAS_DEBUG("ACK, quit\n");
			AuStopFlow(snd->aud, snsd->flow, &as);
			SXE_MUTEX_LOCK(&aj->mtx);
			aj->play_state = MTPSTATE_STOP;
			SXE_MUTEX_UNLOCK(&aj->mtx);
			break;
		}
		snsd->mtp = mtp;
	}

uhoh:
	/* -- Close and shutdown -- */
	SXE_MUTEX_LOCK(&aj->mtx);
	if (alloced_myself && aj->buffer) {
		xfree(aj->buffer);
	}
	aj->buffer = NULL;
	aj->buffer_alloc_size = 0;
	SXE_MUTEX_UNLOCK(&aj->mtx);

	return 1;
}