我正在研究基于VoIP的IOS应用程序。
有两种播放声音的方法可以在来电时通知用户:
UILocalNotification
声音。声音将持续最多30秒; setKeepAliveTimeout:handler:
功能中播放本地音乐素材。但系统只给我10秒的时间来进行操作。有没有办法像本机手机应用程序一样永久播放声音?
答案 0 :(得分:1)
我害怕@Dan2552是正确的。
这是Apple states:
的内容不支持持续时间超过30秒的声音。如果你 指定一个播放超过30秒的声音的文件,默认值 而是播放声音。
修改强>
使用AVAudioPlayer
AVFoundation
,可以播放音频文件超过30秒(或永远,为此)
@import AVFoundation; // module -> no need to link the framework
// #import <AVFoundation/AVFoundation.h> // old style
- (void)playAudio
{
NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"mp3"];
NSError *error = nil;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
if (!error) {
player.numberOfLoops = -1; // infinite loop
[player play];
} else {
NSLog(@"Audio player init error: %@", error.localizedDescription);
}
}
然后,必须在主线程上调用此方法,而不是设置本地通知的soundName属性:
[self performSelectorOnMainThread:@selector(playAudio) withObject:nil waitUntilDone:NO];
答案 1 :(得分:1)
伊斯兰问答问题的答案是,AVAudioPlayer无法处理通知,因为当您不使用该应用时,应用会被静音。只有UILocalNotification可以让您的应用在未激活时发出声音。 30秒的限制是真实的。应该通过另外30秒通知重复通知来完成。我不知道其他VOIP应用程序会持续响多长时间,但即使使用传统手机,通常也会有限制,例如一分钟。
我的策略是:
这将允许用户1:40的时间来响应呼叫。
您的代码看起来像这样:
UILocalNotification* notification = [[UILocalNotification alloc] init];
notification.alertBody = NSLocalizedString(@"FIRST_CALL", @"%@ is calling you!");
notification.soundName = @"normal_ring.mp3";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(40 * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
if (!phone.isRinging)
{
// Somebody picked it up already in the mean time
return;
}
UILocalNotification* notification = [[UILocalNotification alloc] init];
notification.alertBody = NSLocalizedString(@"HURRY_CALL", @"Hurry, you are about to miss a call from %@!");
notification.soundName = @"hurry_ring.mp3";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
if (!phone.isRinging)
{
// Somebody picked it up already in the mean time
return;
}
UILocalNotification* notification = [[UILocalNotification alloc] init];
notification.alertBody = NSLocalizedString(@"MISSED_CALL", @"You've just missed a call from %@");
notification.soundName = @"missed_call.mp3";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
});
});
如果您使用该代码,请记住您首先需要确保该应用程序在后台,因此UILocalNotification将是您唯一的选择。当它在前台时使用普通的AVAudioPlayer,更加灵活。第二件事是当用户响应呼叫时应用程序成为前台,因此它应该使警报静音并让AVAudioPlayer接管。
您希望警报和应用内声音之间或多或少平滑过渡,以便为您的用户提供完美的体验,因此最好的办法是测量响铃之间的时间,让AVAudioPlayer完全正确启动新循环开始时的时间。
您的第二个问题是让应用程序在后台运行。这个简单的代码将一直用于轮询应用程序,然后保持活着。它直接来自一个正常工作的应用程序,此代码轮询定时器是否仍在运行并在以下时间内休眠五秒钟:
UIBackgroundTaskIdentifier backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[timerExecuted timerUpdate];
while (!timerExecuted.isStopped)
{
[NSThread sleepForTimeInterval:5];
}
[application endBackgroundTask:backgroundTask];
});