iOS 音频

作者: owenqi | 来源:发表于2017-02-10 11:56 被阅读223次

    iOS 音频播放

    • 本地音频文件 AVPlayer / AVAudioPlayer
    • 在线音频流 AVPlayer
    • iPod 歌曲 AVPlayer / AVAudioPlayer / MPMusicPlayerController
    • 音效 AudioServices

    iPod 音乐

    • iPod 歌曲的读取
      • MPMediaPickerController 系统封装的, 包括 UI
      • MPMediaLibrary + MPMediaQuery 系统封装的读取类, 不包含 UI
    • iPod 歌曲的读取权限
      • 权限相关接口: iOS 9.3+
      • iPod 读取权限弹窗: iOS 9.3+ 暂时不会直接提醒弹窗权限, 在 iOS10 加入了弹窗
      • 权限用途的说明文案: iOS 10+; Xcode 8+ 必须要在 info.plist 写明 NSAppleMusicUsageDescription
    • 使用 MPMediaPickerController 读取
    @interface MPMediaPickerController : UIViewController
    
    @property (nonatomic, readonly) MPMediaType mediaTypes;
    @property (nonatomic, weak, nullable) id<MPMediaPickerControllerDelegate> delegate;
    @property (nonatomic) BOOL allowsPickingMultipleItems;
    @property (nonatomic) BOOL showsCloudItems;
    @property (nonatomic) BOOL showsItemsWithProtectedAssets;
    @property (nonatomic, copy, mullable) NSString *prompt; 
    
    @protocol MPMediaPickerControllerDelegate <NSObject>
    - (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection;
    - (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker;
    
    @interface MPMediaItemCollection : MPMediaEntity
    
    @interface MPMediaItem : MPMediaEntity
    
    • [musicPlayer prepareToPlay] 将选中的音乐放进播放列表中

      • 直接调用 play 方法也可以达到将歌曲放入播放列表中的效果
    • 播放状态

        /*** MPMusicPlaybackState ***/
        MPMusicPlaybackStateStopped
        MPMusicPlaybackStatePlaying         // 播放
        MPMusicPlaybackStatePaused          // 暂停
        MPMusicPlaybackStateInterrupted     // 中断状态
        MPMusicPlaybackStateSeekingForward  // 线控时播放状态
        MPMusicPlaybackStateSeekingBackword // 线控时播放状态
      
    • 播放状态的通知

        MPMusicPlayerControllerPlaybackStateDidChangeNotification
      
    • 播放进度

    • 切歌

      @interface MPMusicPlayerController (MPPlaybackControl)
      - (void)skipToNextItem;     // 下一曲
      - (void)skipToPreviousItem; // 上一曲
      
    • 播放模式

        repeatMode
            MPMusicRepeatModeDefault
            MPMusicRepeatModeNone
            MPMusicRepeatModeOne
            MPMusicRepeatModeAll        
        shuffleMode
            MPMusicShuffleModeDefault
            MPMusicShuffleModeOff
            MPMusicShuffleModeSongs
            MPMusicShuffleModeAlbums
      
    • 定义自己的播放模式

      typedef NS_ENUM (NSUInteger, AudioPlayerMode) {
          AudioPlayerModeRepeat,
          AudioPlayerModeSingle,
          AudioPlayerModeRandom,
      }
      - (void)setMode:(AudioPlayerMode)mode {
          _mode = mode;
          if (mode == AudioPlayerModeRepeat) {
              _musicPlayer.repeatMode  =  MPMusicRepeatModeAll;
              _musicPlayer.shuffleMode =  MPMusicShuffleModeOff;
          } else if (mode == AudioPlayerModeSingle) {
              _musicPlayer.repeatMode  =  MPMusicRepeatModeOne;
              _musicPlayer.shuffleMode =  MPMusicShuffleModeOff;
          } else if (mode == AudioPlayerModeRandom) {
              _musicPlayer.repeatMode  =  MPMusicRepeatModeAll;
              _musicPlayer.shuffleMode =  MPMusicShuffleModeSongs;
          }
      }
      
    • applicationMusicPlayer & systemMusicPlayer

      • 都是调用系统的音乐 app 进行播放
      • 不同
        • applicationMusicPlayer 不会改变系统正在播放的歌曲
        • systemMusicPlayer 会改变系统自动播放的歌曲, 相当于直接在系统音乐中进行播放

    优势

    - 接口完全封装, 使用简单
    - 不关心播放模式, 播放列表的维护
    - 不关心其他的问题, 例如打断
    

    问题

    - 只能播放 iPod 歌曲
    - 不是自己的 app 在后台播放, 而是调用系统的音乐 app 在播放
    - 进入系统选歌界面或者使用 MPMediaLibrary 歌曲会停止, 播放列表会清空
    

    自行实现 iPod 歌曲选择

    • MPMediaLibrary
    类型 资源
    在线音频流 音频 URL AVURLAsset
    本地音频文件 音频文件 AVURLAsset
    iPod 歌曲 Music.app 中的歌曲 MPMediaItem
    • Metadata

      • 音频信息
        • 歌名
        • 专辑
        • 歌手
        • 封面图
      • 音频数据 - 听到的音乐
    • commonMetadata & metadata

      • commonMetadata 共有格式的数据内容
      • metadata 不一定通用的格式

    AVPlayer

    • 在线
    • 本地
    • iPod

    AVPlayerItem

    • 代表一个播放对象
    • 加载状态
    • 播放总时长
    • 进行 seek 操作

    AVQueuePlayer

    初始化

    • 在线歌曲不能获取 metadata, 所以对于在线歌曲就不获取 metadata
    • 使用 rate 控制播放状态
    • 使用在线音频的时候不能直接做立即播放

    AudioSession

    后台播放

    1. Set AudioSession Category & Active
    2. Set App Background Mode
    3. [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]

    管理输入输出设备

    NowPlayingCenter


    录音

    AudioSession

    1. 获取录音权限 + 填写使用理由
      • AVAudioSessionRecordPermission permission = [[AVAudioSession sharedInstance] recordPermission];
    2. set Category
      • [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:nil];
      • [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    3. set Active
      • [[AVAudioSession sharedInstance] setActive:YES error:nil];
    4. 处理打断或设备更换

    AVAudioRecorder

    #import <AVFoundation/AVFoundation.h>
    NSString *const AVNumberOfChannelsKey; // 声道数
    NSString *const AVSampleRateKey; // 采样率
    NSString *const AVLinearPCMBitDepthKey; // 位声
    NSString *const AVFormatIDKey;
    /* ------ AVFormatIDKey ------
    kAudioFormatLinearPCM     = 'lpcm'
    kAudioFormatApplelMA4     = 'ima4'
    kAudioFormatMPEG4AAc      = 'aac'
    kAudioFormatULaw          = 'ulaw'
    kAudioFormatALaw          = 'alaw'
    kAudioFormatAppleLossless = 'alac'
    */
    
    • PCM 文件: 最原始的未经过处理的录音文件
      • 等同于: WAV
      • 压缩成: AAC, MP3(有损压缩), FLAC(无损压缩), ...
      • iOS 不能直接录制成 MP3 格式
    NSString *filePath = [NSTemporaryDirectory() stringByAppendingFileComponent:@"tempRecord.aac"];
    NSDictionary *settings = @{
        AVNumberOfChannelsKey : @1,
        AVSampleRateKey : @8000,
        AVLinearPCMBitDepthKey : @16,
        AVFormatIDKey : @(kAudioFormatMPEG4AAC)
    };
    NSError *error = nil;
    // 生成 recorder
    _recorder = [[AVAudioRecorder alloc] initWithURL:[NSURL fileURLWithPath:filePath] settings:settings error:&error];
    

    创建文件

    开始录音

    - (BOOL)preparedToRecord;
    - (BOOL)record;
    - (BOOL)recordAtTime:(NSTimeInterval)time; // 开始时间
    - (BOOL)recordForDuration:(NSTimeInterval)duration; // 录音时长
    - (BOOL)recordAtTime:(NSTimeInterval)time forDuration:(NSTimeInterval)duration;
    

    录音停止和文件操作

    - (void)pause;
    - (void)stop;
    - (BOOL)deleteRecording;
    @property BOOL recording;
    @property NSURL *url;
    @property NSTimeInterval currentTime; // 当前录音进行的时间
    

    AVAudioPlayer

    • 不支持播放模式
    • 调整左右声道
    • 调整播放器内部的音量
    • 调整播放速率
    • 读取播放歌曲的数据参数, 例如采样率
    • 读取某个时间点的歌曲声音大小

    资源类型

    类型 资源
    在线音频流 音频 URL AVURLAsset
    本地音频文件 音频文件 AVURLAsset
    iPod歌曲 Music.app中的歌曲 MPMediaItem

    AVURLAsset �: AVAsset

    /*  AVAsset  */
    @interface AVAsset : NSObject
    + assetWithURL:(NSURL *)URL;
    @property (notatomic, readonly) CMTime duration;
    
    @property NSArray *commomMetadata;
    @property NSArray *metadata;
    
    /*  AVURLAsset  */
    @interface AVURLAsset : AVAsset
    + URLAssetWithURL: options: ;
    - initWithURL: options: ;
    
    @property NSURL *URL;
    // 继承子 AVAsset 后提供了两个初始化方法
    // 提供 URL 属性的访问
    // 提供 metadata 的读取
    

    Metadata

    • 音频数据 : 听到的音乐
    • 音频信息 : 歌名, 专辑, 歌手, 封面 等

    创建 AVURLAsset

    • 三种资源转换成 AVURLAsset
    // 在线音频
    NSURL *audioURL = [NSURL URLWithString:@"http://xxx.com/music.mp3"];
    AVURLAsset *audioAsset = [AVURLAsset assetWithURL:audioURL];
    
    // 本地音频
    NSString *filePath = [[NSBundle mainBundle] pathForResources:@"music" ofType:@"mp3"];
    NSURL *fileURL = [NSURL fireURLWithPath:filePath];
    AVURLAsset *fileAsset = [AVURLAsset assetWithURL:fileURL];
    
    // iPod 音频
    MPMediaQuery *query = [MPMediaQuery songsQuery];
    if (query.items.count > 0) {
        MPMediaItem *item = query.item[0];
        AVURLAsset *iPodAsset = [AVURLAsset assetWithURL:item.assetURL];
    }
    

    AVAudioPlayer

    • 初始化方法
      • 尽量使用带有 fileTypeHint 的初始化方法, 并填入 hint
      • 如果使用 URL 作为参数, 尽量让其带有后缀名, 例如: xxx.mp3
      • 使用 URL 作为参数时只能是本地文件的 URL, 不能是网络 URL 地址
    @interface AVAudioPlayer : NSObject
    
    - initWithContentOfURL: error: ;
    - initWithData: error: ;
    
    - initWithContentOfURL: fileTypeHint: error: ; // 表示单个歌曲
    - initWithData: fileTypeHint: error: ;
    
    • fileTypeHint : 文件类型的判断, 帮助解码器判断, 使得解码不容易出错

    相关文章

      网友评论

        本文标题:iOS 音频

        本文链接:https://www.haomeiwen.com/subject/ykegittx.html