Zachary Kotlarek 12 лет назад
Родитель
Сommit
38ae4341df
3 измененных файлов с 171 добавлено и 0 удалено
  1. 20 0
      speak/Makefile
  2. 41 0
      speak/say.m
  3. 110 0
      speak/speak.m

+ 20 - 0
speak/Makefile

@@ -0,0 +1,20 @@
+STD_FLAGS=-fobjc-arc
+FRAMES=-framework AppKit
+
+default: speak
+.PHONY: clean
+
+clean:
+	rm -f *.o speak say
+
+say.o: say.m
+	gcc -c say.m
+
+say: say.o
+	gcc $(FRAMES) -o say say.o
+
+speak.o: speak.m
+	gcc $(STD_FLAGS) -c speak.m
+
+speak: speak.o
+	gcc $(FRAMES) $(STD_FLAGS) -o speak speak.m

+ 41 - 0
speak/say.m

@@ -0,0 +1,41 @@
+#import <AppKit/AppKit.h>
+
+@interface SpeechDelegate : NSObject <NSSpeechSynthesizerDelegate>
+@end
+
+@implementation SpeechDelegate
+- (void)speechSynthesizer: (NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)success {
+	if (!success) {
+		exit(-3);
+	}
+	exit(0);
+}
+@end
+
+int main(int argc, const char *argv[]) {
+	if (argc < 2) {
+		return -1;
+	}
+
+	// Init the speech engine
+	NSSpeechSynthesizer *synth = [[NSSpeechSynthesizer alloc] init];
+	[synth setDelegate: [SpeechDelegate new]];
+
+	// Convert from c-string to NSString
+	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+	NSString *str = [NSString stringWithUTF8String: argv[1]];
+
+	// Wait for other apps to stop speaking before we start
+	// This provides no cordination with other waiting speakers
+	while( [NSSpeechSynthesizer isAnyApplicationSpeaking] ) {
+		[NSThread sleepForTimeInterval: 0.25];
+	}
+
+	// Speak
+	[synth startSpeakingString: str];
+	[[NSRunLoop currentRunLoop] run];
+
+	// Cleanup (not reached)
+	[pool drain];
+	return 0;
+}

+ 110 - 0
speak/speak.m

@@ -0,0 +1,110 @@
+#import <AppKit/AppKit.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+
+// The speach synth is global
+NSSpeechSynthesizer *synth = NULL;
+
+@interface SpeechDelegate : NSObject <NSSpeechSynthesizerDelegate>
+@end
+
+@implementation SpeechDelegate
+- (void)speechSynthesizer: (NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)success {
+	if (!success) {
+		NSLog(@"Unable to speak");
+	}
+}
+@end
+
+@interface Socket : NSObject <NSStreamDelegate>
+- (BOOL)listen:(NSString *)path;
+static void sockCallback (CFSocketRef sock, CFSocketCallBackType type, CFDataRef address, const void *data, void *info);
+
+@property NSString *path;
+@property CFSocketRef unixSocket;
+@end
+
+@implementation Socket
+
+- (BOOL)listen:(NSString *)path {
+	self.path = path;
+	
+	unlink([self.path cStringUsingEncoding:NSUTF8StringEncoding]);
+	CFSocketContext CTX = { 0, (__bridge void *)(self), NULL, NULL, NULL };
+
+	self.unixSocket = CFSocketCreate(NULL, PF_UNIX, SOCK_DGRAM, 0,
+		kCFSocketDataCallBack, (CFSocketCallBack)sockCallback, &CTX);
+	if (self.unixSocket == NULL) {
+		return NO;
+	} 
+
+	struct sockaddr_un addr;
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, [self.path cStringUsingEncoding:NSUTF8StringEncoding], sizeof(addr.sun_path) - 1);
+	addr.sun_len = SUN_LEN(&addr);
+
+	NSData *address = [ NSData dataWithBytes: &addr length: sizeof(addr) ];
+	if (CFSocketSetAddress(self.unixSocket, (__bridge CFDataRef) address) != kCFSocketSuccess) {
+		CFRelease(self.unixSocket);
+		return NO;
+	}
+
+	CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource(kCFAllocatorDefault, self.unixSocket, 0);
+	CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes);
+	CFRelease(sourceRef);  
+	return YES;
+}
+
+static void sockCallback (CFSocketRef sock, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
+	switch(type) {
+		case kCFSocketDataCallBack: {
+			// Wait for other apps to stop speaking before we start
+			// This provides no cordination with other waiting speakers
+			while( [NSSpeechSynthesizer isAnyApplicationSpeaking] ) {
+				[NSThread sleepForTimeInterval: 0.25];
+			}
+
+			// Speak
+			NSString *str = [[NSString alloc] initWithData:(__bridge NSData*)data encoding:NSUTF8StringEncoding];
+			[synth startSpeakingString: str];
+			break;			
+		}
+		case kCFSocketNoCallBack:
+		case kCFSocketAcceptCallBack:
+		case kCFSocketConnectCallBack:
+		case kCFSocketWriteCallBack:
+		case kCFSocketReadCallBack: {
+			break;
+		}
+	}
+}
+
+@end
+
+int main(int argc, const char *argv[]) {
+	if (argc < 2) {
+		return -1;
+	}
+		
+	// Convert from c-string to NSString
+	NSString *str = [NSString stringWithUTF8String: argv[1]];
+	
+	// Init the speech engine
+	synth = [[NSSpeechSynthesizer alloc] init];
+	[synth setDelegate: [SpeechDelegate new]];
+	
+	// Open the socket
+	Socket *sock = [[Socket alloc] init];
+	if (![sock listen:str]) {
+		NSLog(@"Unable to open socket");
+		exit(-1);
+	}	
+
+	// Run
+	[[NSRunLoop currentRunLoop] run];
+
+	// Cleanup (not reached)
+	return 0;
+}