updated to use portaudio v19.

on startup creates a daemon using NSTask.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@21640 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
esersale 2005-08-16 17:36:44 +00:00
parent 5cd54d4415
commit 134aac6c8a

View file

@ -251,6 +251,8 @@ gsnd_log (int prio)
- (void)checkIsPlaying; - (void)checkIsPlaying;
- (void)closeStream;
- (Snd *)cachedSoundWithName:(NSString *)aName; - (Snd *)cachedSoundWithName:(NSString *)aName;
- (void)checkCachedSounds; - (void)checkCachedSounds;
@ -270,7 +272,7 @@ gsnd_log (int prio)
SoundServer *gsnd = nil; SoundServer *gsnd = nil;
PortAudioStream *pStream = NULL; PaStream *pStream = NULL;
struct SoundServer_t { struct SoundServer_t {
@defs(SoundServer) @defs(SoundServer)
@ -291,8 +293,7 @@ struct SoundServer_t {
{ {
self = [super init]; self = [super init];
if (self) if (self) {
{
ASSIGN (name, [anobject name]); ASSIGN (name, [anobject name]);
ASSIGN (identifier, [anobject identifier]); ASSIGN (identifier, [anobject identifier]);
data = [[anobject data] mutableCopy]; data = [[anobject data] mutableCopy];
@ -463,14 +464,14 @@ struct SoundServer_t {
@end @end
@implementation SoundServer
static int paCallback(void *inputBuffer, static int paCallback(void *inputBuffer,
void *outputBuffer, void *outputBuffer,
unsigned long framesPerBuffer, unsigned long framesPerBuffer,
PaTimestamp outTime, const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData) void *userData)
{ {
NSAutoreleasePool *pool;
NSData *data; NSData *data;
long length; long length;
int chunkLength; int chunkLength;
@ -479,7 +480,11 @@ static int paCallback(void *inputBuffer,
gss16 *in; gss16 *in;
int i; int i;
CREATE_AUTORELEASE_POOL(pool); #ifdef GNUSTEP
GSRegisterCurrentThread();
#endif
pool = [[NSAutoreleasePool alloc] init];
data = serverPtr->soundData; data = serverPtr->soundData;
length = [data length]; length = [data length];
@ -502,19 +507,8 @@ static int paCallback(void *inputBuffer,
} }
if (retvalue == 1) { if (retvalue == 1) {
PaError err; [(SoundServer *)serverPtr performSelectorOnMainThread: @selector(closeStream)
withObject: (SoundServer *)serverPtr waitUntilDone: NO];
err = Pa_CloseStream(pStream);
if (err != paNoError) {
NSLog(@"PortAudio Pa_CloseStream error: %s", Pa_GetErrorText(err));
}
err = Pa_Terminate();
if (err != paNoError) {
NSLog(@"PortAudio Pa_Terminate error: %s", Pa_GetErrorText(err));
}
[(SoundServer *)serverPtr stopAll];
} }
serverPtr->isPlaying = !retvalue; serverPtr->isPlaying = !retvalue;
@ -524,6 +518,9 @@ static int paCallback(void *inputBuffer,
return retvalue; return retvalue;
} }
@implementation SoundServer
- (void)dealloc - (void)dealloc
{ {
[nc removeObserver: self]; [nc removeObserver: self];
@ -558,11 +555,13 @@ static int paCallback(void *inputBuffer,
[conn setDelegate: self]; [conn setDelegate: self];
[nc addObserver: self [nc addObserver: self
selector: @selector(connectionBecameInvalid:) selector: @selector(connectionBecameInvalid:)
name: NSConnectionDidDieNotification object: (id)conn]; name: NSConnectionDidDieNotification
object: (id)conn];
hostname = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"]; hostname = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"];
if ([hostname length] == 0 if ([hostname length] == 0
|| [[NSHost hostWithName: hostname] isEqual: [NSHost currentHost]] == YES) { || [[NSHost hostWithName: hostname] isEqual: [NSHost currentHost]]) {
if ([conn registerName: GSNDNAME] == NO) { if ([conn registerName: GSNDNAME] == NO) {
NSLog(@"Unable to register with name server.\n"); NSLog(@"Unable to register with name server.\n");
exit(1); exit(1);
@ -746,37 +745,36 @@ static int paCallback(void *inputBuffer,
int d = 0; int d = 0;
err = Pa_Initialize(); err = Pa_Initialize();
if(err != paNoError) {
NSLog(@"PortAudio error: %s", Pa_GetErrorText(err)); if (err != paNoError) {
} else { fprintf(stderr, "An error occured while using the portaudio stream\n");
NSLog(@"Pa_Initialize"); fprintf(stderr, "Error number: %d\n", err );
fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err));
Pa_Terminate();
return;
} }
err = Pa_OpenDefaultStream(&pStream, 0, DEFAULT_CHANNELS, paInt16, err = Pa_OpenDefaultStream(&pStream, 0, DEFAULT_CHANNELS, paInt16,
PLAY_RATE, BUFFER_SIZE_IN_FRAMES, 0, paCallback, &d); PLAY_RATE, BUFFER_SIZE_IN_FRAMES, (PaStreamCallback *)paCallback, &d);
if(err != paNoError) {
NSLog(@"PortAudio Pa_OpenDefaultStream error: %s", Pa_GetErrorText(err));
} else {
NSLog(@"Pa_OpenDefaultStream");
}
if (err == paNoError) {
err = Pa_StartStream(pStream); err = Pa_StartStream(pStream);
if(err != paNoError) {
NSLog(@"PortAudio Pa_StartStream error: %s", Pa_GetErrorText(err)); if (err == paNoError) {
Pa_Sleep(2);
} else { } else {
NSLog(@"Pa_StartStream"); NSLog(@"PortAudio Pa_StartStream error: %s", Pa_GetErrorText(err));
} }
Pa_Sleep(2); } else {
NSLog(@"PortAudio Pa_OpenDefaultStream error: %s", Pa_GetErrorText(err));
}
} }
- (void)mixWithSound:(Snd *)snd - (void)mixWithSound:(Snd *)snd
{ {
if (isPlaying == NO) { if (isPlaying) {
return;
} else {
NSData *snddata = [snd remainingData]; NSData *snddata = [snd remainingData];
long inFrameCount = (long)([snddata length] / FRAME_SIZE); long inFrameCount = (long)([snddata length] / FRAME_SIZE);
gss16 *in = (gss16 *)[snddata bytes]; gss16 *in = (gss16 *)[snddata bytes];
@ -790,6 +788,7 @@ static int paCallback(void *inputBuffer,
[snd setEndPos: posInBytes + (long)([snddata length] / FRAME_SIZE)]; [snd setEndPos: posInBytes + (long)([snddata length] / FRAME_SIZE)];
j = 0; j = 0;
for (i = posInBytes; i < frameCount; i++) { for (i = posInBytes; i < frameCount; i++) {
sum_l = out[i * 2] + in[j * 2]; sum_l = out[i * 2] + in[j * 2];
sum_r = out[i * 2 + 1] + in[j * 2 + 1]; sum_r = out[i * 2 + 1] + in[j * 2 + 1];
@ -804,6 +803,7 @@ static int paCallback(void *inputBuffer,
} }
inPos = (j * FRAME_SIZE); inPos = (j * FRAME_SIZE);
if (inPos < ([snddata length] - 1)) { if (inPos < ([snddata length] - 1)) {
long remLength = [snddata length] - inPos; long remLength = [snddata length] - inPos;
NSRange range = NSMakeRange(inPos, remLength); NSRange range = NSMakeRange(inPos, remLength);
@ -818,10 +818,7 @@ static int paCallback(void *inputBuffer,
- (void)unMixSound:(Snd *)snd - (void)unMixSound:(Snd *)snd
{ {
if (isPlaying == NO) { if (isPlaying) {
return;
} else {
int *in = (int *)[[snd data] bytes]; int *in = (int *)[[snd data] bytes];
int *out = (int *)[soundData mutableBytes]; int *out = (int *)[soundData mutableBytes];
long deleteFrom = [snd startPos] + [snd posInBytes]; long deleteFrom = [snd startPos] + [snd posInBytes];
@ -903,12 +900,41 @@ static int paCallback(void *inputBuffer,
} }
} }
- (void)closeStream
{
PaError err;
err = Pa_StopStream(pStream);
if (err != paNoError) {
NSLog(@"PortAudio Pa_StopStream error: %s", Pa_GetErrorText(err));
return;
}
err = Pa_CloseStream(pStream);
if (err != paNoError) {
NSLog(@"PortAudio Pa_CloseStream error: %s", Pa_GetErrorText(err));
return;
}
err = Pa_Terminate();
if (err != paNoError) {
NSLog(@"PortAudio Pa_Terminate error: %s", Pa_GetErrorText(err));
return;
}
[self stopAll];
}
- (Snd *)cachedSoundWithName:(NSString *)aName - (Snd *)cachedSoundWithName:(NSString *)aName
{ {
int i; int i;
for (i = 0; i < [sounds count]; i++) { for (i = 0; i < [sounds count]; i++) {
Snd *snd = [sounds objectAtIndex: i]; Snd *snd = [sounds objectAtIndex: i];
if ([[snd name] isEqual: aName]) { if ([[snd name] isEqual: aName]) {
return snd; return snd;
} }
@ -1008,7 +1034,7 @@ static int paCallback(void *inputBuffer,
} }
- (BOOL)connection:(NSConnection*)ancestor - (BOOL)connection:(NSConnection*)ancestor
shouldMakeNewConnection:(NSConnection*)newConn; shouldMakeNewConnection:(NSConnection*)newConn;
{ {
[nc addObserver: self [nc addObserver: self
selector: @selector(connectionBecameInvalid:) selector: @selector(connectionBecameInvalid:)
@ -1034,95 +1060,80 @@ shouldMakeNewConnection:(NSConnection*)newConn;
@end @end
int int main(int argc, char** argv, char **env)
main(int argc, char** argv, char **env)
{ {
int c;
CREATE_AUTORELEASE_POOL(pool); CREATE_AUTORELEASE_POOL(pool);
BOOL subtask = YES;
NSProcessInfo *pInfo;
NSMutableArray *args;
#ifdef GS_PASS_ARGUMENTS #ifdef GS_PASS_ARGUMENTS
[NSProcessInfo initializeWithArguments: argv count: argc environment: env]; [NSProcessInfo initializeWithArguments: argv count: argc environment: env];
#endif #endif
#ifdef __MINGW__ pInfo = [NSProcessInfo processInfo];
{ args = AUTORELEASE ([[pInfo arguments] mutableCopy]);
char **a = malloc((argc+2) * sizeof(char*));
memcpy(a, argv, argc * sizeof(char*)); if ([[pInfo arguments] containsObject: @"--daemon"]) {
a[argc] = "--no-fork"; subtask = NO;
a[argc+1] = 0; is_daemon = YES;
if (_spawnv(_P_NOWAIT, argv[0], a) == -1) {
fprintf(stderr, "gsnd - spawn failed - bye.\n");
exit(1);
}
exit(0);
}
#else
is_daemon = 1;
switch (fork()) {
case -1:
NSLog(@"gsnd - fork failed - bye.\n");
exit(1);
case 0:
#ifdef NeXT
setpgrp(0, getpid());
#else
setsid();
#endif
break;
default:
exit(0);
} }
/* if (subtask) {
* Ensure we don't have any open file descriptors which may refer NSFileHandle *null;
* to sockets bound to ports we may try to use. NSTask *t;
*
* Use '/dev/null' for stdin and stdout. Assume stderr is ok. t = [NSTask new];
*/
for (c = 0; c < FD_SETSIZE; c++) NS_DURING
{ {
if (is_daemon || (c != 2)) [args removeObjectAtIndex: 0];
{ [args addObject: @"--daemon"];
(void)close(c); [t setLaunchPath: [[NSBundle mainBundle] executablePath]];
[t setArguments: args];
[t setEnvironment: [pInfo environment]];
null = [NSFileHandle fileHandleWithNullDevice];
[t setStandardInput: null];
[t setStandardOutput: null];
[t setStandardError: null];
[t launch];
DESTROY(t);
} }
} NS_HANDLER
if (open("/dev/null", O_RDONLY) != 0)
{ {
sprintf(ebuf, "failed to open stdin from /dev/null (%s)\n",
strerror(errno));
gsnd_log(LOG_CRIT); gsnd_log(LOG_CRIT);
DESTROY(t);
}
NS_ENDHANDLER
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (open("/dev/null", O_WRONLY) != 1)
RELEASE(pool);
{ {
sprintf(ebuf, "failed to open stdout from /dev/null (%s)\n", #if GS_WITH_GC == 0
strerror(errno)); CREATE_AUTORELEASE_POOL(pool);
gsnd_log(LOG_CRIT);
exit(EXIT_FAILURE);
}
if (is_daemon && open("/dev/null", O_WRONLY) != 2)
{
sprintf(ebuf, "failed to open stderr from /dev/null (%s)\n",
strerror(errno));
gsnd_log(LOG_CRIT);
exit(EXIT_FAILURE);
}
#endif #endif
gsnd = [[SoundServer alloc] init]; gsnd = [[SoundServer alloc] init];
if (gsnd == nil) [[NSFileHandle fileHandleWithStandardInput] closeFile];
{ [[NSFileHandle fileHandleWithStandardOutput] closeFile];
NSLog(@"Unable to create gsnd object.\n"); #ifndef __MINGW__
exit(1); [[NSFileHandle fileHandleWithStandardError] closeFile];
#endif
RELEASE (pool);
} }
if (gsnd != nil) {
CREATE_AUTORELEASE_POOL(pool);
[[NSRunLoop currentRunLoop] run]; [[NSRunLoop currentRunLoop] run];
RELEASE(pool); RELEASE(pool);
exit(0); }
exit(EXIT_SUCCESS);
} }