【问题标题】:How to play tracks from iPod music library with different volume than system volume?如何以与系统音量不同的音量播放 iPod 音乐库中的曲目?
【发布时间】:2013-01-30 15:30:08
【问题描述】:

如何以与系统音量不同的音量播放 ipod 音乐库(如用户定义的播放列表等)中的音乐?

【问题讨论】:

    标签: ios iphone avplayer volume


    【解决方案1】:

    这适用于尝试以与系统音量不同的音量播放 ipod 音乐库中的音乐/播放列表的人。有几个帖子说[MPMusicPlayerController applicationMusicPlayer]可以做到这一点,但我发现每当我改变应用程序音乐播放器的音量时,系统音量也会改变。

    还有一种使用 AVAudioPlayer 类播放音乐的复杂方法,但它需要您将音乐文件从 ipod 库复制到应用程序包,当您播放动态内容(例如用户生成的)时,这可能会变得很棘手播放列表。不过,该技术确实可以让您访问字节,如果您想对数据进行处理(如 DJ 应用程序),这是一种可行的方法。链接到该解决方案HERE

    我采用的解决方案使用 AVPlayer 类,那里有几篇关于如何做到这一点的好帖子。这篇文章基本上是我在 Stackoverflow 和其他地方找到的几种不同解决方案的组合。

    我链接了以下框架:

    AVFoundation
    媒体播放器
    音频工具箱
    核心音频
    核心媒体

    (我不确定所有这些是否都很重要,但这就是我所拥有的。我也实现了一些 OpenAL 的东西,我没有在下面的代码中显示)

    // Presumably in your SoundManage.m file (or whatever you call it) ...
    
    #import <CoreAudio/CoreAudioTypes.h>
    #import <AudioToolbox/AudioToolbox.h>
    
    @interface SoundManager()
    
    @property (retain, nonatomic) AVPlayer* audioPlayer;
    @property (retain, nonatomic) AVPlayerItem* currentItem;
    
    @property (retain, nonatomic) MPMediaItemCollection* currentPlaylist;
    @property (retain, nonatomic) MPMediaItem* currentTrack;
    @property (assign, nonatomic) MPMusicPlaybackState currentPlaybackState;
    
    @end
    
    
    @implementation SoundManager
    
    @synthesize audioPlayer;
    @synthesize currentItem = m_currentItem;
    
    @synthesize currentPlaylist;
    @synthesize currentTrack;
    @synthesize currentPlaybackState;
    
    - (id) init
    {
        ...
    
        //Define an AVPlayer instance
        AVPlayer* tempPlayer = [[AVPlayer alloc] init];
        self.audioPlayer = tempPlayer;
        [tempPlayer release];
    
        ...
    
        //load the playlist you want to play
        MPMediaItemCollection* playlist = [self getPlaylistWithName: @"emo-pop-unicorn-blood-rage-mix-to-the-max"];
        if(playlist)
            [self loadPlaylist: playlist];
    
        ...
    
        //initialize the playback state
        self.currentPlaybackState = MPMusicPlaybackStateStopped;
    
    
        //start the music playing
        [self playMusic];
    
        ...
    
    }
    
    
    //Have a way to get a playlist reference (as an MPMediaItemCollection in this case)
    - (MPMediaItemCollection*) getPlaylistWithName:(NSString *)playlistName
    {
        MPMediaQuery* query = [[MPMediaQuery alloc] init];
        MPMediaPropertyPredicate* mediaTypePredicate = [MPMediaPropertyPredicate predicateWithValue: [NSNumber numberWithInteger: MPMediaTypeMusic]                                                                              forProperty:MPMediaItemPropertyMediaType];
        [query addFilterPredicate: mediaTypePredicate];
        [query setGroupingType: MPMediaGroupingPlaylist];
    
        NSArray* playlists = [query collections];
        [query release];
    
        for(MPMediaItemCollection* testPlaylist in playlists)
        {
            NSString* testPlaylistName = [testPlaylist valueForProperty: MPMediaPlaylistPropertyName];
            if([testPlaylistName isEqualToString: playlistName])
                return testPlaylist;
        }
    
        return nil;
    }
    
    //Override the setter on currentItem so that you can add/remove 
    //the notification listener that will tell you when the song has completed
    - (void) setCurrentItem:(AVPlayerItem *)currentItem
    {
        if(m_currentItem)
        {
            [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:m_currentItem];
            [m_currentItem release];
        }
    
        if(currentItem)
            m_currentItem = [currentItem retain];
        else
            m_currentItem = nil;
    
        if(m_currentItem)
        {
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMusicTrackFinished) name:AVPlayerItemDidPlayToEndTimeNotification object:m_currentItem];
        }
    }
    
    //handler that gets called when the name:AVPlayerItemDidPlayToEndTimeNotification notification fires
    - (void) handleMusicTrackFinished
    {
        [self skipSongForward];  //or something similar
    }
    
    //Have a way to load a playlist
    - (void) loadPlaylist:(MPMediaItemCollection *)playlist
    {
        self.currentPlaylist = playlist;
        self.currentTrack = [playlist.items objectAtIndex: 0];
    }
    
    //Play the beats, yo
    - (void) playMusic
    {
        //check the current playback state and exit early if we're already playing something
        if(self.currentPlaybackState == MPMusicPlaybackStatePlaying)
            return;
    
        if(self.currentPlaybackState == MPMusicPlaybackStatePaused)
        {
            [self.audioPlayer play];
        }
        else if(self.currentTrack)
        {
            //Get the system url of the current track, and use that to make an AVAsset object
            NSURL* url = [self.currentTrack valueForProperty:MPMediaItemPropertyAssetURL];
            AVAsset* asset = [AVURLAsset URLAssetWithURL:url options:nil];
    
            //Get the track object from the asset object - we'll need to trackID to tell the
            //AVPlayer that it needs to modify the volume of this track
            AVAssetTrack* track = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    
            //Build the AVPlayerItem - this is where you modify the volume, etc. Not the AVPlayer itself
            AVPlayerItem* playerItem = [[AVPlayerItem alloc] initWithAsset: asset]; //initWithURL:url];
            self.currentItem = playerItem;
    
            //Set up some audio mix parameters to tell the AVPlayer what to do with this AVPlayerItem
            AVMutableAudioMixInputParameters* audioParams = [AVMutableAudioMixInputParameters audioMixInputParameters];
            [audioParams setVolume: 0.5 atTime:kCMTimeZero];  //replace 0.5 with your volume
            [audioParams setTrackID: track.trackID];  //here's the track id
    
            //Set up the actual AVAudioMix object, which aggregates effects
            AVMutableAudioMix* audioMix = [AVMutableAudioMix audioMix];
            [audioMix setInputParameters: [NSArray arrayWithObject: audioParams]];
    
            //apply your AVAudioMix object to the AVPlayerItem
            [playerItem setAudioMix:audioMix];
    
            //refresh the AVPlayer object, and play the track
            [self.audioPlayer replaceCurrentItemWithPlayerItem: playerItem];
            [self.audioPlayer play];
    
        }
    
        self.currentPlaybackState = MPMusicPlaybackStatePlaying;
    }
    
    - (void) pauseMusic
    {   
        if(self.currentPlaybackState == MPMusicPlaybackStatePaused)
            return;
    
        [self.audioPlayer pause];
    
        self.currentPlaybackState = MPMusicPlaybackStatePaused;
    }
    
    - (void) skipSongForward
    {
        //adjust self.currentTrack to be the next object in self.currentPlaylist
        //start the new track in a manner similar to that used in -playMusic
    }
    
    - (void) skipSongBackward
    {
        float currentTime = self.audioPlayer.currentItem.currentTime.value / self.audioPlayer.currentItem.currentTime.timescale;
    
        //if we're more than a second into the song, just skip back to the beginning of the current track
        if(currentTime > 1.0)
        {
            [self.audioPlayer seekToTime: CMTimeMake(0, 1)];
        }
        else
        {
            //otherwise, adjust self.currentTrack to be the previous object in self.currentPlaylist
            //start the new track in a manner similar to that used in -playMusic
        }
    }
    
    //Set volume mid-song - more or less the same process we used in -playMusic
    - (void) setMusicVolume:(float)vol
    {
        AVPlayerItem* item = self.audioPlayer.currentItem;
    
        AVAssetTrack* track = [[item.asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    
        AVMutableAudioMixInputParameters* audioParams = [AVMutableAudioMixInputParameters audioMixInputParameters];
        [audioParams setVolume: vol atTime:kCMTimeZero];
        [audioParams setTrackID: track.trackID];
    
        AVMutableAudioMix* audioMix = [AVMutableAudioMix audioMix];
        [audioMix setInputParameters: [NSArray arrayWithObject: audioParams]];
    
        [item setAudioMix:audioMix];
    }
    
    
    @end
    

    请原谅您看到的任何错误 - 请在 cmets 中告诉我,我会修复它们。否则,如果有人遇到与我相同的挑战,我希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      其实我通过loading iPod URL's from MPMusicPlayer 找到了一个非常简单的方法来做到这一点,然后通过 AVAudioPlayer 进行播放。

      // Get-da iTunes player thing
      MPMusicPlayerController* iTunes = [MPMusicPlayerController iPodMusicPlayer]; 
      
      // whazzong
      MPMediaItem *currentSong = [iTunes nowPlayingItem];
      
      // whazzurl
      NSURL *currentSongURL = [currentSong valueForProperty:MPMediaItemPropertyAssetURL];
      
      info( "AVAudioPlayer playing %s", [currentSongURL.absoluteString UTF8String] ) ;
      
      // mamme AVAudioPlayer
      NSError *err;
      avAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:currentSongURL error:&err] ;
      if( err!=nil )
      {
        error( "AVAudioPlayer couldn't load %s", [currentSongURL.absoluteString UTF8String] ) ;
      }
      avAudioPlayer.numberOfLoops = -1; //infinite
      
      // Play that t
      [avAudioPlayer prepareToPlay] ;
      [avAudioPlayer play];
      
      [avAudioPlayer setVolume:0.5]; // set the AVAUDIO PLAYER's volume to only 50%. This
      // does NOT affect system volume. You can adjust this music volume anywhere else too.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-01
        • 2012-10-20
        • 1970-01-01
        • 1970-01-01
        • 2013-10-28
        相关资源
        最近更新 更多