mirror of
https://github.com/oonyeje/Get-Hip.git
synced 2025-12-25 11:47:41 +00:00
262 lines
7.6 KiB
Objective-C
Executable File
262 lines
7.6 KiB
Objective-C
Executable File
//
|
|
// TDAudioPlayer.m
|
|
// TDAudioPlayer
|
|
//
|
|
// Created by Tony DiPasquale on 10/16/13.
|
|
// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT).
|
|
//
|
|
|
|
#import <AVFoundation/AVFoundation.h>
|
|
#import <MediaPlayer/MediaPlayer.h>
|
|
|
|
#import "TDAudioPlayer.h"
|
|
|
|
@interface TDAudioPlayer ()
|
|
|
|
@property (strong, nonatomic) TDAudioInputStreamer *streamer;
|
|
@property (strong, nonatomic) NSMutableDictionary *nowPlayingMetaInfo;
|
|
@property (assign, nonatomic) TDAudioPlayerState state;
|
|
|
|
@property (strong, nonatomic) NSTimer *timer;
|
|
@property (assign, nonatomic) NSUInteger elapsedTime;
|
|
|
|
@end
|
|
|
|
@implementation TDAudioPlayer
|
|
|
|
+ (instancetype)sharedAudioPlayer
|
|
{
|
|
static TDAudioPlayer *player;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
player = [[TDAudioPlayer alloc] init];
|
|
});
|
|
return player;
|
|
}
|
|
|
|
- (instancetype)init
|
|
{
|
|
self = [super init];
|
|
if (!self) return nil;
|
|
|
|
[[AVAudioSession sharedInstance] setActive:YES error:nil];
|
|
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionDidInterrupt:) name:AVAudioSessionInterruptionNotification object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionDidChangeRoute:) name:AVAudioSessionRouteChangeNotification object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioDidStartPlaying) name:TDAudioStreamDidStartPlayingNotification object:nil];
|
|
|
|
return self;
|
|
}
|
|
|
|
#pragma mark - Audio Loading
|
|
|
|
- (void)loadAudioFromURL:(NSURL *)url
|
|
{
|
|
[self loadAudioFromURL:url withMetaData:nil];
|
|
}
|
|
|
|
- (void)loadAudioFromURL:(NSURL *)url withMetaData:(TDAudioMetaInfo *)meta
|
|
{
|
|
[self reset];
|
|
self.streamer = [[TDAudioInputStreamer alloc] initWithURL:url];
|
|
[self changeAudioMetaInfo:meta];
|
|
}
|
|
|
|
- (void)loadAudioFromStream:(NSInputStream *)stream
|
|
{
|
|
[self loadAudioFromStream:stream withMetaData:nil];
|
|
}
|
|
|
|
- (void)loadAudioFromStream:(NSInputStream *)stream withMetaData:(TDAudioMetaInfo *)meta
|
|
{
|
|
[self reset];
|
|
self.streamer = [[TDAudioInputStreamer alloc] initWithInputStream:stream];
|
|
[self changeAudioMetaInfo:meta];
|
|
}
|
|
|
|
- (void)reset
|
|
{
|
|
[self.streamer stop];
|
|
self.streamer = nil;
|
|
|
|
self.state = TDAudioPlayerStateStopped;
|
|
self.elapsedTime = 0;
|
|
[self clearTimer];
|
|
}
|
|
|
|
#pragma mark - Audio Controls
|
|
|
|
- (void)play
|
|
{
|
|
if (!self.streamer || self.state == TDAudioPlayerStatePlaying) return;
|
|
if (self.state == TDAudioPlayerStateStopped) return [self start];
|
|
|
|
[self.streamer resume];
|
|
[self setNowPlayingInfoWithPlaybackRate:@1];
|
|
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(elapseTime) userInfo:nil repeats:YES];
|
|
self.state = TDAudioPlayerStatePlaying;
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidPlayNotification object:nil];
|
|
}
|
|
|
|
- (void)start
|
|
{
|
|
if (self.state == TDAudioPlayerStateStarting) return;
|
|
[self.streamer start];
|
|
self.state = TDAudioPlayerStateStarting;
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidPlayNotification object:nil];
|
|
}
|
|
|
|
- (void)pause
|
|
{
|
|
if (!self.streamer || self.state == TDAudioPlayerStatePaused) return;
|
|
|
|
[self setNowPlayingInfoWithPlaybackRate:@0.000001f];
|
|
[self clearTimer];
|
|
|
|
[self.streamer pause];
|
|
self.state = TDAudioPlayerStatePaused;
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidPauseNotification object:nil];
|
|
}
|
|
|
|
- (void)stop
|
|
{
|
|
if (!self.streamer || self.state == TDAudioPlayerStateStopped) return;
|
|
[self reset];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidStopNotification object:nil];
|
|
}
|
|
|
|
#pragma mark - Remote Events
|
|
|
|
- (void)handleRemoteControlEvent:(UIEvent *)event
|
|
{
|
|
if (event.type != UIEventTypeRemoteControl) return;
|
|
|
|
switch (event.subtype) {
|
|
case UIEventSubtypeRemoteControlPause:
|
|
[self pause];
|
|
break;
|
|
|
|
case UIEventSubtypeRemoteControlPlay:
|
|
[self play];
|
|
break;
|
|
|
|
case UIEventSubtypeRemoteControlStop:
|
|
[self stop];
|
|
break;
|
|
|
|
case UIEventSubtypeRemoteControlTogglePlayPause:
|
|
if (self.state == TDAudioPlayerStatePlaying) {
|
|
[self pause];
|
|
} else {
|
|
[self play];
|
|
}
|
|
break;
|
|
|
|
case UIEventSubtypeRemoteControlNextTrack:
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerNextTrackRequestNotification object:nil];
|
|
break;
|
|
|
|
case UIEventSubtypeRemoteControlPreviousTrack:
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerPreviousTrackRequestNotification object:nil];
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#pragma mark - Timer Helpers
|
|
|
|
- (void)elapseTime
|
|
{
|
|
self.elapsedTime++;
|
|
}
|
|
|
|
- (void)clearTimer
|
|
{
|
|
[self.timer invalidate];
|
|
self.timer = nil;
|
|
}
|
|
|
|
#pragma mark - Now Playing Info Helpers
|
|
|
|
- (void)changeAudioMetaInfo:(TDAudioMetaInfo *)meta
|
|
{
|
|
[self setNowPlayingInfoWithMetaInfo:meta];
|
|
|
|
if (!meta)
|
|
return [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidChangeAudioNotification object:nil];
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidChangeAudioNotification object:nil userInfo:@{@"meta": meta}];
|
|
}
|
|
|
|
- (void)setNowPlayingInfoWithMetaInfo:(TDAudioMetaInfo *)info
|
|
{
|
|
if (!info) {
|
|
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = @{};
|
|
return;
|
|
}
|
|
|
|
if (!self.nowPlayingMetaInfo)
|
|
self.nowPlayingMetaInfo = [NSMutableDictionary dictionary];
|
|
else
|
|
[self.nowPlayingMetaInfo removeAllObjects];
|
|
|
|
if (info.title) self.nowPlayingMetaInfo[MPMediaItemPropertyTitle] = info.title;
|
|
if (info.artist) self.nowPlayingMetaInfo[MPMediaItemPropertyArtist] = info.artist;
|
|
|
|
if (info.albumArtLarge) {
|
|
MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:info.albumArtLarge]]]];
|
|
if (artwork) self.nowPlayingMetaInfo[MPMediaItemPropertyArtwork] = artwork;
|
|
}
|
|
|
|
if (info.duration) self.nowPlayingMetaInfo[MPMediaItemPropertyPlaybackDuration] = info.duration;
|
|
|
|
[self setNowPlayingInfoWithPlaybackRate:@0];
|
|
}
|
|
|
|
- (void)setNowPlayingInfoWithPlaybackRate:(NSNumber *)rate
|
|
{
|
|
if (!self.nowPlayingMetaInfo) return;
|
|
|
|
self.nowPlayingMetaInfo[MPNowPlayingInfoPropertyPlaybackRate] = rate;
|
|
self.nowPlayingMetaInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = @(self.elapsedTime);
|
|
|
|
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = self.nowPlayingMetaInfo;
|
|
}
|
|
|
|
#pragma mark - Notification Handlers
|
|
|
|
- (void)audioSessionDidInterrupt:(NSNotification *)notification
|
|
{
|
|
NSUInteger type = [notification.userInfo[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
|
|
|
|
if (type == AVAudioSessionInterruptionTypeBegan)
|
|
[self pause];
|
|
}
|
|
|
|
- (void)audioSessionDidChangeRoute:(NSNotification *)notification
|
|
{
|
|
NSUInteger reason = [notification.userInfo[AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue];
|
|
|
|
if (reason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable)
|
|
[self pause];
|
|
}
|
|
|
|
- (void)audioDidStartPlaying
|
|
{
|
|
[self setNowPlayingInfoWithPlaybackRate:@1];
|
|
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(elapseTime) userInfo:nil repeats:YES];
|
|
self.state = TDAudioPlayerStatePlaying;
|
|
}
|
|
|
|
#pragma mark - Cleanup
|
|
|
|
- (void)dealloc
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
}
|
|
|
|
@end
|