我制作了一款可在运动时使用的iPhone应用程序。它会播放铃声,表示您(用户)应该从练习例程的一个步骤切换到下一个步骤。我设计了应用程序,以便您在使用应用程序时可以在iPod上听音乐,我希望音调可以在音乐上充分发声。我已经让这个工作......有点......
当音乐响亮时,很难听到音调。我理想的解决方案类似于iPod应用程序处理传入短信或电子邮件的方式。音乐音量降低,声音播放,音乐音量逐渐消失。
以下是我迄今为止尝试过的方法:
我用AudioServicesPlaySystemSound
来播放声音。
我将声音初始化为:
CFBundleRef mainBundle = CFBundleGetMainBundle();
soundFileURLRef = CFBundleCopyResourceURL(mainBundle, CFSTR ("bell"), CFSTR ("wav"), NULL);
AudioServicesCreateSystemSoundID (soundFileURLRef, &soundFileID);
我在适当的时候使用以下方式播放声音:
AudioServicesPlaySystemSound (self.soundFileID);
这听起来很好,但听到嘈杂的音乐太难了。在尝试2 ...
我尝试降低iPod音量,播放声音,然后将音量恢复到之前的水平。
如果当前步骤还剩1秒,则开始降低音量:
if ([self.intervalSet currentStepTimeRemainingInSeconds] == 1) {
self.volumeIncrement = originalVolume/5.0f;
[NSTimer scheduledTimerWithTimeInterval:0.5f
target:self
selector:@selector(fadeVolumeOut:)
userInfo:[NSNumber numberWithInt:1]
repeats:NO];
}
以下是fadeVolumeOut:
方法:
- (void) fadeVolumeOut:(NSTimer *)timer {
if (!TARGET_IPHONE_SIMULATOR) {
NSNumber *volumeStep = (NSNumber *)[timer userInfo];
int vStep = [(NSNumber *)volumeStep intValue];
float volume = [[MPMusicPlayerController iPodMusicPlayer] volume];
volume = volume - self.volumeIncrement;
if (volume < 0.0f) {
volume = 0.0f;
}
[[MPMusicPlayerController iPodMusicPlayer] setVolume:volume];
if (vStep < 5) {
vStep = vStep + 1;
[NSTimer scheduledTimerWithTimeInterval:0.1f
target:self
selector:@selector(fadeVolumeOut:)
userInfo:[NSNumber numberWithInt:vStep]
repeats:NO];
}
}
}
然后,当步骤结束时,播放警报声并将音量淡入:
[NSTimer scheduledTimerWithTimeInterval:0.1f
target:self
selector:@selector(alertAndFadeVolumeIn)
userInfo:nil
repeats:NO];
以下是alertAndFadeVolumeIn
方法:
- (void) alertAndFadeVolumeIn {
[self alert];
[NSTimer scheduledTimerWithTimeInterval:0.25f
target:self
selector:@selector(fadeVolumeIn:)
userInfo:[NSNumber numberWithInt:1]
repeats:NO];
}
fadeVolumeIn:
基本上与上面的fadeVolumeOut:
相反。
此功能正常,音量消失,声音播放,音量逐渐消失。问题是音量降低了与iPod相同的音量,因此听起来不容易听在音乐上。
我切换到AVAudioSession
播放声音,并设置会话,以便在应用程序使用时iPod音乐将继续播放。这是我正在初始化会话的方式:
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
OSStatus propertySetError = 0;
UInt32 allowMixing = true;
propertySetError = AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryMixWithOthers,
sizeof (allowMixing),
&allowMixing
);
NSError *activationError = nil;
[session setActive:YES error:&activationError];
NSString *audioFile = [[NSBundle mainBundle] pathForResource:@"bell"
ofType:@"wav"];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:audioFile] error:NULL];
要播放声音,我会在适当的时候拨打[self.player play]
。同样,音量与iPod音量一起降低,音调也不容易听到。
我尝试在发出提示音之前放[[MPMusicPlayerController applicationMusicPlayer] setVolume:1.0f];
。结果好坏参半。第一次按照我的预期,音量以满音量播放,但随后音量会低很多。此外,音乐不会平滑淡出。似乎iPodMusicPlayer
和applicationMusicPlayer
共享相同的音量。这是使用[AVAudioSession sharedInstance];
的结果吗?是否有其他方法可以初始化AVAudioSession
?
接下来,我尝试使用AVAudioSession
“躲避”:
OSStatus propertySetError = 0;
UInt32 allowDucking = true;
propertySetError = AudioSessionSetProperty (
kAudioSessionProperty_OtherMixableAudioShouldDuck,
sizeof (allowDucking),
&allowDucking
);
不幸的是,当音频会话被激活时,iPod音乐会“躲避”,就像我一样装载viewController一样。
最后,我改变了我的代码,以便音频会话在步骤结束前一秒激活,声音在步骤结束时播放,一秒钟后,会话被停用。此时我已经删除了所有淡入淡出的代码。以下是相关的代码段:
if ([self.intervalSet currentStepTimeRemainingInSeconds] == 1) {
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
}
...
if (self.shouldRing) {
[self.player play];
[NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:@selector(stopSound)
userInfo:nil
repeats:NO];
}
...
- (void) stopSound {
[self.player stop];
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:NO error:nil];
}
这让我陷入了困境。这在第一步结束后完美地起作用。 iPod音量下降,声音大声播放,iPod音量在一秒后消失。然而,第二次步骤结束时,声音播放的声音稍微不那么大,第三次几乎听不到声音,第四次声音静音。然后,第五次,它再次大声播放,循环重复。
最重要的是,激活和停用似乎是非常繁重的操作,它们会导致定时器略微断断续续。
有没有人试图做类似的事情?有没有一种首选的方法来播放iPod音乐?
答案 0 :(得分:11)
AVAudioSession
是处理“audio behavior at the application, interapplication, and device levels.的正确方法”我在iOS 4上使用了略微修改的#6而没有任何问题。背景音频淡出,我的声音播放,背景音频消失了。
初始化音频会话(删除错误处理代码):
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil]
[audioSession setActive:NO error:nil];
播放声音(AVAudioPlayer
的播放/ prepareToPlay将activate the audio session for you):
AVAudioPlayer* audioPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil];
[audioPlayer play];
停止声音:
[audioPlayer stop];
[[AVAudioSession sharedInstance] setActive:NO withFlags:AVAudioSessionSetActiveFlags_NotifyOthersOnDeactivation error:nil];
标志kAudioSessionSetActiveFlag_NotifyOthersOnDeactivation(iOS 4新增功能)告诉系统通知背景音频以继续播放。
答案 1 :(得分:11)
按照你原来所说的你想做的正确方法是你的(5) - 使用闪避。这是交易。使用允许其他应用播放声音的音频会话类型(播放)。在你即将播放声音之前不要打开闪避。当您即将播放声音时,请打开闪避!背景音乐会立即消失,因此可以听到您的声音。然后,当你的声音播放完毕后,关闭闪避现在(这是技巧)停用音频会话并再次激活它,使背景音乐立即恢复原来的响度:
UInt32 duck = 0;
AudioSessionSetProperty(kAudioSessionProperty_OtherMixableAudioShouldDuck, sizeof(duck), &duck);
AudioSessionSetActive(false);
AudioSessionSetActive(true);
编辑:在iOS 6中,您可以(并且应该)仅使用Objective-C API完成所有这些操作。所以,开始躲避其他音频:
[[AVAudioSession sharedInstance]
setCategory: AVAudioSessionCategoryAmbient
withOptions: AVAudioSessionCategoryOptionDuckOthers
error: nil];
完成播放声音后,请关闭闪避:
[[AVAudioSession sharedInstance] setActive:NO withOptions:0 error:nil];
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient
withOptions: 0
error: nil];
[[AVAudioSession sharedInstance] setActive:YES withOptions: 0 error:nil];
答案 2 :(得分:4)
为什么不回到#2?而不是:
使用:
答案 3 :(得分:0)
适用于Xcode 8,iOS 10
<强>目的:强>
像在导航应用中一样工作(Waze / Google Maps / RideAustin) 播放您的声音,减少背景音乐音量。播放声音后,恢复背景音乐音量
<强>实施强>
初始化:
{
NSError *error = nil;
[[AVAudioSession sharedInstance]
setCategory: AVAudioSessionCategoryPlayback
withOptions: AVAudioSessionCategoryOptionDuckOthers | AVAudioSessionCategoryOptionMixWithOthers
error: nil];
[[AVAudioSession sharedInstance] setPreferredIOBufferDuration:0.005 error:&error];
...
}
播放声音时
{
...
NSError *error = nil;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];
//set delegate
player.delegate = self
...
[player play]
}
确保其他音乐播放器应用量将恢复工具
#pragma mark - AVAudioPlayerDelegate
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
...
[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
}