1#import "GSSpeechSynthesizer.h"
2
3static GSSpeechServer *server;
4static int clients;
5
6@interface GSSpeechSynthesizer (Private)
7+ (void)connectionDied: (NSNotification*)aNotification;
8@end
9
10@implementation GSSpeechSynthesizer
11+ (void)initialize
12{
13  server = [[GSSpeechServer sharedServer] retain];
14  [[NSNotificationCenter defaultCenter]
15		addObserver: self
16		   selector: @selector(connectionDied:)
17                       name: NSConnectionDidDieNotification
18                     object: nil];
19}
20
21/**
22 * If the remote end exits before freeing the GSSpeechSynthesizer then we need
23 * to send it a -release message to make sure it dies.
24 */
25+ (void)connectionDied: (NSNotification*)aNotification
26{
27  NSEnumerator *e = [[[aNotification object] localObjects] objectEnumerator];
28  NSObject *o = nil;
29  for (o = [e nextObject] ; nil != o ; o = [e nextObject])
30    {
31      if ([o isKindOfClass: self])
32        {
33          [o release];
34        }
35    }
36}
37
38/**
39 * If no clients have been active for some time, kill the speech server to
40 * conserve resources.
41 */
42+ (void)exitIfUnneeded: (NSTimer*)sender
43{
44  if (clients == 0)
45    {
46      exit(0);
47    }
48}
49
50- (id)initWithVoice: (NSString*)aVoice
51{
52  clients++;
53  if (nil == (self = [super init]))
54    {
55      return nil;
56    }
57  [self setVoice: currentVoice];
58  return self;
59}
60
61- (id)init
62{
63  return [self initWithVoice: nil];
64}
65
66- (NSString*)voice
67{
68  return currentVoice;
69}
70
71- (id)delegate
72{
73  return delegate;
74}
75
76- (void)setDelegate: (id)aDelegate
77{
78  // Either -retain or -release can throw an exception due to DO.
79  NS_DURING
80    aDelegate = [aDelegate retain];
81  NS_HANDLER
82  NS_ENDHANDLER
83  NS_DURING
84    [delegate release];
85  NS_HANDLER
86  NS_ENDHANDLER
87  delegate = aDelegate;
88}
89
90- (void)setVoice: (NSString*)aVoice
91{
92  if (nil == aVoice)
93    {
94      aVoice = [server defaultVoice];
95    }
96  ASSIGN(currentVoice, aVoice);
97}
98
99- (BOOL)startSpeakingString: (NSString*)aString
100{
101  [server setVoice: currentVoice];
102  return [server startSpeakingString: aString notifyWhenDone: self];
103}
104
105- (void)didFinishSpeaking: (BOOL)didFinish
106{
107  // Throw the delegate away if it is throwing exceptions during
108  // notification.
109  NS_DURING
110    [delegate speechSynthesizer: self didFinishSpeaking: didFinish];
111  NS_HANDLER
112    NS_DURING
113      id d = delegate;
114      delegate = nil;
115      [d release];
116    NS_HANDLER
117    NS_ENDHANDLER
118  NS_ENDHANDLER
119}
120
121- (void)stopSpeaking
122{
123  [server stopSpeaking];
124}
125
126- (void)dealloc
127{
128  clients--;
129  [currentVoice release];
130  if (clients == 0)
131    {
132      [NSTimer scheduledTimerWithTimeInterval: 600
133                                       target: object_getClass(self)
134                                     selector: @selector(exitIfUnneeded:)
135                                     userInfo: nil
136                                      repeats: NO];
137    }
138  [super dealloc];
139}
140@end
141