Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(789)

Side by Side Diff: chrome/browser/speech/tts_mac.mm

Issue 12636005: Fix crash in NSSpeechSynthesizer by explicitly retaining NSString. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <string> 5 #include <string>
6 6
7 #include "base/memory/scoped_nsobject.h" 7 #include "base/memory/scoped_nsobject.h"
8 #include "base/memory/singleton.h" 8 #include "base/memory/singleton.h"
9 #include "base/sys_string_conversions.h" 9 #include "base/sys_string_conversions.h"
10 #include "base/values.h" 10 #include "base/values.h"
11 #include "chrome/browser/extensions/extension_function.h" 11 #include "chrome/browser/extensions/extension_function.h"
12 #include "chrome/browser/speech/tts_controller.h" 12 #include "chrome/browser/speech/tts_controller.h"
13 #include "chrome/browser/speech/tts_platform.h" 13 #include "chrome/browser/speech/tts_platform.h"
14 14
15 #import <Cocoa/Cocoa.h> 15 #import <Cocoa/Cocoa.h>
16 16
17 class TtsPlatformImplMac; 17 class TtsPlatformImplMac;
18 18
19 @interface ChromeTtsDelegate : NSObject <NSSpeechSynthesizerDelegate> { 19 @interface ChromeTtsDelegate : NSObject <NSSpeechSynthesizerDelegate> {
20 @private 20 @private
21 TtsPlatformImplMac* ttsImplMac_; // weak. 21 TtsPlatformImplMac* ttsImplMac_; // weak.
22 } 22 }
23 23
24 - (id)initWithPlatformImplMac:(TtsPlatformImplMac*)ttsImplMac; 24 - (id)initWithPlatformImplMac:(TtsPlatformImplMac*)ttsImplMac;
25 25
26 @end 26 @end
27 27
28 @interface SingleUseSpeechSynthesizer : NSSpeechSynthesizer {
Nico 2013/03/14 22:45:17 Can you add a comment explaining why this exists?
dmazzoni 2013/03/14 23:29:31 Done.
Nico 2013/03/14 23:32:00 I meant a link to the openradar one, rdar:// links
29 @private
30 scoped_nsobject<NSString> utterance_;
31 bool didSpeak_;
32 }
33
34 - (id)initWithUtterance:(NSString*)utterance;
35 - (bool)startSpeakingRetainedUtterance;
36 - (bool)startSpeakingString:(NSString*)utterance;
37
38 @end
39
28 class TtsPlatformImplMac : public TtsPlatformImpl { 40 class TtsPlatformImplMac : public TtsPlatformImpl {
29 public: 41 public:
30 virtual bool PlatformImplAvailable() OVERRIDE { 42 virtual bool PlatformImplAvailable() OVERRIDE {
31 return true; 43 return true;
32 } 44 }
33 45
34 virtual bool Speak( 46 virtual bool Speak(
35 int utterance_id, 47 int utterance_id,
36 const std::string& utterance, 48 const std::string& utterance,
37 const std::string& lang, 49 const std::string& lang,
(...skipping 12 matching lines...) Expand all
50 int char_index, 62 int char_index,
51 const std::string& error_message); 63 const std::string& error_message);
52 64
53 // Get the single instance of this class. 65 // Get the single instance of this class.
54 static TtsPlatformImplMac* GetInstance(); 66 static TtsPlatformImplMac* GetInstance();
55 67
56 private: 68 private:
57 TtsPlatformImplMac(); 69 TtsPlatformImplMac();
58 virtual ~TtsPlatformImplMac(); 70 virtual ~TtsPlatformImplMac();
59 71
60 scoped_nsobject<NSSpeechSynthesizer> speech_synthesizer_; 72 scoped_nsobject<SingleUseSpeechSynthesizer> speech_synthesizer_;
61 scoped_nsobject<ChromeTtsDelegate> delegate_; 73 scoped_nsobject<ChromeTtsDelegate> delegate_;
62 int utterance_id_; 74 int utterance_id_;
63 std::string utterance_; 75 std::string utterance_;
64 bool sent_start_event_; 76 bool sent_start_event_;
65 77
66 friend struct DefaultSingletonTraits<TtsPlatformImplMac>; 78 friend struct DefaultSingletonTraits<TtsPlatformImplMac>;
67 79
68 DISALLOW_COPY_AND_ASSIGN(TtsPlatformImplMac); 80 DISALLOW_COPY_AND_ASSIGN(TtsPlatformImplMac);
69 }; 81 };
70 82
71 // static 83 // static
72 TtsPlatformImpl* TtsPlatformImpl::GetInstance() { 84 TtsPlatformImpl* TtsPlatformImpl::GetInstance() {
73 return TtsPlatformImplMac::GetInstance(); 85 return TtsPlatformImplMac::GetInstance();
74 } 86 }
75 87
76 bool TtsPlatformImplMac::Speak( 88 bool TtsPlatformImplMac::Speak(
77 int utterance_id, 89 int utterance_id,
78 const std::string& utterance, 90 const std::string& utterance,
79 const std::string& lang, 91 const std::string& lang,
80 const UtteranceContinuousParameters& params) { 92 const UtteranceContinuousParameters& params) {
93 // TODO: convert SSML to SAPI xml. http://crbug.com/88072
94 utterance_ = utterance;
95
96 NSString* utterance_nsstring =
97 [NSString stringWithUTF8String: utterance_.c_str()];
Nico 2013/03/14 22:45:17 No space after ':' (btw, clang_format can format
dmazzoni 2013/03/14 23:29:31 Done.
98
81 // Deliberately construct a new speech synthesizer every time Speak is 99 // Deliberately construct a new speech synthesizer every time Speak is
82 // called, otherwise there's no way to know whether calls to the delegate 100 // called, otherwise there's no way to know whether calls to the delegate
83 // apply to the current utterance or a previous utterance. In 101 // apply to the current utterance or a previous utterance. In
84 // experimentation, the overhead of constructing and destructing a 102 // experimentation, the overhead of constructing and destructing a
85 // NSSpeechSynthesizer is minimal. 103 // NSSpeechSynthesizer is minimal.
86 speech_synthesizer_.reset([[NSSpeechSynthesizer alloc] init]); 104 speech_synthesizer_.reset(
105 [[SingleUseSpeechSynthesizer alloc]
106 initWithUtterance:utterance_nsstring]);
87 [speech_synthesizer_ setDelegate:delegate_]; 107 [speech_synthesizer_ setDelegate:delegate_];
88 108
89 utterance_id_ = utterance_id; 109 utterance_id_ = utterance_id;
90 sent_start_event_ = false; 110 sent_start_event_ = false;
91 111
92 // TODO: convert SSML to SAPI xml. http://crbug.com/88072
93 utterance_ = utterance;
94
95 // TODO: support languages other than the default: crbug.com/88059 112 // TODO: support languages other than the default: crbug.com/88059
96 113
97 if (params.rate >= 0.0) { 114 if (params.rate >= 0.0) {
98 // The TTS api defines rate via words per minute. Let 200 be the default. 115 // The TTS api defines rate via words per minute. Let 200 be the default.
99 [speech_synthesizer_ 116 [speech_synthesizer_
100 setObject:[NSNumber numberWithInt:params.rate * 200] 117 setObject:[NSNumber numberWithInt:params.rate * 200]
101 forProperty:NSSpeechRateProperty error:nil]; 118 forProperty:NSSpeechRateProperty error:nil];
102 } 119 }
103 120
104 if (params.pitch >= 0.0) { 121 if (params.pitch >= 0.0) {
105 // The TTS api allows an approximate range of 30 to 65 for speech pitch. 122 // The TTS api allows an approximate range of 30 to 65 for speech pitch.
106 [speech_synthesizer_ 123 [speech_synthesizer_
107 setObject: [NSNumber numberWithInt:(params.pitch * 17 + 30)] 124 setObject: [NSNumber numberWithInt:(params.pitch * 17 + 30)]
108 forProperty:NSSpeechPitchBaseProperty error:nil]; 125 forProperty:NSSpeechPitchBaseProperty error:nil];
109 } 126 }
110 127
111 if (params.volume >= 0.0) { 128 if (params.volume >= 0.0) {
112 [speech_synthesizer_ 129 [speech_synthesizer_
113 setObject: [NSNumber numberWithFloat:params.volume] 130 setObject: [NSNumber numberWithFloat:params.volume]
114 forProperty:NSSpeechVolumeProperty error:nil]; 131 forProperty:NSSpeechVolumeProperty error:nil];
115 } 132 }
116 133
117 return [speech_synthesizer_ startSpeakingString: 134 return [speech_synthesizer_ startSpeakingRetainedUtterance];
118 [NSString stringWithUTF8String: utterance.c_str()]];
119 } 135 }
120 136
121 bool TtsPlatformImplMac::StopSpeaking() { 137 bool TtsPlatformImplMac::StopSpeaking() {
122 if (speech_synthesizer_.get()) { 138 if (speech_synthesizer_.get()) {
123 [speech_synthesizer_ stopSpeaking]; 139 [speech_synthesizer_ stopSpeaking];
124 speech_synthesizer_.reset(nil); 140 speech_synthesizer_.reset(nil);
125 } 141 }
126 return true; 142 return true;
127 } 143 }
128 144
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 - (void)speechSynthesizer:(NSSpeechSynthesizer*)sender 215 - (void)speechSynthesizer:(NSSpeechSynthesizer*)sender
200 didEncounterErrorAtIndex:(NSUInteger)character_index 216 didEncounterErrorAtIndex:(NSUInteger)character_index
201 ofString:(NSString*)string 217 ofString:(NSString*)string
202 message:(NSString*)message { 218 message:(NSString*)message {
203 std::string message_utf8 = base::SysNSStringToUTF8(message); 219 std::string message_utf8 = base::SysNSStringToUTF8(message);
204 ttsImplMac_->OnSpeechEvent(sender, TTS_EVENT_ERROR, character_index, 220 ttsImplMac_->OnSpeechEvent(sender, TTS_EVENT_ERROR, character_index,
205 message_utf8); 221 message_utf8);
206 } 222 }
207 223
208 @end 224 @end
225
226 @implementation SingleUseSpeechSynthesizer
227
228 - (id)initWithUtterance:(NSString*)utterance {
229 self = [super init];
230 if (self) {
231 utterance_.reset([utterance retain]);
232 didSpeak_ = false;
233 }
234 return self;
235 }
236
237 - (bool)startSpeakingRetainedUtterance {
238 CHECK(!didSpeak_);
239 CHECK(utterance_);
240 didSpeak_ = true;
241 return [super startSpeakingString:utterance_];
242 }
243
244 - (bool)startSpeakingString:(NSString*)utterance {
245 CHECK(false);
246 return false;
247 }
248
249 @end
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698