简体   繁体   English

iOS AVPlayer流媒体音乐问题

[英]iOS AVPlayer streaming music issues

I'm having some really weird issues with AVPlayer . 我对AVPlayer有一些非常奇怪的问题。 I have a very simple music player (which streams sample music from the iTunes store) working with it correctly on the simulator (both iPhone and iPad with iOS 5.1) but it behaves abnormally on a real device. 我有一个非常简单的音乐播放器(从iTunes商店流式传输样本音乐)在模拟器上正确使用它(iPhone和iPad都带有iOS 5.1),但它在真实设备上表现异常。

On an iPad 2 with iOS 5.1.1 it plays correctly even if I connect my headphones to the device. 在带有iOS 5.1.1的iPad 2上,即使我将耳机连接到设备,它也能正常播放。 But as soon as I disconnect them it won't play a sound through the speakers (even though if I connect them again I can listen to the song). 但是一旦我断开它们就不会通过扬声器发出声音(即使我再次连接它们,我也可以听这首歌)。

On an iPhone 4 with iOS 5.1 installed it doesn't seem to play at all through the speakers but I can listen to the music through my headphones. 在安装了iOS 5.1的iPhone 4上,它似乎不能通过扬声器播放,但我可以通过耳机收听音乐。 Although it doesn't seem to be playing through the speakers I can hear now and then for a very brief moment the music playing (and can confirm that it in fact is playing because my UI responds accordingly) although it seems to be random. 虽然它似乎没有通过扬声器播放,我可以偶尔听到音乐播放的短暂时间(并且可以确认它实际上正在播放,因为我的UI响应相应)虽然它似乎是随机的。

I'm using AVPlayer since it seems to fit the requirements. 我正在使用AVPlayer因为它似乎符合要求。 Should I use another library? 我应该使用其他图书馆吗? Do I need to manually route the sound? 我需要手动路由声音吗? Why am I having these types of problems? 为什么我遇到这些类型的问题? And am I using Audio Sessions correctly? 我正确使用音频会话吗?

Media.h: Media.h:

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>

#define NOT_PLAYING -1

@protocol MediaDelegate <NSObject>
@optional
- (void) didEndPlayingAtIndex:(int) index;
- (void) startedToPlayAtIndex:(int) index;
- (void) stoppedToPlayAtIndex:(int) index;
- (void) startedToPlayAtIndex:(int) to fromIndex:(int) from;
- (void) pausedAtIndex:(int) index;
@end

@interface Media : NSObject <AVAudioSessionDelegate>

@property (nonatomic, assign) int currentItem;
@property (nonatomic, strong) NSURL *url;
@property (nonatomic, strong) AVPlayer *player;
@property (nonatomic, assign) id<MediaDelegate> delegate;

- (void) toggle:(int) index;
- (void) stop;

@end

Media.m: Media.m:

#import "Media.h"

@implementation Media

@synthesize currentItem;
@synthesize player;
@synthesize delegate;
@synthesize url;

- (id)init
{
    self = [super init];
    if (self) {
        NSError *activationError = nil;
        NSError *setCategoryError = nil;
        AVAudioSession *session = [AVAudioSession sharedInstance];
        session.delegate = self;
        [session setActive:YES error:&activationError];
        [session setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];

        if(activationError || setCategoryError)
            NSLog(@"ERROR: %@, %@",activationError,setCategoryError);

        self.currentItem = NOT_PLAYING;
    }
    return self;
}

- (void)dealloc{
    NSError *activationError = nil;
    [[AVAudioSession sharedInstance] setActive:NO error:&activationError];

    if(activationError)
        NSLog(@"ERROR: %@",activationError);

    [self.player removeObserver:self forKeyPath:@"status"];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{    
    switch (player.status) {
        case AVPlayerItemStatusReadyToPlay:
            [self.player play];
            if([self.delegate respondsToSelector:@selector(startedToPlayAtIndex:)])
                [self.delegate startedToPlayAtIndex:self.currentItem];
            break;
        default:
            break;
    }
}

- (void) toggle:(int) index{
    if (self.currentItem == NOT_PLAYING) {
        self.player = [AVPlayer playerWithPlayerItem:[AVPlayerItem playerItemWithURL:self.url]];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(didEnd:)
                                                     name:AVPlayerItemDidPlayToEndTimeNotification 
                                                   object:self.player];
        self.currentItem = index;
        [self.player addObserver:self forKeyPath:@"status" options:0 context:nil];
    }
    else {
        if (self.currentItem == index) {
            [self.player pause];
            if([self.delegate respondsToSelector:@selector(stoppedToPlayAtIndex:)])
                [self.delegate stoppedToPlayAtIndex:index];
            self.currentItem = NOT_PLAYING;
            [self.player removeObserver:self forKeyPath:@"status"];
            self.player = nil;
            [[NSNotificationCenter defaultCenter] removeObserver:self];
        }
        else{
            [self.player replaceCurrentItemWithPlayerItem:[AVPlayerItem playerItemWithURL:self.url]];
            if([self.delegate respondsToSelector:@selector(startedToPlayAtIndex:fromIndex:)])
                [self.delegate startedToPlayAtIndex:index fromIndex:self.currentItem];
            self.currentItem = index;
        }
    }
}

- (void) stop{
    [self.player pause];
    if([self.delegate respondsToSelector:@selector(stoppedToPlayAtIndex:)])
        [self.delegate stoppedToPlayAtIndex:self.currentItem];
}

-(void) didEnd:(id)sender{
    if([self.delegate respondsToSelector:@selector(didEndPlayingAtIndex:)])
        [self.delegate didEndPlayingAtIndex:self.currentItem];
    self.currentItem = NOT_PLAYING;
    [self.player removeObserver:self forKeyPath:@"status"];
    self.player = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - AVAudioSession delegate

-(void)beginInterruption{
    NSLog(@"Interruption");
    if(self.currentItem != NOT_PLAYING){
        [self.player pause];
        if([self.delegate respondsToSelector:@selector(pausedAtIndex:)])
            [self.delegate pausedAtIndex:self.currentItem];
    }
}

-(void)endInterruption{
    NSLog(@"Ended interruption");
    if(self.currentItem != NOT_PLAYING){
        [self.player play];
        if([self.delegate respondsToSelector:@selector(startedToPlayAtIndex:)])
            [self.delegate startedToPlayAtIndex:self.currentItem];
    }
}

@end

It looks like you have a problem with correct audio routing. 看起来你有正确的音频路由问题。 I suggest to add an audio route change listener callback. 我建议添加一个音频路由更改侦听器回调。 First of all declare a method: 首先声明一个方法:

void audioRouteChangeListenerCallback(void *inUserData, AudioSessionPropertyID inPropertyID, UInt32 inPropertyValueSize, const void *inPropertyValue);

Then in your init method add a callback: 然后在你的init方法中添加一个回调:

// Prevent from audio issues when you pull out earphone
AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, audioRouteChangeListenerCallback, (__bridge void *)(self));

And finally, add a callback implementation: 最后,添加一个回调实现:

void audioRouteChangeListenerCallback(void *inUserData, AudioSessionPropertyID inPropertyID, UInt32 inPropertyValueSize, const void *inPropertyValue) {
    if (inPropertyID != kAudioSessionProperty_AudioRouteChange) {
        return;
    }

    CFDictionaryRef routeChangeDictionary = inPropertyValue;
    CFNumberRef     routeChangeReasonRef  = CFDictionaryGetValue(routeChangeDictionary, CFSTR(kAudioSession_AudioRouteChangeKey_Reason));
    SInt32          routeChangeReason;
    CFNumberGetValue(routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);

    if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {
        // Headset is unplugged..
        NSLog(@"Headset is unplugged..");
        // Delayed play: 0.5 s.
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
            [CORE.player play]; // NOTE: change this line according your current player implementation
            NSLog(@"resumed play");
        });
    }
    if (routeChangeReason == kAudioSessionRouteChangeReason_NewDeviceAvailable) {
        // Headset is plugged in..
        NSLog(@"Headset is plugged in..");
    }
}

Hope this help! 希望这有帮助! At least for other people it will be helpful tip. 至少对其他人来说,这将是有用的提示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM