iOS音频播放相关

第一类:有的软件会播放背景音乐和音效,并且可以控制音乐和音效的开关控制,下面进行这种效果的分析

工具类创建需求
1.创建一个专门管理音乐和音效的单例类
2.设置播放音乐、音效的两个属性方法,和两个是否播放音乐、音效的BOOL属性。(音乐播放方法是为了在APPDelegate中调用)
3.设置两个BOOL属性的get方法,这样当外界更改这两个方法的时候,可以立即做出对应的改变,在get方法中最对应的相关操作 e.g.使用对象序列化来保存状态,音乐的开关可以在这里进行开关操作。

当需要播放音乐的时候调用属性方法,在属性方法里面进行音乐BOOL属性的判断,如果不播放直接return,如果播放则调用播放方法。(音乐播放不需要传入音乐名称,因为一般为固定的一个)

当需要播放音效的时候调用属性方法,在属性方法里面进行音效BOOL属性的判断,如果不播放直接return,如果播放则调用音效方法。(音效播放需要传入音效名称)

工具类初始化
在这个工具类里面初始化时需要需要调用直接调用加载音乐和加载音效的方法,两个BOOL属性值需要从对象序列化中取出,取出时就会调用get方法。e.g.音乐是否播放在这里设置

音效的播放每次都要传入要播放的文件名

专门写一个.h文件把音效,音乐等文件名写成一个#define来防止写错。

加载资源的时候一次全部加载完成

#pragma mark 加载背景音乐
- (void)loadBgMusic
{
    // 1.获得背景音乐的URL
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"bg_music.mp3" withExtension:nil];

    // 2.加载播放器
    _bgMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
    // 缓冲
    [_bgMusicPlayer prepareToPlay];
    // 无限循环
    _bgMusicPlayer.numberOfLoops = -1;
}

#pragma mark 加载音效 一次全部加载完
- (void)loadSounds
{
    // 1.初始化字典
    _soundIDs = [NSMutableDictionary dictionary];

    // 2.加载sound.bundle
    NSURL *bundleURL = [[NSBundle mainBundle] URLForResource:@"sound" withExtension:@"bundle"];
    NSBundle *soundBundle = [NSBundle bundleWithURL:bundleURL];

    // 3.获得sound.bundle中所有mp3文件的URL
    NSArray *mp3URLs = [soundBundle URLsForResourcesWithExtension:@"mp3" subdirectory:nil];

    // 4.根据每个mp3的URL加载soundID
    for (NSURL *url in mp3URLs)
    {
        SystemSoundID soundID;
        // 5.加载音频ID
        AudioServicesCreateSystemSoundID((__bridge CFURLRef )url, &soundID);

        // 6.获得文件名
        NSString *filename = [url.path lastPathComponent];

        // 7.将音频ID和文件名放入字典
        [_soundIDs setObject:@(soundID) forKey:filename];
    }
}

第二类:音乐播放APP

写一个工具类专门进行播放、暂停、停止等操作
再专门写一个工具类进行上一首、下一首操作

#pragma mark - 传入需要播放的音效文件
+(void)playAudioWithFileName:(NSString *)fileName
{
    //容错判断
    if (fileName == nil) return;
    //取出音效ID
    SystemSoundID soundID = [[self soundIDs][fileName] unsignedIntValue];
    //容错判断
    if (!soundID)
    {
        //创建URL
        NSURL *url = [[NSBundle mainBundle] URLForResource:fileName withExtension:nil];
        //容错判断
        if (!url) return;
        //创建音效ID 传一个URL 一个SystemSoundID 报错fix就好
        AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &soundID);
        //添加到字典中
        [self soundIDs][fileName] = @(soundID);
    }
    // 播放音效
//    AudioServicesPlaySystemSound(soundID);
    // 播放音效带点震动
    AudioServicesPlayAlertSound(soundID);
}
#pragma mark - 销毁音效文件
+(void)disposeAudioWithFileName:(NSString *)fileName
{
    //容错判断
    if (!fileName) return;
    //从字典中取出音效ID
    SystemSoundID soundID = [[self soundIDs][fileName] unsignedIntValue];
    //容错判断
    if (soundID)
    {
        //销毁音效ID
        AudioServicesDisposeSystemSoundID(soundID);
        //从字典中移除
        [[self soundIDs] removeObjectForKey:fileName];
    }
}
#pragma mark - 根据音乐文件播放音乐文件
+(AVAudioPlayer *)playMusicWithFileName:(NSString *)fileName
{
    if (!fileName) return nil;
    //从字典中取出播放器
    AVAudioPlayer *player = [self players][fileName];
    //判断播放器是否为nil
    if (!player) {
        //根据文件名加载音效URL
        NSURL *url = [[NSBundle mainBundle] URLForResource:fileName withExtension:nil];
        if (!url) return nil;
        //创建播放器
        player = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];
//        NSLog(@"playMusicWithFileName");
        //准备播放(缓冲提高播放的流畅性)
        if (![player prepareToPlay]) return nil;

        // 允许快进
//        player.enableRate = YES;
//        player.rate = 3;

        //添加到字典中
        [self players][fileName] = player;
    }
    //判断是否在播放
    if (!player.isPlaying) {
        //播放(异步播放)
        [player play];
    }
    return player;

    /*
     时长
     @property(readonly) NSTimeInterval duration;
     当前的播放位置
     @property NSTimeInterval currentTime;
     播放次数(-1代表无限循环播放,其他代表播放numberOfLoops+1次)
     @property NSInteger numberOfLoops;
     音量
     @property float volume;
     是否允许更改速率
     @property BOOL enableRate;
     播放速率(1是正常速率,0.5是一般速率,2是双倍速率)
     @property float rate;
     有多少个声道
     @property(readonly) NSUInteger numberOfChannels;
     声道(-1是左声道,1是右声道,0是中间)
     @property float pan;
     是否允许测量音量
     @property(getter=isMeteringEnabled) BOOL meteringEnabled;
     更新测量值
     - (void)updateMeters;
     获得当前的平均音量
     - (float)averagePowerForChannel:(NSUInteger)channelNumber;
     */
}
#pragma mark - 根据音乐名暂停播放音乐文件
+(void)pauseMusicWithFileName:(NSString *)fileName
{
    if (fileName == nil) return;

    //从字典中取出播放器
    AVAudioPlayer *player = [self players][fileName];

    if (player)
    {
        //如果正在播放就停止播放
        if (player.playing)
        {
            [player pause];
        }
    }
}

#pragma mark - 根据音乐名停止播放音乐文件
+(void)stopMusicWithFileName:(NSString *)fileName
{
    if (!fileName) return;

    //从字典中取出播放器
    AVAudioPlayer *player = [self players][fileName];

    if (player)
    {
        [player stop];
        player = nil;
        //从字典中移除播放器
        [[self players] removeObjectForKey:fileName];
    }
}
后台播放
-(void)applicationDidEnterBackground:(UIApplication *)application
{
    //开启后台任务
    UIBackgroundTaskIdentifier identifier = [application beginBackgroundTaskWithExpirationHandler:^{
        [application endBackgroundTask:identifier];
    }];

    //在plist文件中添加 Required background modes 设为音乐

    //设置会话类型让我放的时候把其他停掉
}

在工具类中设置
//设置会话类型 //这个方法保证只在第一次创建时调用
+(void)initialize
{
    NSLog(@"initialize");
    //创建音频会话
    AVAudioSession *session = [[AVAudioSession alloc]init];
    //设置会话类型
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];
    //激活会话
    [session setActive:YES error:nil];
}
打断操作
#pragma mark - AVAudioPlayerDelegate
// 播放结束时调用
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    // 下一曲
    [self downMusic:nil];
}

// 播放器被打断时调用(例如电话)
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
    // 暂停
    if (self.audioPlayer.playing) {
        [QCFAudioTool pauseMusicWithFileName:[_array objectAtIndex:_index]];
    }
}

// 播放器打断结束
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player
{
    // 继续播放
    if (!self.audioPlayer.playing) {
        [self play:nil];
    }
}
锁屏界面显示内容
#pragma mark - 在锁屏中添加内容 更新也会调用
-(void)lockContext
{
    // 1.播放信息中心
    MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];

    // 2.初始化播放信息
    NSMutableDictionary *info = [NSMutableDictionary dictionary];
    //锁屏上面显示的信息
    info[MPMediaItemPropertyAlbumTitle] = @"专辑名称";
    info[MPMediaItemPropertyArtist] = @"歌手";
    info[MPMediaItemPropertyTitle] = @"歌曲名称";
    info[MPMediaItemPropertyArtwork] = [[MPMediaItemArtwork alloc]initWithImage:[UIImage imageNamed:@"123"]];
    //显示文字就是把文字画在图片上

    //设置持续时间(歌曲总时间)
    info[MPMediaItemPropertyPlaybackDuration] = @"12.12";
    //设置当前播放的进度
    info[MPNowPlayingInfoPropertyElapsedPlaybackTime] = @"22";


    // 3.切换播放信息
    center.nowPlayingInfo = info;

    // 4.开始监听远程事件
    // 4.1 成为第一相应者 (必须设置)
    [self becomeFirstResponder];
    // 4.2 开始监控
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

}

#pragma mark - 远程控制事件监听
-(BOOL)canBecomeFirstResponder
{
    return YES;
}

-(void)remoteControlReceivedWithEvent:(UIEvent *)event
{
//    event.subtype;//事件的子类型
    /*
     UIEventSubtypeNone
     UIEventSubtypeMotionShake
     UIEventSubtypeRemoteControlPlay
     UIEventSubtypeRemoteControlPause
     UIEventSubtypeRemoteControlStop
     UIEventSubtypeRemoteControlTogglePlayPause
     UIEventSubtypeRemoteControlNextTrack
     UIEventSubtypeRemoteControlPreviousTrack
     UIEventSubtypeRemoteControlBeginSeekingBackward
     UIEventSubtypeRemoteControlEndSeekingBackward
     UIEventSubtypeRemoteControlBeginSeekingForward
     UIEventSubtypeRemoteControlEndSeekingForward
     */

    switch (event.subtype) {
        case UIEventSubtypeRemoteControlPlay:
        {
            NSLog(@"播放点击");
        }break;

        case UIEventSubtypeRemoteControlPause:
        {
            NSLog(@"暂停点击");
        }break;

        case UIEventSubtypeRemoteControlNextTrack:
        {
            NSLog(@">>>下一首点击");
        }break;

        case UIEventSubtypeRemoteControlPreviousTrack:
        {
            NSLog(@"<<<上一首点击");
        }break;

        default: break;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值