AVAudioPlayer 从 C++ 开始回调调用 audioPlayerDidFinishPlaying 不知为何晚了
您能给我一些关于问题可能出在哪里的提示吗?我对 ObjC 很陌生,所以我有点陷入困境。
我使用 C++ 构建的库来生成各种声音,我想使用 AVAudioPlayer 来播放这些声音。然而,我观察到 audioPlayerDidFinishPlaying 的某种令人惊讶的行为。我将在下面的例子中进行说明。
这是我的 .h 文件(省略了不相关的内容):
#import <AVFoundation/AVFoundation.h>
@interface mytest_appViewController : UIViewController <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
....
}
void HaveSoundCallback(const short *psSamples, long lSamplesNum, void *pOwner);
....
@property (nonatomic, retain) AVAudioPlayer *player;
@end
这是实现的一部分:
....
#import "MyCplusplusSoundGeneratingLibrary.h"
....
- (IBAction)GoButtonTouched:(UIButton *)sender{
// calling the C++ made GenerateSound and passing it the callback
int ret=GenerateSound(couple_of_parameters, HaveSoundCallback, self);
}
通常我不知道GenerateSound函数会产生多少声音(每次调用),但每当它产生一个声音时,它调用 HaveSoundCallback 来处理它(它还发送“self”作为声音的“所有者”)。
现在这是回调实现(它位于相同的 .mm 中,但在 @implementation...@end 之外):
void HaveSoundCallback(const short *psSamples, long lSamplesNum, void *pOwner){
NSString *OutWave;
NSLog(@"Entered the callback function");
OutWave=[pOwner getDocumentFile:@"out.wav"];
[pOwner SaveSoundData:OutWave pcm:psSamples len:lSamplesNum];
[pOwner PlaySound:OutWave];
[OutWave release];
}
这意味着回调函数将声音数据保存到 wav(通过调用 SaveSoundData),然后调用 PlaySound 来播放它们。 PlaySound 和 audioPlayerDidFinishPlaying 实现再次位于 mytest_appViewController 类中:
- (void)PlaySound:(NSString *)WaveFile{
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:WaveFile];
NSLog(@"Playing started");
self.player =[[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
self.player.delegate = self;
[self.player play];
while (self.player.playing) {
sleep(0.01);
}
[fileURL release];
NSLog(@"Playing finished");
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)p successfully:(BOOL)flag
{
NSLog(@"hi from audioPlayerDidFinishPlaying");
}
我故意在 while 循环中等待,以防止播放器同时播放所有可能返回的声音 - 在播放器停止播放当前声音后会发生另一个回调。但我想触发player.delegate完成的播放。因此,为了我的实验(和 ObjC“自学”)目的,我实现了 audioPlayerDidFinishPlaying 委托。
现在是测试情况:假设GenerateSound 产生3 种声音(它们之间有很短的延迟)。我希望输出控制台类似于:
Entered the callback function
Playing started
hi from audioPlayerDidFinishPlaying
Playing finished
Entered the callback function
Playing started
hi from audioPlayerDidFinishPlaying
Playing finished
Entered the callback function
Playing started
hi from audioPlayerDidFinishPlaying
Playing finished
但不是这样,而是在最后调用了 audioPlayerDidFinishPlaying 3 次,即:
Entered the callback function
Playing started
Playing finished
Entered the callback function
Playing started
Playing finished
Entered the callback function
Playing started
Playing finished
hi from audioPlayerDidFinishPlaying
hi from audioPlayerDidFinishPlaying
hi from audioPlayerDidFinishPlaying
我做错了什么?为什么当播放真正结束时,audioPlayerDidFinishPlaying 没有立即执行,而是堆在某处,最后执行了 3 次?
这是否与程序实际上一直在C++库函数GenerateSound内部有关,因此一旦离开GenerateSound就执行audioPlayerDidFinishPlaying?如果是,有没有更好的方法来实现我想要获得的功能?
预先非常感谢您的帮助!
could you please give me any tips on where the problem might be? I'm very new to ObjC, so I sort of got stuck.
I use a C++ built library which generates various sounds and I would like to play these sounds using AVAudioPlayer. However, I observe some kind of suprising behaviour of audioPlayerDidFinishPlaying. I'll illustrate it on the following example.
This is my .h file (with the irrelevant stuff left out):
#import <AVFoundation/AVFoundation.h>
@interface mytest_appViewController : UIViewController <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
....
}
void HaveSoundCallback(const short *psSamples, long lSamplesNum, void *pOwner);
....
@property (nonatomic, retain) AVAudioPlayer *player;
@end
And this is one part of the implementation:
....
#import "MyCplusplusSoundGeneratingLibrary.h"
....
- (IBAction)GoButtonTouched:(UIButton *)sender{
// calling the C++ made GenerateSound and passing it the callback
int ret=GenerateSound(couple_of_parameters, HaveSoundCallback, self);
}
Generally I don't know how many sounds the GenerateSound function will produce (per one calling), but whenever it produces one, it calls HaveSoundCallback that is supposed to take care of it (it also sends "self" as the "owner" of the sound).
Now this is the callback implementation (it's in the same .mm but outside @implementation...@end):
void HaveSoundCallback(const short *psSamples, long lSamplesNum, void *pOwner){
NSString *OutWave;
NSLog(@"Entered the callback function");
OutWave=[pOwner getDocumentFile:@"out.wav"];
[pOwner SaveSoundData:OutWave pcm:psSamples len:lSamplesNum];
[pOwner PlaySound:OutWave];
[OutWave release];
}
It means that the callback function saves the sound data to a wav (by calling SaveSoundData) and then it calls PlaySound to play them. PlaySound and audioPlayerDidFinishPlaying implementation are again in the mytest_appViewController class:
- (void)PlaySound:(NSString *)WaveFile{
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:WaveFile];
NSLog(@"Playing started");
self.player =[[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
self.player.delegate = self;
[self.player play];
while (self.player.playing) {
sleep(0.01);
}
[fileURL release];
NSLog(@"Playing finished");
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)p successfully:(BOOL)flag
{
NSLog(@"hi from audioPlayerDidFinishPlaying");
}
I intentionally wait here in the while loop so as to prevent the player from playing all possible returning sounds concurrently - another callback happens after the player stops playing the current sound. But I would like to trigger the finished playing by the player.delegate. So for my experimental (and ObjC "self-tutoring") purposes I implemented the audioPlayerDidFinishPlaying delegate.
And now the testing situation: lets say that GenerateSound produces 3 sounds (with short delays between them). I would expect the output console to be something like:
Entered the callback function
Playing started
hi from audioPlayerDidFinishPlaying
Playing finished
Entered the callback function
Playing started
hi from audioPlayerDidFinishPlaying
Playing finished
Entered the callback function
Playing started
hi from audioPlayerDidFinishPlaying
Playing finished
But instead of this, the audioPlayerDidFinishPlaying is called at the very end 3 times, i.e.:
Entered the callback function
Playing started
Playing finished
Entered the callback function
Playing started
Playing finished
Entered the callback function
Playing started
Playing finished
hi from audioPlayerDidFinishPlaying
hi from audioPlayerDidFinishPlaying
hi from audioPlayerDidFinishPlaying
What do I do wrong? Why isn't the audioPlayerDidFinishPlaying executed immediately when the playing really finished, and instead it gets stacked somewhere and is executed 3 times at the end?
Has it something to do with the fact that the program is actually all the time inside the C++ library function GenerateSound, and thus the audioPlayerDidFinishPlaying is executed as soon as GenerateSound is left? And if yes, is there any better way implement the functionality which I'd like to get?
Thanks a lot in advance for any help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论