录音

来源:互联网 发布:spring源码深度解析pdf 编辑:程序博客网 时间:2024/04/27 14:15

http://www.devdiv.com/forum.php?mod=viewthread&tid=125220


9.5 在其他活动声音上面播放音频

问题
你可能想在播放音频时让其他程序静音,或者在其他程序的音频回放之上播放音频。

解决
使用音频会话设置你的应用程序所使用的音频类别。

讨论
AVAudioSession类由AVFoundation框架引入。每个IOS应用都有一个音频会话。这个会话可以被AVAudioSession类的sharedInstance类方法访问,如下:
AVAudioSession *audioSession = [AVAudioSession sharedInstance];

在获得一个AVAudioSession类的实例后,你就能通过调用音频会话对象的setCategory:error:实例方法,来从IOS应用可用的不同类别中作出选择。下面列出了可供使用的音频会话类别:
AVAudioSessionCategorySoloAmbient

这个类别非常像AVAudioSessionCategoryAmbient类别,除了会停止其他程序的音频回放,比如iPod程序。当设备被设置为静音模式,你的音频回放将会停止。

AVAudioSessionCategoryRecord
这会停止其他应用的声音(比如iPod)并让你的应用也不能初始化音频回放(比如AVAudioPlayer)。在这种模式下,你只能进行录音。使用这个类别,调用AVAudioPlayer的prepareToPlay会返回YES,但是调用play方法将返回NO。主UI界面会照常工作。这时,即使你的设备屏幕被用户锁定了,应用的录音仍会继续。

AVAudioSessionCategoryPlayback
这个类别会静止其他应用的音频回放(比如iPod应用的音频回放)。你可以使用AVAudioPlayer的prepareToPlay和play方法,在你的应用中播放声音。主UI界面会照常工作。这时,即使屏幕被锁定或者设备为静音模式,音频回放都会继续。

AVAudioSessionCategoryPlayAndRecord
这个类别允许你的应用中同时进行声音的播放和录制。当你的声音录制或播放开始后,其他应用的声音播放将会停止。主UI界面会照常工作。这时,即使屏幕被锁定或者设备为静音模式,音频回放和录制都会继续。

AVAudioSessionCategoryAudioProcessing
这个类别用于应用中进行音频处理的情形,而不是音频回放或录制。设置了这种模式,你在应用中就不能播放和录制任何声音。调用AVAPlayer的prepareToPlay和play方法都将返回NO。其他应用的音频回放,比如iPod,也会在此模式下停止。

AVAudioSessionCategoryAmbient
这个类别不会停止其他应用的声音,相反,它允许你的音频播放于其他应用的声音之上,比如iPod。你的应用的主UI县城会工作正常。调用AVAPlayer的prepareToPlay和play方法都将返回YES。当用户锁屏时,你的应用将停止所有正在回放的音频。仅当你的应用是唯一播放该音频文件的应用时,静音模式将停止你程序的音频回放。如果正当iPod播放一手歌时,你开始播放音频,将设备设为静音模式并不能停止你的音频回放。

9.7 为视频文件捕获缩略图

问题
你在使用MPMoviePlayerController类的实例播放一个视频文件时,可能想要在某个时刻从影片捕获一张截图。

解决
使用MPMoviePlayerController的requestThumbnailImagesAtTimes:timeOption:实例方法,如下:

/* Capture the frame at the third second into the movie */ NSNumber *thirdSecondThumbnail = [NSNumber numberWithFloat:3.0f];
/* We can ask to capture as many frames as we
want. But for now, we are just asking to capture one frame */
NSArray *requestedThumbnails =
[NSArray arrayWithObject:thirdSecondThumbnail];
/* Ask the movie player to capture this frame for us */
[self.moviePlayer
requestThumbnailImagesAtTimes:requestedThumbnails timeOption:MPMovieTimeOptionExact];
讨论
MPMoviePlayerController的一个实例能够从最近播放的影片中捕获缩略图,同步和异步都可以。在这里,我们将关注这个类的异步图像捕获。

我们可以使用MPMoviePlayerController的requestThumbnailImagesAtTimes:timeOption:实例方法来异步访问缩略图。当我说“异步”时,我的意思是,在缩略图正在被捕获和被报告给你指派的对象(我们很快能看到)的过程中,视频播放器将继续它的工作,且不会阻塞回放。我们必须观察MPMoviePlayerThumbnailImage RequestDidFinishNotification通知消息,这个消息由视频播放器发送给默认消息中心,以便知道我们的缩略图什么时候可用:

- (void) startPlayingVideo:(id)paramSender{
/* First let's construct the URL of the file in our application bundle
that needs to get played by the movie player */ NSBundle *mainBundle = [NSBundle mainBundle];
NSString *urlAsString = [mainBundle pathForResource:@"Sample"
ofType:@"m4v"];
NSURL *url = [NSURL fileURLWithPath:urlAsString];
/* If we have already created a movie player before, let's try to stop it */
if (self.moviePlayer != nil){
[self stopPlayingVideo:nil]; }
/* Now create a new movie player using the URL */
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];
if (self.moviePlayer != nil){
/* Listen for the notification that the movie player sends us whenever it finishes playing an audio file */
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(videoHasFinishedPlaying:) name:MPMoviePlayerPlaybackDidFinishNotification object:self.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(videoThumbnailIsAvailable:)
name:MPMoviePlayerThumbnailImageRequestDidFinishNotification object:self.moviePlayer];
NSLog(@"Successfully instantiated the movie player.");
/* Scale the movie player to fit the aspect ratio */ self.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
/* Let's start playing the video in full screen mode */ [self.moviePlayer play];
[self.view addSubview:self.moviePlayer.view];
[self.moviePlayer setFullscreen:YES animated:YES];
/* Capture the frame at the third second into the movie */ NSNumber *thirdSecondThumbnail = [NSNumber numberWithFloat:3.0f];
/* We can ask to capture as many frames as we
want. But for now, we are just asking to capture one frame */
NSArray *requestedThumbnails =
[NSArray arrayWithObject:thirdSecondThumbnail];
/* Ask the movie player to capture this frame for us */ [self.moviePlayer
requestThumbnailImagesAtTimes:requestedThumbnails timeOption:MPMovieTimeOptionExact];
} else {
NSLog(@"Failed to instantiate the movie player."); }
}
你可以看到,我们我们要求视频播放器捕获影片中第三秒的那个帧。一旦这个任务完成,我们的视图控制器的videoThumbnailIsAvailable:实例方法就会被调用,下面的代码说明了我们如何能访问被捕获的图像:

- (void) videoThumbnailIsAvailable:(NSNotification *)paramNotification{ MPMoviePlayerController *controller = [paramNotification object];
if (controller != nil &&
[controller isEqual:self.moviePlayer]){ NSLog(@"Thumbnail is available");
/* Now get the thumbnail out of the user info dictionary */ UIImage *thumbnail =
[paramNotification.userInfo
objectForKey:MPMoviePlayerThumbnailImageKey];
if (thumbnail != nil){
/* We got the thumbnail image. You can now use it here */
} }
}

因为我们在startPlayingVideo:中实例化视频播放器时,开始了监听MPMoviePlayerThumbnailImageRequestDidFinishNotifi cation
通知,所以也必须在我们停止视频播放器时,停止对这个通知的监听(或者任何你在你的应用框架中认为恰当的时间)。

- (void) stopPlayingVideo:(id)paramSender { if (self.moviePlayer != nil){
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:self.moviePlayer];
[[NSNotificationCenter defaultCenter]
removeObserver:self name:MPMoviePlayerThumbnailImageRequestDidFinishNotification object:self.moviePlayer];
[self.moviePlayer stop];
if ([self.moviePlayer.view.superview isEqual:self.view]){ [self.moviePlayer.view removeFromSuperview];
} }
}

当在调用MPMoviePlayerController的requestThumbnailImagesAtTimes:timeOption:实例方法时,我们可以为timeOption:指定MPMovie TimeOptionExact 或者MPMovieTimeOptionNearestKeyFrame其中之一。前者捕获视频时间线上精确的点,后者虽然不那么精确,但使用更少的系统资源,并在捕获缩略图时整体上有更好的表现。MPMovieTimeOptionNearestKey Frame通常能胜任精确要求,因为它仅仅有那么一两帧的误差。


9.8 访问音乐库

问题
你想要访问用户从她的音乐库中挑选的物品。

解决
使用MPMediaPickerController类:
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc]
initWithMediaTypes:MPMediaTypeAny];
讨论
MPMediaPickerController是一个iPod程序显示给用户的视图控制器。只要实例化MPMediaPickerController,你就可以为你的用户展现一个标准的视图控制器,让他们任意从音乐库中进行选择,然后控制重新返回到你的程序中。这点对游戏特别有用,例如,用户玩游戏时,可以让你的程序在背景播放它最喜爱的歌曲。

你可以用成为媒体选择控制器的委托(遵守MPMediaPickerControllerDelegate协议)的方式从它那里获得信息:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
@interface Accessing_the_Music_LibraryViewController
: UIViewController <MPMediaPickerControllerDelegate>
@end

在你的displayMediaPicker:选择器中,实现所需的代码,来显示媒体选择控制器实例并且向用户展现一个模态视图控制器:
- (void) displayMediaPicker{
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeAny];
if (mediaPicker != nil){
NSLog(@"Successfully instantiated a media picker."); mediaPicker.delegate = self; mediaPicker.allowsPickingMultipleItems = NO;
[self.navigationController presentModalViewController:mediaPicker animated:YES];
} else {
NSLog(@"Could not instantiate a media picker."); }
}

媒体选择控制器的allowsPickingMultipleItems属性,让你指定用户能否在隐藏控制器之前选择多于一个物品。它接受一个BOOL值,目前我们就把它设置为NO,稍后我们会看到效果。现在,让我们来实现MPMediaPickerControllerDelegate协议的各种委托消息:
- (void) mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection{
NSLog(@"Media Picker returned");
for (MPMediaItem *thisItem in mediaItemCollection.items){
NSURL [thisItem
NSString [thisItem
NSString [thisItem
*itemURL = valueForProperty:MPMediaItemPropertyAssetURL];
*itemTitle = valueForProperty:MPMediaItemPropertyTitle];
*itemArtist = valueForProperty:MPMediaItemPropertyArtist];
MPMediaItemArtwork *itemArtwork =
[thisItem valueForProperty:MPMediaItemPropertyArtwork];
NSLog(@"Item URL = %@", itemURL); NSLog(@"Item Title = %@", itemTitle); NSLog(@"Item Artist = %@", itemArtist); NSLog(@"Item Artwork = %@", itemArtwork);
}
[mediaPicker dismissModalViewControllerAnimated:YES]; }
你可以使用MPMediaItem的valueForProperty:实例方法访问不同的属性。这个类的实例通过mediaPicker:didPick MediaItems:委托消息的mediaItemCollection参数返回到你的程序中。

现在让我们写一个带有很简单的GUI的一个程序,它允许我们询问用户,来从iPod库中选择一个音乐。在她选择了音乐文件后,我们尝试使用MPMusicPlayerController实例来播放它。我们的GUI有个简单的按钮:“选择”和“播放”,以及“停止播放”。第一个按钮会要用户从iPod库中选择一段音频给我们播放,第二个按钮会停止音频回放(如果我们已经在播放音频了)。我们会从程序的UI设计开始。让我们以简单的方式创建,就像图9-1那样。

图9-1 一个极简单的UI,展示了媒体选择器和AV音频播放器

现在让我们继续在视图控制器的.h中定义这两个按钮:
@interface Accessing_the_Music_LibraryViewController : UIViewController <MPMediaPickerControllerDelegate, AVAudioPlayerDelegate>
@property (nonatomic, strong) MPMusicPlayerController *myMusicPlayer; @property (nonatomic, strong) UIButton *buttonPickAndPlay;
@property (nonatomic, strong) UIButton *buttonStopPlaying;
@end

当我们的视图加载完毕,我们会实例化这两个按钮们将他们放置于视图之上:
- (void)viewDidLoad { [super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.buttonPickAndPlay = [UIButton buttonWithType:UIButtonTypeRoundedRect]; self.buttonPickAndPlay.frame = CGRectMake(0.0f,
0.0f, 200, 37.0f);
self.buttonPickAndPlay.center = CGPointMake(self.view.center.x, self.view.center.y - 50);
[self.buttonPickAndPlay setTitle:@"Pick and Play" forState:UIControlStateNormal];
[self.buttonPickAndPlay addTarget:self action:@selector(displayMediaPickerAndPlayItem)
forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:self.buttonPickAndPlay];
self.buttonStopPlaying = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.buttonStopPlaying.frame = CGRectMake(0.0f, 0.0f,
200, 37.0f);
self.buttonStopPlaying.center = CGPointMake(self.view.center.x,
self.view.center.y + 50); [self.buttonStopPlaying setTitle:@"Stop Playing"
forState:UIControlStateNormal]; [self.buttonStopPlaying addTarget:self
action:@selector(stopPlayingAudio) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.buttonStopPlaying];
[self.navigationController setNavigationBarHidden:YES animated:NO];
}

视图控制器的两个最重要的方法是displayMediaPicker 和 PlayItem and stopPlayingAudio:
- (void) stopPlayingAudio{
if (self.myMusicPlayer != nil){
[[NSNotificationCenter defaultCenter]
removeObserver:self name:MPMusicPlayerControllerPlaybackStateDidChangeNotification object:self.myMusicPlayer];
[[NSNotificationCenter defaultCenter]
removeObserver:self name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification object:self.myMusicPlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMusicPlayerControllerVolumeDidChangeNotification object:self.myMusicPlayer];
[self.myMusicPlayer stop]; }
}
- (void) displayMediaPickerAndPlayItem{
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc]
initWithMediaTypes:MPMediaTypeMusic]; if (mediaPicker != nil){
NSLog(@"Successfully instantiated a media picker."); mediaPicker.delegate = self; mediaPicker.allowsPickingMultipleItems = YES;
[self.navigationController presentModalViewController:mediaPicker animated:YES];
} else {
NSLog(@"Could not instantiate a media picker.");
} }

当我们的媒体选择控制器成功完成,mediaPicker:didPickMediaItems消息会在委托对象中被调用(这个例子中就是视图控制器)。另一方面,如果用户取消了媒体播放器,我们会得到mediaPicker:mediaPickerDid Cancel消息。下面的代码实现了每种情况下将会被调用的方法。
- (void) mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection{
NSLog(@"Media Picker returned");
/* First, if we have already created a music player, let's deallocate it */
self.myMusicPlayer = nil;
self.myMusicPlayer = [[MPMusicPlayerController alloc] init]; [self.myMusicPlayer beginGeneratingPlaybackNotifications];
/* Get notified when the state of the playback changes */ [[NSNotificationCenter defaultCenter]
addObserver:self selector:@selector(musicPlayerStateChanged:)
name:MPMusicPlayerControllerPlaybackStateDidChangeNotification object:self.myMusicPlayer];
/* Get notified when the playback moves from one item
to the other. In this recipe, we are only going to allow our user to pick one music file */
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(nowPlayingItemIsChanged:) name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification object:self.myMusicPlayer];
/* And also get notified when the volume of the music player is changed */
[[NSNotificationCenter defaultCenter]
addObserver:self selector:@selector(volumeIsChanged:)
name:MPMusicPlayerControllerVolumeDidChangeNotification object:self.myMusicPlayer];
/* Start playing the items in the collection */
[self.myMusicPlayer setQueueWithItemCollection:mediaItemCollection]; [self.myMusicPlayer play];
/* Finally dismiss the media picker controller */ [mediaPicker dismissModalViewControllerAnimated:YES];
}
- (void) mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker{
/* The media picker was cancelled */
NSLog(@"Media Picker was cancelled");
[mediaPicker dismissModalViewControllerAnimated:YES];
}

我么在监听音乐播放器通过通知发送的事件。下面是用于处理被监听的音乐播放器通知消息的三个方法:
- (void) musicPlayerStateChanged:(NSNotification *)paramNotification{ NSLog(@"Player State Changed");
/* Let's get the state of the player */ NSNumber *stateAsObject = [paramNotification.userInfo
objectForKey:@"MPMusicPlayerControllerPlaybackStateKey"]; NSInteger state = [stateAsObject integerValue];
/* Make your decision based on the state of the player */ switch (state){
case MPMusicPlaybackStateStopped:{
/* Here the media player has stopped playing the queue. */
break; }
case MPMusicPlaybackStatePlaying:{
/* The media player is playing the queue. Perhaps you
can reduce some processing that your application that is using to give more processing power
to the media player */ break;
}
case MPMusicPlaybackStatePaused:{
/* The media playback is paused here. You might want to indicate by showing graphics to the user */
break; }
case MPMusicPlaybackStateInterrupted:{
/* An interruption stopped the playback of the media queue */
break; }
case MPMusicPlaybackStateSeekingForward:{
/* The user is seeking forward in the queue */
break; }
case MPMusicPlaybackStateSeekingBackward:{
/* The user is seeking backward in the queue */
break; }
} /* switch (State){ */ }
                -  (void) nowPlayingItemIsChanged:(NSNotification *)paramNotification{ NSLog(@"Playing Item Is Changed"); 
NSString *persistentID = [paramNotification.userInfo 
objectForKey:@"MPMusicPlayerControllerNowPlayingItemPersistentIDKey"]; 
/* Do something with Persistent ID */ NSLog(@"Persistent ID = %@", persistentID); 
} 
                -  (void) volumeIsChanged:(NSNotification *)paramNotification{ 
NSLog(@"Volume Is Changed"); 
/* The userInfo dictionary of this notification is normally empty */ } 

我们还会实现视图控制器的viewDidUnload方法,来确保不会留下任何内存泄漏:
        .        - (void) viewDidUnload{ [super viewDidUnload]; 
[self stopPlayingAudio]; 
self.myMusicPlayer = nil; }
接下来,运行我们的程序,点击视图控制器的“点击”和“播放”按钮,我们会看到媒体选择控制器。一旦控制器出现,和iPod相同的UI将展现给用户。在用户选择了一项之后(或者取消整个对话框),我们会在视图控制器中得到相应的委托消息(当我们的视图控制器是媒体选择器的视图控制器时)。在物品被选择后(在这里我们只允许选一个),我们会开始我们的音乐播放器,并开始播放整个选择集合。
如果你想允许用户一次选择多于一项,只要设置你的媒体选择器的allowsPickingMultipleItems属性为YES:
mediaPicker.allowsPickingMultipleItems = YES;

有时,当在使用媒体选择控制器时(MPMedia PickerController),“MPMediaPicker:失去到iPod库的连接”消息将会输出到控制台屏幕。这是因为媒体选择器在显示给用户时,因为诸如iTunes同步这样的事件而被打断。这时,你的mediaPickerDidCancel:委托方法立刻会被调用。


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 没有做税种核定开了票怎么办 在学信网上查不到学历信息怎么办 学信网手机号换了密码忘了怎么办 学信网手机号换了密码也忘了怎么办 学信网上学习形式是星号怎么办 新手机号已被注册微店买家怎么办 微信号被冻结了里面的钱怎么办 不懂公司产品却要接待老外怎么办 上菜时发现桌面摆不下新菜怎么办 超市买到过期产品商家不赔尝怎么办 皇帝成长计划2俘虏的士兵怎么办 晚上楼上有挪桌子的声音怎么办 金灶茶具出故障码e7怎么办 起亚k2灯泡掉进大灯总成怎么办 衣服上拆过线的针孔怎么办 驾考科目二坡道定点熄火怎么办 穿着超短裤感觉要漏屁股怎么办 台式电脑开机后无法进入系统怎么办 产后两年了肚子肥胖松弛怎么办 在作文中写上自己的名字怎么办 外出玩耍时迷路了你会怎么办 外出玩耍时孩子总喜欢乱跑怎么办? 如果真的物价高的受不了怎么办 每晚要5次真的受不了怎么办 五年级的学生钢笔字写不好怎么办 全麻醉药过后让人产生幻觉怎么办? 网贷小象优品上被别人冒用了怎么办 当你和老人产生冲突时该怎么办 百度网盘会员到期后容量怎么办 一个人不停的给你发视频聊天怎么办 被谋杀后的身后事应该怎么办 社保交了五年被单位辞退怎么办 桅子花叶子变黄叶杆蔫怎么办 薄荷养的都黄了干掉了怎么办 被烟草局没收的烟要是假烟怎么办 干了10年工程不想干了怎么办 在服务行业当服务员干不下去怎么办 高中生晚上偷着跑出去玩怎么办 货车高速忘记过安全检查站了怎么办 u盘上的文件名称乱码了怎么办 暖气管掉进去一点水泥渣怎么办