void audio_term(void) { if (aud) { AuFlush(aud); AuCloseServer(aud); } }
static int nas_free(WINE_WAVEOUT* wwo) { if (!wwo->FlowStarted && wwo->BufferUsed) { AuStartFlow(wwo->AuServ, wwo->AuFlow, NULL); wwo->FlowStarted = 1; } while (wwo->BufferUsed || wwo->writeBytes != wwo->sendBytes) { if (wwo->freeBytes) nas_send_buffer(wwo); AuHandleEvents(wwo->AuServ); } AuFlush(wwo->AuServ); return TRUE; }
static int nas_close(WINE_WAVEOUT* wwo) { AuEvent ev; nas_free(wwo); AuStopFlow(wwo->AuServ, wwo->AuFlow, NULL); AuDestroyFlow(wwo->AuServ, wwo->AuFlow, NULL); AuFlush(wwo->AuServ); AuNextEvent(wwo->AuServ, AuTrue, &ev); AuDispatchEvent(wwo->AuServ, &ev); wwo->AuFlow = 0; wwo->open = 0; wwo->BufferUsed = 0; wwo->freeBytes = 0; wwo->SoundBuffer = NULL; return 1; }
/* 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; }
/* Process audio events from the NAS server. The same routine is used whether we are recording or playing back */ static void handleAudioEvents(int fd, void *data, int flags) { if(!server) { DPRINTF( "handleAudioEvents called while unconnected!\n"); return; } /* read events once */ AuEventsQueued(server, AuEventsQueuedAfterReading); /* then loop through the read queue */ while(AuEventsQueued(server, AuEventsQueuedAlready)) { AuEvent event; AuNextEvent(server, AuTrue, &event); DPRINTF("event of type %d\n", event.type); switch(event.type) { case 0: { AuErrorEvent *errEvent = (AuErrorEvent *) &event; char errdesc[1000]; AuGetErrorText(server, errEvent->error_code, errdesc, sizeof(errdesc)); fprintf(stderr, "audio error: %s\n", errdesc); sound_Stop(); return; /* return, not break, so that we don't process the now-closed server any longer! */ } case AuEventTypeElementNotify: { AuElementNotifyEvent *enEvent = (AuElementNotifyEvent *)&event; switch(enEvent->kind) { case AuElementNotifyKindLowWater: DPRINTF("low water event\n"); bytesAvail += enEvent->num_bytes; break; case AuElementNotifyKindHighWater: DPRINTF("high water event\n"); bytesAvail += enEvent->num_bytes; break; case AuElementNotifyKindState: DPRINTF("state change (%d->%d)\n", enEvent->prev_state, enEvent->cur_state); bytesAvail += enEvent->num_bytes; if(enEvent->cur_state == AuStatePause) { /* if the flow has stopped, then arrange for it to get started again */ /* XXX there is probably a more intelligent place to do this, in case there is a real reason it has paused */ DPRINTF("unpausing\n"); AuStartFlow(server, flow, NULL); AuFlush(server); } break; } } } } if(bytesAvail > 0) { DPRINTF("bytesAvail: %d\n", bytesAvail); signalSemaphoreWithIndex(semaIndex); } aioHandle(fd, handleAudioEvents, flags & AIO_RW); }
static int sound_PlaySamplesFromAtLength(int frameCount, int arrayIndex, int startIndex) { int bytesToPlay; int framesToPlay; char *buf; /* buffer to play from; it may not be arrayIndex if a conversion is necessary */ DPRINTF("PlaySamples(frameCount=%d, arrayIndex=%d, startIndex=%d\n", frameCount, arrayIndex, startIndex); /* figure out how much to play */ bytesToPlay = frameCount * bytesPerPlayFrame(); if (bytesToPlay > bytesAvail) bytesToPlay = bytesAvail; framesToPlay = bytesToPlay / bytesPerPlayFrame(); /* convert the buffer when not in stereo; when playing back, Squeak will send mono data as stereo, where the right channel is to be ignored */ if(stereo) { buf= (char *) (arrayIndex + 4*startIndex); } else { int i; short *sbuf; /* the buffer, as short's instead of char's */ DPRINTF("converting\n"); buf= malloc(2 * frameCount); if(buf == NULL) { fprintf(stderr, "out of memory\n"); return 0; } sbuf= (short *) buf; for(i=0; i<frameCount; i++) { sbuf[i]= ((short *) (arrayIndex + 4*startIndex)) [2*i]; } } DPRINTF("writing %d bytes (%d frames)\n", bytesToPlay, framesToPlay); AuWriteElement(server, flow, 0, bytesToPlay, buf, AuFalse, NULL); AuFlush(server); bytesAvail -= bytesToPlay; if(!stereo) { free(buf); } return framesToPlay; }