我正在使用AVSpeechSynthesizer播放文字。我有一系列的话语可以玩。
NSMutableArray *utterances = [[NSMutableArray alloc] init];
for (NSString *text in textArray) {
AVSpeechUtterance *welcome = [[AVSpeechUtterance alloc] initWithString:text];
welcome.rate = 0.25;
welcome.voice = voice;
welcome.pitchMultiplier = 1.2;
welcome.postUtteranceDelay = 0.25;
[utterances addObject:welcome];
}
lastUtterance = [utterances lastObject];
for (AVSpeechUtterance *utterance in utterances) {
[speech speakUtterance:utterance];
}
我有一个取消按钮停止说话。当我说出第一个话语时单击取消按钮时,语音停止并清除队列中的所有话语。如果在说出第一个话语(即第二个话语)之后按下取消按钮,则停止讲话不会刷新话语队列。我正在使用的代码是:
[speech stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
有人可以确认这是API中的错误还是我错误地使用了API?如果是错误,是否有解决此问题的解决方法?
答案 0 :(得分:23)
我找到了解决方法:
- (void)stopSpeech
{
if([_speechSynthesizer isSpeaking]) {
[_speechSynthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:@""];
[_speechSynthesizer speakUtterance:utterance];
[_speechSynthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
}
}
调用stopSpeakingAtBoundary:
,将空话发入队列并再次致电stopSpeakingAtBoundary:
以停止并清理队列。
答案 1 :(得分:5)
很可能是一个错误,因为在第一个话语之后没有调用委托方法合成器didCancelSpeechUtterance ;
解决方法是链接话语而不是将它们放在数组中并立即排队。
使用委托方法 synthesizer didFinishSpeechUtterance 递增数组指针并说出该数组中的下一个文本。然后,在尝试停止语音时,在尝试说出下一个文本之前设置在此委托方法中检查的BOOL。
例如:
1)在正在进行语音合成的视图控制器中实现协议
#import <UIKit/UIKit.h>
@import AVFoundation;
@interface ViewController : UIViewController <AVSpeechSynthesizerDelegate>
@end
2)实例化AVSpeechSynthesizer并将其委托设置为self
speechSynthesizer = [AVSpeechSynthesizer new];
speechSynthesizer.delegate = self;
3)使用话语计数器,在开始讲话时设置为零
4)使用一系列文字说话
textArray = @[@"Mary had a little lamb, its fleece",
@"was white as snow",
@"and everywhere that Mary went",
@"that sheep was sure to go"];
5)添加委托方法didFinishSpeechUtterance来说出数组中的下一个话语 文本和增加话语计数器
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance{
if(utteranceCounter < utterances.count){
AVSpeechUtterance *utterance = utterances[utteranceCounter];
[synthesizer speakUtterance:utterance];
utteranceCounter++;
}
}
5)停止说话,将话语计数器设置为文本数组的计数,并尝试让合成器停止
utteranceCounter = utterances.count;
BOOL speechStopped = [speechSynthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
if(!speechStopped){
[speechSynthesizer stopSpeakingAtBoundary:AVSpeechBoundaryWord];
}
6)再次发言时,将话语计数器重置为零
答案 2 :(得分:2)
这里的所有答案都失败了,我想出的就是停止合成器,然后重新实例化它:
- (void)stopSpeech
{
if([_speechSynthesizer isSpeaking]) {
[_speechSynthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
_speechSynthesizer = [AVSpeechSynthesizer new];
_speechSynthesizer.delegate = self;
}
}
答案 3 :(得分:1)
我做了类似SPA提到的事情。从循环中一次说出一个项目。 这是想法..
NSMutableArray *arr; //array of NSStrings, declared as property
AVSpeechUtterance *currentUtterence; //declared as property
AVSpeechSynthesizer *synthesizer; //property
- (void) viewDidLoad:(BOOL)anim
{
[super viewDidLoad:anim];
synthesizer = [[AVSpeechSynthesizer alloc]init];
//EDIT -- Added the line below
synthesizer.delegate = self;
arr = [self populateArrayWithString]; //generates strings to speak
}
//assuming one thread will call this
- (void) speakNext
{
if (arr.count > 0)
{
NSString *str = [arr objectAtIndex:0];
[arr removeObjectAtIndex:0];
currentUtterence = [[AVSpeechUtterance alloc] initWithString:str];
//EDIT -- Commentted out the line below
//currentUtterence.delegate = self;
[synthesizer speakUtterance:utteranc];
}
}
- (void)speechSynthesizer:(AVSpeechSynthesizer *)avsSynthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance
{
if ([synthesizer isEqual:avsSynthesizer] && [utterance isEqual:currentUtterence])
[self speakNext];
}
- (IBOutlet) userTappedCancelledButton:(id)sender
{
//EDIT <- replaced the object the method gets called on.
[synthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
[arr removeAllObjects];
}
答案 4 :(得分:1)
didCancelSpeechUtterance不能使用相同的AVSpeechSynthesizer对象,即使话语是在didFinishSpeechUtterance方法中链接的。
-(void)speakInternal
{
speech = [[AVSpeechSynthesizer alloc] init];
speech.delegate = self;
[speech speakUtterance:[utterances objectAtIndex:position++]];
}
在speakInternal中,我多次创建AVSpeechSynthesizer对象以确保didCancelSpeechUtterance有效。一种解决方法。