123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875 |
- /*
- * This file is part of the FreeStreamer project,
- * (C)Copyright 2011-2018 Matias Muhonen <mmu@iki.fi> 穆马帝
- * See the file ''LICENSE'' for using the code.
- *
- * https://github.com/muhku/FreeStreamer
- */
- #import "FSAudioController.h"
- #import "FSPlaylistItem.h"
- #import "FSCheckContentTypeRequest.h"
- #import "FSParsePlaylistRequest.h"
- #import "FSParseRssPodcastFeedRequest.h"
- #import <AVFoundation/AVFoundation.h>
- /**
- * Private interface for FSAudioController.
- */
- @interface FSAudioController ()
- - (void)notifyRetrievingURL;
- @property (readonly) FSAudioStream *audioStream;
- @property (readonly) FSCheckContentTypeRequest *checkContentTypeRequest;
- @property (readonly) FSParsePlaylistRequest *parsePlaylistRequest;
- @property (readonly) FSParseRssPodcastFeedRequest *parseRssPodcastFeedRequest;
- @property (nonatomic,assign) BOOL readyToPlay;
- @property (nonatomic,assign) NSUInteger currentPlaylistItemIndex;
- @property (nonatomic,strong) NSMutableArray *playlistItems;
- @property (nonatomic,strong) NSMutableArray *streams;
- @property (nonatomic,assign) BOOL needToSetVolume;
- @property (nonatomic,assign) BOOL songSwitchInProgress;
- @property (nonatomic,assign) float outputVolume;
- - (void)audioStreamStateDidChange:(NSNotification *)notification;
- - (void)deactivateInactivateStreams:(NSUInteger)currentActiveStream;
- - (void)setAudioSessionActive:(BOOL)active;
- @end
- /**
- * Acts as a proxy object for FSAudioStream. Lazily initializes
- * the stream when it is needed.
- *
- * A call to deactivate releases the stream.
- */
- @interface FSAudioStreamProxy : NSObject {
- FSAudioStream *_audioStream;
- }
- @property (readonly) FSAudioStream *audioStream;
- @property (nonatomic,copy) NSURL *url;
- @property (nonatomic,weak) FSAudioController *audioController;
- - (void)deactivate;
- @end
- /*
- * =======================================
- * FSAudioStreamProxy implementation.
- * =======================================
- */
- @implementation FSAudioStreamProxy
- - (id)init
- {
- if (self = [super init]) {
- }
- return self;
- }
- - (id)initWithAudioController:(FSAudioController *)controller
- {
- if (self = [self init]) {
- self.audioController = controller;
- }
- return self;
- }
- - (void)dealloc
- {
- if (self.audioController.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] FSAudioStreamProxy.dealloc: %@", __LINE__, self.url);
- }
-
- [self deactivate];
- }
- - (FSAudioStream *)audioStream
- {
- if (!_audioStream) {
- FSStreamConfiguration *conf;
- if (self.audioController.configuration) {
- conf = self.audioController.configuration;
- } else {
- conf = [[FSStreamConfiguration alloc] init];
- }
-
- // Disable audio session handling for the audio stream; audio controller handles it
- conf.automaticAudioSessionHandlingEnabled = NO;
-
- _audioStream = [[FSAudioStream alloc] initWithConfiguration:conf];
-
- if (self.audioController.needToSetVolume) {
- _audioStream.volume = self.audioController.outputVolume;
- }
-
- if (self.url) {
- _audioStream.url = self.url;
- }
- }
- return _audioStream;
- }
- - (void)deactivate
- {
- [_audioStream stop];
-
- _audioStream = nil;
- }
- @end
- /*
- * =======================================
- * FSAudioController implementation
- * =======================================
- */
- @implementation FSAudioController
- -(id)init
- {
- if (self = [super init]) {
- _url = nil;
- _checkContentTypeRequest = nil;
- _parsePlaylistRequest = nil;
- _readyToPlay = NO;
- _playlistItems = [[NSMutableArray alloc] init];
- _streams = [[NSMutableArray alloc] init];
- self.preloadNextPlaylistItemAutomatically = YES;
- self.enableDebugOutput = NO;
- self.automaticAudioSessionHandlingEnabled = YES;
- self.configuration = [[FSStreamConfiguration alloc] init];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(audioStreamStateDidChange:)
- name:FSAudioStreamStateChangeNotification
- object:nil];
- }
- return self;
- }
- - (id)initWithUrl:(NSURL *)url
- {
- if (self = [self init]) {
- self.url = url;
- }
- return self;
- }
- - (void)dealloc
- {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
- [_checkContentTypeRequest cancel];
- [_parsePlaylistRequest cancel];
- [_parseRssPodcastFeedRequest cancel];
-
- for (FSAudioStreamProxy *proxy in _streams) {
- if (self.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] dealloc. Deactivating stream %@", __LINE__, proxy.url);
- }
-
- [proxy deactivate];
- }
-
- [self setAudioSessionActive:NO];
- }
- - (void)audioStreamStateDidChange:(NSNotification *)notification
- {
- if (notification.object == self) {
- // URL retrieving notification from ourselves, ignore
- return;
- }
-
- if (!(notification.object == self.audioStream)) {
- // This doesn't concern us, return
- return;
- }
-
- NSDictionary *dict = [notification userInfo];
- int state = [[dict valueForKey:FSAudioStreamNotificationKey_State] intValue];
-
- if (state == kFSAudioStreamEndOfFile) {
- if (self.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] EOF reached for %@", __LINE__, self.audioStream.url);
- }
-
- if (!self.preloadNextPlaylistItemAutomatically) {
- // No preloading wanted, skip
- if (self.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] Preloading disabled, return.", __LINE__);
- }
-
- return;
- }
-
- // Reached EOF for this stream, do we have another item waiting in the playlist?
- if ([self hasNextItem]) {
- FSAudioStreamProxy *proxy = [_streams objectAtIndex:self.currentPlaylistItemIndex + 1];
- FSAudioStream *nextStream = proxy.audioStream;
-
- if (self.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] Preloading %@", __LINE__, nextStream.url);
- }
-
- if ([self.delegate respondsToSelector:@selector(audioController:allowPreloadingForStream:)]) {
- if ([self.delegate audioController:self allowPreloadingForStream:nextStream]) {
- [nextStream preload];
- } else {
- if (self.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] Preloading disallowed for stream %@", __LINE__, nextStream.url);
- }
- }
- } else {
- // Start preloading the next stream; we can load this as there is no override
- [nextStream preload];
- }
-
- if ([self.delegate respondsToSelector:@selector(audioController:preloadStartedForStream:)]) {
- [self.delegate audioController:self preloadStartedForStream:nextStream];
- }
- }
- } else if (state == kFsAudioStreamStopped && !self.songSwitchInProgress) {
- if (self.enableDebugOutput) {
- NSLog(@"Stream %@ stopped. No next playlist items. Deactivating audio session", self.audioStream.url);
- }
-
- [self setAudioSessionActive:NO];
- } else if (state == kFsAudioStreamPlaybackCompleted && [self hasNextItem]) {
- self.currentPlaylistItemIndex = self.currentPlaylistItemIndex + 1;
- self.songSwitchInProgress = YES;
-
- [self play];
- } else if (state == kFsAudioStreamFailed) {
- if (self.enableDebugOutput) {
- NSLog(@"Stream %@ failed. Deactivating audio session", self.audioStream.url);
- }
-
- [self setAudioSessionActive:NO];
- } else if (state == kFsAudioStreamBuffering) {
- if (self.enableDebugOutput) {
- NSLog(@"Stream buffering. Activating audio session");
- }
-
- self.songSwitchInProgress = NO;
-
- if (self.automaticAudioSessionHandlingEnabled) {
- #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 60000)
- [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
- #endif
- }
- [self setAudioSessionActive:YES];
- } else if (state == kFsAudioStreamPlaying) {
- self.currentPlaylistItem.audioDataByteCount = self.activeStream.audioDataByteCount;
- }
- }
- - (void)deactivateInactivateStreams:(NSUInteger)currentActiveStream
- {
- NSUInteger streamIndex = 0;
-
- for (FSAudioStreamProxy *proxy in _streams) {
- if (streamIndex != currentActiveStream) {
- if (self.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] Deactivating stream %@", __LINE__, proxy.url);
- }
-
- [proxy deactivate];
- }
- streamIndex++;
- }
- }
- - (void)setAudioSessionActive:(BOOL)active
- {
- if (self.automaticAudioSessionHandlingEnabled) {
- #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 60000)
- [[AVAudioSession sharedInstance] setActive:active withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
- #else
- #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
- [[AVAudioSession sharedInstance] setActive:active error:nil];
- #endif
- #endif
- }
- }
- /*
- * =======================================
- * Properties
- * =======================================
- */
- - (FSAudioStream *)audioStream
- {
- FSAudioStream *stream = nil;
-
- if ([_streams count] == 0) {
- if (self.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] Stream count %lu, creating a proxy object", __LINE__, (unsigned long)[_streams count]);
- }
-
- FSAudioStreamProxy *proxy = [[FSAudioStreamProxy alloc] initWithAudioController:self];
- [_streams addObject:proxy];
- }
-
- FSAudioStreamProxy *proxy = [_streams objectAtIndex:self.currentPlaylistItemIndex];
-
- stream = proxy.audioStream;
-
- return stream;
- }
- - (FSCheckContentTypeRequest *)checkContentTypeRequest
- {
- if (!_checkContentTypeRequest) {
- __weak FSAudioController *weakSelf = self;
-
- _checkContentTypeRequest = [[FSCheckContentTypeRequest alloc] init];
- _checkContentTypeRequest.url = self.url;
- _checkContentTypeRequest.onCompletion = ^() {
- if (weakSelf.checkContentTypeRequest.playlist) {
- // The URL is a playlist; retrieve the contents
- [weakSelf.parsePlaylistRequest start];
- } else if (weakSelf.checkContentTypeRequest.xml) {
- // The URL may be an RSS feed, check the contents
- [weakSelf.parseRssPodcastFeedRequest start];
- } else {
- // Not a playlist; try directly playing the URL
-
- weakSelf.readyToPlay = YES;
- [weakSelf play];
- }
- };
- _checkContentTypeRequest.onFailure = ^() {
- // Failed to check the format; try playing anyway
-
- #if defined(DEBUG) || (TARGET_IPHONE_SIMULATOR)
- NSLog(@"FSAudioController: Failed to check the format, trying to play anyway, URL: %@", weakSelf.audioStream.url);
- #endif
-
- weakSelf.readyToPlay = YES;
- [weakSelf play];
- };
- }
- return _checkContentTypeRequest;
- }
- - (FSParsePlaylistRequest *)parsePlaylistRequest
- {
- if (!_parsePlaylistRequest) {
- __weak FSAudioController *weakSelf = self;
-
- _parsePlaylistRequest = [[FSParsePlaylistRequest alloc] init];
- _parsePlaylistRequest.onCompletion = ^() {
- [weakSelf playFromPlaylist:weakSelf.parsePlaylistRequest.playlistItems];
- };
- _parsePlaylistRequest.onFailure = ^() {
- // Failed to parse the playlist; try playing anyway
- #if defined(DEBUG) || (TARGET_IPHONE_SIMULATOR)
- NSLog(@"FSAudioController: Playlist parsing failed, trying to play anyway, URL: %@", weakSelf.audioStream.url);
- #endif
-
- weakSelf.readyToPlay = YES;
- [weakSelf play];
- };
- }
- return _parsePlaylistRequest;
- }
- - (FSParseRssPodcastFeedRequest *)parseRssPodcastFeedRequest
- {
- if (!_parseRssPodcastFeedRequest) {
- __weak FSAudioController *weakSelf = self;
-
- _parseRssPodcastFeedRequest = [[FSParseRssPodcastFeedRequest alloc] init];
- _parseRssPodcastFeedRequest.onCompletion = ^() {
- [weakSelf playFromPlaylist:weakSelf.parseRssPodcastFeedRequest.playlistItems];
- };
- _parseRssPodcastFeedRequest.onFailure = ^() {
- // Failed to parse the XML file; try playing anyway
-
- #if defined(DEBUG) || (TARGET_IPHONE_SIMULATOR)
- NSLog(@"FSAudioController: Failed to parse the RSS feed, trying to play anyway, URL: %@", weakSelf.audioStream.url);
- #endif
-
- weakSelf.readyToPlay = YES;
- [weakSelf play];
- };
- }
- return _parseRssPodcastFeedRequest;
- }
- - (void)notifyRetrievingURL
- {
- if (self.onStateChange) {
- self.onStateChange(kFsAudioStreamRetrievingURL);
- }
- }
- - (BOOL)isPlaying
- {
- return [self.audioStream isPlaying];
- }
- /*
- * =======================================
- * Public interface
- * =======================================
- */
- - (void)play
- {
- if (!self.readyToPlay) {
- /*
- * Not ready to play; start by checking the content type of the given
- * URL.
- */
- [self.checkContentTypeRequest start];
-
- NSDictionary *userInfo = @{FSAudioStreamNotificationKey_State: @(kFsAudioStreamRetrievingURL)};
- NSNotification *notification = [NSNotification notificationWithName:FSAudioStreamStateChangeNotification object:self userInfo:userInfo];
- [[NSNotificationCenter defaultCenter] postNotification:notification];
-
- [NSTimer scheduledTimerWithTimeInterval:0
- target:self
- selector:@selector(notifyRetrievingURL)
- userInfo:nil
- repeats:NO];
-
- return;
- }
-
- if ([self.playlistItems count] > 0) {
- if (self.currentPlaylistItem.originatingUrl) {
- self.audioStream.url = self.currentPlaylistItem.originatingUrl;
- } else {
- self.audioStream.url = self.currentPlaylistItem.url;
- }
- } else {
- self.audioStream.url = self.url;
- }
-
- if (self.onStateChange) {
- self.audioStream.onStateChange = self.onStateChange;
- }
- if (self.onMetaDataAvailable) {
- self.audioStream.onMetaDataAvailable = self.onMetaDataAvailable;
- }
- if (self.onFailure) {
- self.audioStream.onFailure = self.onFailure;
- }
-
- FSAudioStream *stream = self.audioStream;
-
- if (self.enableDebugOutput) {
- NSLog(@"Playing %@", stream);
- }
-
- [stream play];
- }
- - (void)playFromURL:(NSURL*)url
- {
- if (!url) {
- return;
- }
-
- [_playlistItems removeAllObjects];
-
- [self stop];
-
- self.url = url;
-
- [self play];
- }
- - (void)playFromPlaylist:(NSArray *)playlist
- {
- [self playFromPlaylist:playlist itemIndex:0];
- }
- - (void)playFromPlaylist:(NSArray *)playlist itemIndex:(NSUInteger)index
- {
- [self stop];
-
- self.playlistItems = [[NSMutableArray alloc] init];
- _streams = [[NSMutableArray alloc] init];
-
- self.currentPlaylistItemIndex = 0;
-
- [self.playlistItems addObjectsFromArray:playlist];
-
- for (FSPlaylistItem *item in playlist) {
- FSAudioStreamProxy *proxy = [[FSAudioStreamProxy alloc] initWithAudioController:self];
- proxy.url = item.url;
-
- if (self.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] playFromPlaylist. Adding stream proxy for %@", __LINE__, proxy.url);
- }
-
- [_streams addObject:proxy];
- }
-
- [self playItemAtIndex:index];
- }
- - (void)playItemAtIndex:(NSUInteger)index
- {
- NSUInteger count = [self countOfItems];
-
- if (count == 0) {
- return;
- }
-
- if (index >= count) {
- return;
- }
-
- [self.audioStream stop];
-
- self.currentPlaylistItemIndex = index;
-
- self.readyToPlay = YES;
-
- [self deactivateInactivateStreams:index];
-
- [self play];
- }
- - (NSUInteger)countOfItems
- {
- return [self.playlistItems count];
- }
- - (void)addItem:(FSPlaylistItem *)item
- {
- if (!item) {
- return;
- }
-
- [self.playlistItems addObject:item];
-
- FSAudioStreamProxy *proxy = [[FSAudioStreamProxy alloc] initWithAudioController:self];
- proxy.url = item.url;
-
- if (self.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] addItem. Adding stream proxy for %@", __LINE__, proxy.url);
- }
-
- [_streams addObject:proxy];
- }
- - (void)insertItem:(FSPlaylistItem *)item atIndex:(NSInteger)index
- {
- if (!item) {
- return;
- }
-
- if (index > self.playlistItems.count) {
- return;
- }
-
- if(self.playlistItems.count == 0 && index == 0) {
- [self addItem:item];
- return;
- }
-
- [self.playlistItems insertObject:item
- atIndex:index];
-
- FSAudioStreamProxy *proxy = [[FSAudioStreamProxy alloc] initWithAudioController:self];
- proxy.url = item.url;
-
- [_streams insertObject:proxy
- atIndex:index];
- if(index <= self.currentPlaylistItemIndex) {
- _currentPlaylistItemIndex++;
- }
- }
- - (void)replaceItemAtIndex:(NSUInteger)index withItem:(FSPlaylistItem *)item
- {
- NSUInteger count = [self countOfItems];
-
- if (count == 0) {
- return;
- }
-
- if (index >= count) {
- return;
- }
-
- if (self.currentPlaylistItemIndex == index) {
- // If the item is currently playing, do not allow the replacement
- return;
- }
-
- [self.playlistItems replaceObjectAtIndex:index withObject:item];
-
- FSAudioStreamProxy *proxy = [[FSAudioStreamProxy alloc] initWithAudioController:self];
- proxy.url = item.url;
-
- [_streams replaceObjectAtIndex:index withObject:proxy];
- }
- - (void)moveItemAtIndex:(NSUInteger)from toIndex:(NSUInteger)to {
- NSUInteger count = [self countOfItems];
-
- if (count == 0) {
- return;
- }
-
- if (from >= count || to >= count) {
- return;
- }
-
- if(from == self.currentPlaylistItemIndex) {
- _currentPlaylistItemIndex = to;
- }
- else if(from < self.currentPlaylistItemIndex && to > self.currentPlaylistItemIndex) {
- _currentPlaylistItemIndex--;
- }
- else if(from > self.currentPlaylistItemIndex && to <= self.currentPlaylistItemIndex) {
- _currentPlaylistItemIndex++;
- }
-
- id object = [self.playlistItems objectAtIndex:from];
- [self.playlistItems removeObjectAtIndex:from];
- [self.playlistItems insertObject:object atIndex:to];
-
- id obj = [_streams objectAtIndex:from];
- [_streams removeObjectAtIndex:from];
- [_streams insertObject:obj atIndex:to];
- }
- - (void)removeItemAtIndex:(NSUInteger)index
- {
- NSUInteger count = [self countOfItems];
-
- if (count == 0) {
- return;
- }
-
- if (index >= count) {
- return;
- }
-
- if (self.currentPlaylistItemIndex == index && self.isPlaying) {
- // If the item is currently playing, do not allow the removal
- return;
- }
-
- FSPlaylistItem *current = self.currentPlaylistItem;
-
- [self.playlistItems removeObjectAtIndex:index];
-
- if (self.enableDebugOutput) {
- FSAudioStreamProxy *proxy = [_streams objectAtIndex:index];
- NSLog(@"[FSAudioController.m:%i] removeItemAtIndex. Removing stream proxy %@", __LINE__, proxy.url);
- }
-
- [_streams removeObjectAtIndex:index];
-
- // Update the current playlist item to be correct after the removal
- NSUInteger itemIndex = 0;
- for (FSPlaylistItem *item in self.playlistItems) {
- if (item == current) {
- self.currentPlaylistItemIndex = itemIndex;
-
- break;
- }
-
- itemIndex++;
- }
- }
- - (void)stop
- {
- if ([_streams count] > 0) {
- // Avoid creating an instance if we don't have it
- [self.audioStream stop];
- }
-
- [_checkContentTypeRequest cancel];
- [_parsePlaylistRequest cancel];
- [_parseRssPodcastFeedRequest cancel];
-
- self.readyToPlay = NO;
- }
- - (void)pause
- {
- [self.audioStream pause];
- }
- -(BOOL)hasMultiplePlaylistItems
- {
- return ([self.playlistItems count] > 1);
- }
- -(BOOL)hasNextItem
- {
- return [self hasMultiplePlaylistItems] && (self.currentPlaylistItemIndex + 1 < [self.playlistItems count]);
- }
- -(BOOL)hasPreviousItem
- {
- return ([self hasMultiplePlaylistItems] && (self.currentPlaylistItemIndex != 0));
- }
- -(void)playNextItem
- {
- if ([self hasNextItem]) {
- if (self.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] playNexItem. Stopping stream %@", __LINE__, self.audioStream.url);
- }
- [self.audioStream stop];
-
- [self deactivateInactivateStreams:self.currentPlaylistItemIndex];
-
- self.currentPlaylistItemIndex = self.currentPlaylistItemIndex + 1;
-
- [self play];
- }
- }
- -(void)playPreviousItem
- {
- if ([self hasPreviousItem]) {
- if (self.enableDebugOutput) {
- NSLog(@"[FSAudioController.m:%i] playPreviousItem. Stopping stream %@", __LINE__, self.audioStream.url);
- }
- [self.audioStream stop];
-
- [self deactivateInactivateStreams:self.currentPlaylistItemIndex];
-
- self.currentPlaylistItemIndex = self.currentPlaylistItemIndex - 1;
-
- [self play];
- }
- }
- /*
- * =======================================
- * Properties
- * =======================================
- */
- - (void)setVolume:(float)volume
- {
- self.outputVolume = volume;
- self.needToSetVolume = YES;
-
- if ([_streams count] > 0) {
- self.audioStream.volume = self.outputVolume;
- }
- }
- - (float)volume
- {
- return self.outputVolume;
- }
- - (void)setUrl:(NSURL *)url
- {
- [self stop];
-
- if (url) {
- NSURL *copyOfURL = [url copy];
- _url = copyOfURL;
-
- self.checkContentTypeRequest.url = _url;
- self.parsePlaylistRequest.url = _url;
- self.parseRssPodcastFeedRequest.url = _url;
-
- if ([_url isFileURL]) {
- /*
- * Local file URLs can be directly played
- */
- self.readyToPlay = YES;
- }
- } else {
- _url = nil;
- }
- }
- - (NSURL* )url
- {
- if (!_url) {
- return nil;
- }
-
- NSURL *copyOfURL = [_url copy];
- return copyOfURL;
- }
- - (FSAudioStream *)activeStream
- {
- if ([_streams count] > 0) {
- return self.audioStream;
- }
- return nil;
- }
- - (FSPlaylistItem *)currentPlaylistItem
- {
- if (self.readyToPlay) {
- if ([self.playlistItems count] > 0) {
- FSPlaylistItem *playlistItem = (self.playlistItems)[self.currentPlaylistItemIndex];
- return playlistItem;
- }
- }
- return nil;
- }
- - (void (^)(FSAudioStreamState state))onStateChange
- {
- return _onStateChangeBlock;
- }
- - (void (^)(NSDictionary *metaData))onMetaDataAvailable
- {
- return _onMetaDataAvailableBlock;
- }
- - (void (^)(FSAudioStreamError error, NSString *errorDescription))onFailure
- {
- return _onFailureBlock;
- }
- - (void)setOnStateChange:(void (^)(FSAudioStreamState))newOnStateValue
- {
- _onStateChangeBlock = newOnStateValue;
-
- if ([_streams count] > 0) {
- self.audioStream.onStateChange = _onStateChangeBlock;
- }
- }
- - (void)setOnMetaDataAvailable:(void (^)(NSDictionary *))newOnMetaDataAvailableValue
- {
- _onMetaDataAvailableBlock = newOnMetaDataAvailableValue;
-
- if ([_streams count] > 0) {
- self.audioStream.onMetaDataAvailable = _onMetaDataAvailableBlock;
- }
- }
- - (void)setOnFailure:(void (^)(FSAudioStreamError error, NSString *errorDescription))newOnFailureValue
- {
- _onFailureBlock = newOnFailureValue;
-
- if ([_streams count] > 0) {
- self.audioStream.onFailure = _onFailureBlock;
- }
- }
- @end
|