Skip to content

Commit

Permalink
SkipEmptySound, Fix #91 (add some documentation comments)
Browse files Browse the repository at this point in the history
  • Loading branch information
saiday committed Oct 9, 2015
1 parent 79eb6b3 commit ea525c7
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 62 deletions.
71 changes: 48 additions & 23 deletions HysteriaPlayer/HysteriaPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ typedef NS_ENUM(NSInteger, HysteriaPlayerFailed) {
HysteriaPlayerFailedCurrentItem = 4001,
};

// Delegate
/**
* HysteriaPlayerDelegate, all delegate method is optional.
*/
@protocol HysteriaPlayerDelegate <NSObject>

@optional
Expand All @@ -56,17 +58,29 @@ typedef NS_ENUM(NSInteger, HysteriaPlayerFailed) {
@protocol HysteriaPlayerDataSource <NSObject>

@optional

/**
* Asks the data source to return the number of items that HysteriaPlayer would play.
*
* @return items count
*/
- (NSInteger)hysteriaPlayerNumberOfItems;
/*!
Recommend you use this method to handle your source getter, setupSourceAsyncGetter:ItemsCount: is for advanced usage.
hysteriaPlayerURLForItemAtIndex:(NSInteger)index and hysteriaPlayerAsyncSetUrlForItemAtIndex:(NSInteger)index provides for the use of alternatives.
@method HysteriaPlayerURLForItemAtIndex:(NSInteger)index

/**
* Source URL provider, hysteriaPlayerAsyncSetUrlForItemAtIndex:preBuffer: is for async task usage.
*
* @param index index of the item
* @param preBuffer ask URL for pre buffer or not
*
* @return source URL
*/
- (NSURL *)hysteriaPlayerURLForItemAtIndex:(NSInteger)index preBuffer:(BOOL)preBuffer;
/*!
If you are using asynchronously handle your items use this method to tell HysteriaPlayer which URL you would use for index, will excute until you call setupPlayerItemWithUrl:index:
hysteriaPlayerURLForItemAtIndex:(NSInteger)index and hysteriaPlayerAsyncSetUrlForItemAtIndex:(NSInteger)index provides for the use of alternatives.
@method HysteriaPlayerAsyncSetUrlForItemAtIndex:(NSInteger)index

/**
* Source URL provider, would excute until you call setupPlayerItemWithUrl:index:
*
* @param index index of the item
* @param preBuffer ask URL for pre buffer or not
*/
- (void)hysteriaPlayerAsyncSetUrlForItemAtIndex:(NSInteger)index preBuffer:(BOOL)preBuffer;

Expand Down Expand Up @@ -102,7 +116,8 @@ typedef NS_ENUM(NSInteger, HysteriaPlayerShuffleMode) {
@property (nonatomic) NSInteger itemsCount;
@property (nonatomic) BOOL disableLogs;
@property (nonatomic, strong, readonly) NSArray *playerItems;
@property (nonatomic, readonly) BOOL isInEmptySound;
@property (nonatomic, readonly) BOOL emptySoundPlaying;
@property (nonatomic) BOOL skipEmptySoundPlaying;
@property (nonatomic) BOOL popAlertWhenError;

+ (HysteriaPlayer *)sharedInstance;
Expand All @@ -115,18 +130,23 @@ typedef NS_ENUM(NSInteger, HysteriaPlayerShuffleMode) {
- (void)asyncSetupSourceGetter:(SourceAsyncGetter)asyncBlock ItemsCount:(NSInteger)count DEPRECATED_MSG_ATTRIBUTE("use HysteriaPlayerDataSource instead.");
- (void)setItemsCount:(NSInteger)count DEPRECATED_MSG_ATTRIBUTE("use HysteriaPlayerDataSource instead.");

/*!
This method is necessary if you setting up AsyncGetter.
After you your AVPlayerItem initialized should call this method on your asyncBlock.
Should not call this method directly if you using setupSourceGetter:ItemsCount.
@method setupPlayerItemWithUrl:index:
/**
* This method is necessary if you implement hysteriaPlayerAsyncSetUrlForItemAtIndex:preBuffer: delegate method,
provide source URL to HysteriaPlayer.
Should not use this method outside of hysteriaPlayerAsyncSetUrlForItemAtIndex:preBuffer: scope.
*
* @param url source URL
* @param index index which hysteriaPlayerAsyncSetUrlForItemAtIndex:preBuffer: sent you
*/
- (void)setupPlayerItemWithUrl:(NSURL *)url index:(NSInteger)index;
- (void)fetchAndPlayPlayerItem: (NSInteger )startAt;
- (void)removeAllItems;
- (void)removeQueuesAtPlayer;
/*!
Be sure you update hysteriaPlayerNumberOfItems or itemsCount when you remove items

/**
* Be sure you update hysteriaPlayerNumberOfItems or itemsCount when you remove items
*
* @param index index to removed
*/
- (void)removeItemAtIndex:(NSInteger)index;
- (void)moveItemFromIndex:(NSInteger)from toIndex:(NSInteger)to;
Expand Down Expand Up @@ -156,15 +176,20 @@ typedef NS_ENUM(NSInteger, HysteriaPlayerShuffleMode) {
- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;
- (void)removeTimeObserver:(id)observer;

/*
* Disable memory cache, player will run SourceItemGetter everytime even the media has been played.
* Default is YES
/**
* Default is true
*
* @param isMemoryCached cache
*/
- (void)enableMemoryCached:(BOOL) isMemoryCached;
- (void)enableMemoryCached:(BOOL)memoryCache;
- (BOOL)isMemoryCached;

/*
* Indicating Playeritem's play index
/**
* Indicating Playeritem's play index
*
* @param item item
*
* @return index of the item
*/
- (NSNumber *)getHysteriaIndex:(AVPlayerItem *)item;

Expand Down
59 changes: 30 additions & 29 deletions HysteriaPlayer/HysteriaPlayer.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ @interface HysteriaPlayer ()


@property (nonatomic, strong, readwrite) NSArray *playerItems;
@property (nonatomic, readwrite) BOOL isInEmptySound;
@property (nonatomic, readwrite) BOOL emptySoundPlaying;
@property (nonatomic) NSInteger lastItemIndex;

@property (nonatomic, strong) AVQueuePlayer *audioPlayer;
Expand Down Expand Up @@ -109,13 +109,17 @@ - (void)setItemsCount:(NSInteger)count {}

- (void)playEmptySound
{
//play .1 sec empty sound
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *filepath = [bundle pathForResource:@"point1sec" ofType:@"mp3"];
if ([[NSFileManager defaultManager]fileExistsAtPath:filepath]) {
self.isInEmptySound = YES;
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:filepath]];
self.audioPlayer = [AVQueuePlayer queuePlayerWithItems:[NSArray arrayWithObject:playerItem]];
if (self.skipEmptySoundPlaying) {
self.audioPlayer = [[AVQueuePlayer alloc] init];
} else {
//play .1 sec empty sound
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *filepath = [bundle pathForResource:@"point1sec" ofType:@"mp3"];
if ([[NSFileManager defaultManager]fileExistsAtPath:filepath]) {
self.emptySoundPlaying = YES;
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:filepath]];
self.audioPlayer = [AVQueuePlayer queuePlayerWithItems:[NSArray arrayWithObject:playerItem]];
}
}
}

Expand All @@ -132,22 +136,21 @@ - (void)backgroundPlayable
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&aError];
if (aError) {
if (!self.disableLogs) {
NSLog(@"set category error:%@",[aError description]);
NSLog(@"HysteriaPlayer: set category error:%@",[aError description]);
}
}
aError = nil;
[audioSession setActive:YES error:&aError];
if (aError) {
if (!self.disableLogs) {
NSLog(@"set active error:%@",[aError description]);
NSLog(@"HysteriaPlayer: set active error:%@",[aError description]);
}
}
//audioSession.delegate = self;
}
}
}else {
if (!self.disableLogs) {
NSLog(@"unable to register background playback");
NSLog(@"HysteriaPlayer: unable to register background playback");
}
}

Expand Down Expand Up @@ -528,22 +531,20 @@ - (void)pausePlayerForcibly:(BOOL)forcibly

- (BOOL)isPlaying
{
if (!self.isInEmptySound)
return [self.audioPlayer rate] != 0.f;
else
return NO;
return self.emptySoundPlaying ? NO : self.audioPlayer.rate != 0.f;
}

- (HysteriaPlayerStatus)getHysteriaPlayerStatus
{
if ([self isPlaying])
if ([self isPlaying]) {
return HysteriaPlayerStatusPlaying;
else if (pauseReasonForced)
} else if (pauseReasonForced) {
return HysteriaPlayerStatusForcePause;
else if (pauseReasonBuffering)
} else if (pauseReasonBuffering) {
return HysteriaPlayerStatusBuffering;
else
} else {
return HysteriaPlayerStatusUnknown;
}
}

- (float)getPlayingItemCurrentTime
Expand Down Expand Up @@ -604,7 +605,7 @@ - (void)interruption:(NSNotification*)notification
[self play];
}
if (!self.disableLogs) {
NSLog(@"HysteriaPlayer interruption: %@", interuptionType == AVAudioSessionInterruptionTypeBegan ? @"began" : @"end");
NSLog(@"HysteriaPlayer: HysteriaPlayer interruption: %@", interuptionType == AVAudioSessionInterruptionTypeBegan ? @"began" : @"end");
}
}

Expand All @@ -622,7 +623,7 @@ - (void)routeChange:(NSNotification *)notification
[self play];
}
if (!self.disableLogs) {
NSLog(@"HysteriaPlayer routeChanged: %@", routeChangeType == AVAudioSessionRouteChangeReasonNewDeviceAvailable ? @"New Device Available" : @"Old Device Unavailable");
NSLog(@"HysteriaPlayer: HysteriaPlayer routeChanged: %@", routeChangeType == AVAudioSessionRouteChangeReasonNewDeviceAvailable ? @"New Device Available" : @"Old Device Unavailable");
}
}

Expand All @@ -642,7 +643,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
}
} else if (self.audioPlayer.status == AVPlayerStatusFailed) {
if (!self.disableLogs) {
NSLog(@"%@", self.audioPlayer.error);
NSLog(@"HysteriaPlayer: %@", self.audioPlayer.error);
}

if (self.popAlertWhenError) {
Expand All @@ -655,7 +656,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
}

if(object == self.audioPlayer && [keyPath isEqualToString:@"rate"]){
if (!self.isInEmptySound) {
if (!self.emptySoundPlaying) {
if ([self.delegate respondsToSelector:@selector(hysteriaPlayerRateChanged:)]) {
[self.delegate hysteriaPlayerRateChanged:[self isPlaying]];
}
Expand All @@ -679,7 +680,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
if ([self.delegate respondsToSelector:@selector(hysteriaPlayerCurrentItemChanged:)]) {
[self.delegate hysteriaPlayerCurrentItemChanged:newPlayerItem];
}
self.isInEmptySound = NO;
self.emptySoundPlaying = NO;
}
}

Expand Down Expand Up @@ -731,7 +732,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
if (CMTIME_COMPARE_INLINE(bufferdTime , >, milestone) && self.audioPlayer.currentItem.status == AVPlayerItemStatusReadyToPlay && !interruptedWhilePlaying && !routeChangedWhilePlaying) {
if (![self isPlaying]) {
if (!self.disableLogs) {
NSLog(@"resume from buffering..");
NSLog(@"HysteriaPlayer: resume from buffering..");
}
pauseReasonBuffering = NO;

Expand Down Expand Up @@ -838,11 +839,11 @@ - (BOOL)isMemoryCached
return self.playerItems != nil;
}

- (void)enableMemoryCached:(BOOL)isMemoryCached
- (void)enableMemoryCached:(BOOL)memoryCache
{
if (self.playerItems == nil && isMemoryCached) {
if (self.playerItems == nil && memoryCache) {
self.playerItems = [NSArray array];
} else if (self.playerItems != nil && !isMemoryCached) {
} else if (self.playerItems != nil && !memoryCache) {
self.playerItems = nil;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,8 @@
83AD5EC116A5CABD00604530 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)\"",
Expand All @@ -405,13 +407,16 @@
GCC_PREFIX_HEADER = "HyseteriaSamples/HyseteriaSamples-Prefix.pch";
INFOPLIST_FILE = "HyseteriaSamples/HyseteriaSamples-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
83AD5EC216A5CABD00604530 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)\"",
Expand All @@ -420,6 +425,7 @@
GCC_PREFIX_HEADER = "HyseteriaSamples/HyseteriaSamples-Prefix.pch";
INFOPLIST_FILE = "HyseteriaSamples/HyseteriaSamples-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
WRAPPER_EXTENSION = app;
};
name = Release;
Expand Down
16 changes: 6 additions & 10 deletions HysteriaPlayerObjcExample/HyseteriaSamples/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -149,24 +149,20 @@ - (NSInteger)hysteriaPlayerNumberOfItems
return self.itemsCount;
}


/*!
Adopt one of
hysteriaPlayerURLForItemAtIndex:(NSInteger)index
or
hysteriaPlayerAsyncSetUrlForItemAtIndex:(NSInteger)index
which meets your requirements.
*/
// Adopt one of
// hysteriaPlayerURLForItemAtIndex:(NSInteger)index
// or
// hysteriaPlayerAsyncSetUrlForItemAtIndex:(NSInteger)index
// which meets your requirements.
- (NSURL *)hysteriaPlayerURLForItemAtIndex:(NSInteger)index preBuffer:(BOOL)preBuffer
{
switch (self.playingType) {
case PlayingTypeStaticItems:
return [[NSURL alloc] initFileURLWithPath:[localMedias objectAtIndex:index]];
case PlayingTypeSync:
return [NSURL URLWithString:[itunesPreviewUrls objectAtIndex:index]];

default:
return nil; //
return nil;
}
}

Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,14 @@ HysteriaPlayer *hysteriaPlayer = [HysteriaPlayer sharedInstance];
hysteriaPlayer = nil;
```

## Known Issues
If you going to play HTTP Live streaming on iOS 8 and below. (iOS 9+ is fine, no worries)
There's a property you had to set at very first time when HysteriaPlayer is initiated.
```objective-c
HysteriaPlayer *hysteriaPlayer = [HysteriaPlayer sharedInstance];
hysteriaPlayer.skipEmptySoundPlaying = YES;
```

## Licenses ##

All source code is licensed under the MIT License.
Expand Down

0 comments on commit ea525c7

Please sign in to comment.