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; }
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; }
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); }
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); }
/* 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; }
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; }
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; }
/* 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 */ }
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; }