Git Product home page Git Product logo

hysteriaplayer's Introduction

Hysteria Player

HysteriaPlayer provides useful basic player functionalities.

It provides:

  • PlayerItem cache management.
  • Pre-buffer next PlayerItem.

Features:

  • Supporting both local and remote media.
  • Setting up HysteriaPlayer with few blocks, implementing delegates in your UIView and UIViewController subclasses to update UI when player event changed.
  • Ability to advance next/previous item.
  • If player suspended bacause of buffering issue, auto-resume the playback when buffered size reached 5 secs.
  • Background playable. (check the background audio mode then everything works)
  • Using getHysteriaOrder: to get the index of your PlayerItems.
  • Extends long time buffering in background.
  • Player modes support: Repeat, RepeatOne, Shuffle.

Tutorials

In part 0, what we want? why HysteriaPlayer?

In part 1, demonstrating how to play remote audios with HysteriaPlayer. (version 2.0.0, a little bit outdated. version 2.1.0 modified some APIs)

In part 2, making a simple player user interface.

You can download tutorial source code here

Installation

CocoaPods

If you using CocoaPods, it's easy to install HysteriaPlayer.

Podfile:

platform :ios, 'x.0'

pod 'HysteriaPlayer',			        '~> x.x.x'
    
end

Manually install

Import library to your project

Drag HysteriaPlayer.m, HysteriaPlayer.h to your project.

Add Frameworks

Add CoreMedia.framework, AudioToolbox.framework and AVFoundation.framework to your Link Binary With Libraries.

Copy provided point1sec.mp3 file to your Supporting Files

Ability to play the first PlayerItem when your application is resigned active but first PlayerItem is still buffering.

Background modes for audio playback

Xcode providing GUI checkbox to enable various background modes. Enable Audio and AirPlay, you can find this section from Project -> Capabilities -> Background Modes.

How to use

Delegate, DataSource

Implement HysteriaPlayerDelegate and HysteriaPlayerDataSource in your own playback configurator model. (It can be an UIViewController subclass as well but make it a standalone model makes more sense.)

#import "HysteriaPlayer.h"

@interface ViewController : UIViewController <HysteriaPlayerDelegate, HysteriaPlayerDataSource>

There are 4 optional delegates in HysteriaPlayerDelegate:

@optional
- (void)hysteriaPlayerWillChangedAtIndex:(NSUInteger)index;
- (void)hysteriaPlayerCurrentItemChanged:(AVPlayerItem *)item;
- (void)hysteriaPlayerRateChanged:(BOOL)isPlaying;
- (void)hysteriaPlayerDidReachEnd;
- (void)hysteriaPlayerCurrentItemPreloaded:(CMTime)time;
- (void)hysteriaPlayerDidFailed:(HysteriaPlayerFailed)identifier error:(NSError *)error;
- (void)hysteriaPlayerReadyToPlay:(HysteriaPlayerReadyToPlay)identifier;

3 optional delegates in HysteriaPlayerDataSource:

@optional
- (NSUInteger)hysteriaPlayerNumberOfItems;
- (NSURL *)hysteriaPlayerURLForItemAtIndex:(NSUInteger)index preBuffer:(BOOL)preBuffer;
- (void)hysteriaPlayerAsyncSetUrlForItemAtIndex:(NSUInteger)index preBuffer:(BOOL)preBuffer;

If you don't implement hysteriaPlayerNumberOfItems delegate method, you have to set itemsCount property to HysteriaPlayer.

And you must implement one of hysteriaPlayerURLForItemAtIndex:preBuffer or hysteriaPlayerAsyncSetUrlForItemAtIndex:preBuffer delegate method.

Setup

...

- (void)setupHyseteriaPlayer
{
    HysteriaPlayer *hysteriaPlayer = [HysteriaPlayer sharedInstance];
    hysteriaPlayer.delegate = self;
    hysteriaPlayer.datasource = self;
}

- (NSUInteger)hysteriaPlayerNumberOfItems
{
    return self.itemsCount;
}

- (NSURL *)hysteriaPlayerURLForItemAtIndex:(NSUInteger)index preBuffer:(BOOL)preBuffer
{
    return [[NSURL alloc] initFileURLWithPath:[localMedias objectAtIndex:index]];
}

Snippets

Get item's index of my working items:

HysteriaPlayer *hysteriaPlayer = [HysteriaPlayer sharedInstance];
NSNumber *order = [hysteriaPlayer getHysteriaOrder:[hysteriaPlayer getCurrentItem]];

Get playing item's timescale

HysteriaPlayer *hysteriaPlayer = [HysteriaPlayer sharedInstance];
NSDictionary *dict = [hysteriaPlayer getPlayerTime];
double durationTime = [[dict objectForKey:@"DurationTime"] doubleValue];
double currentTime = [[dict objectForKey:@"CurrentTime"] doubleValue];

Get Player status

switch ([hysteriaPlayer getHysteriaPlayerStatus]) {
    case HysteriaPlayerStatusUnknown:
        
        break;
    case HysteriaPlayerStatusForcePause:
        
        break;
    case HysteriaPlayerStatusBuffering:
        
        break;
    case HysteriaPlayerStatusPlaying:
        
    default:
        break;
}

Disable played item caching

Default is cache enabled

HysteriaPlayer *hysteriaPlayer = [HysteriaPlayer sharedInstance];
[hysteriaPlayer enableMemoryCached:NO];

What if I don't need player instance anymore?

HysteriaPlayer *hysteriaPlayer = [HysteriaPlayer sharedInstance];
[hysteriaPlayer deprecatePlayer];
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.

HysteriaPlayer *hysteriaPlayer = [HysteriaPlayer sharedInstance];
hysteriaPlayer.skipEmptySoundPlaying = YES;

Licenses

All source code is licensed under the MIT License.

Author

Created by Saiday

hysteriaplayer's People

Contributors

bitdeli-chef avatar jerson avatar kjpolaszek avatar littlema0404 avatar nathanwhy avatar newbdez33 avatar readmecritic avatar saiday avatar scottphc avatar thezentrader avatar twgeolo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hysteriaplayer's Issues

PAUSE_REASON_Buffering and PAUSE_REASON_ForcePause can be true at the same time

When this happens getHysteriaPlayerStatus returns HysteriaPlayerStatusBuffering.

I am using the sample code:

    if ([hysteriaPlayer isPlaying])
    {
        [hysteriaPlayer pausePlayerForcibly:YES];
        [hysteriaPlayer pause];
    }else{
        [hysteriaPlayer pausePlayerForcibly:NO];
        [hysteriaPlayer play];
    }

My player becomes stuck either playing or buffering but never forced pause.

PAUSE_REASON_Buffering doesn't seem to ever be reset to NO.

Wiki

  • add PlayerPreLoaded
  • methods and properties
  • guide
  • who's using

can HysteriaPlayer support ios5.0 ?

"AVAudioSessionInterruptionNotification/AVAudioSessionRouteChangeNotification" used, which are avalable on ios6.0+.
how to support ios5.0?

Using a TableView with HysteriaPlayer

Hello, I was wondering if someone could help me use HysteriaPlayer with a tableview so that when someone clicks on the tableviewcell it plays the audio and you can click next or previous. The tableview would be populated with songs from different urls. Thanks.

Using delegate instead of init blocks

It's much clear and flexible.

@class AVPlayerItem;

// Including NSObject to perform respondsToSelector:
@protocol HysteriaPlayerDelegate<NSObject>

@required
- (void)playerReadyToPlay;
- (void)playerRateChanged;
- (void)playerCurrentItemChanged:(AVPlayerItem *)item;
- (void)playerCurrentItemReadyToPlay;

@optional
- (void)playerFailed;
- (void)playerDidReachEnd;
- (HysteriaBufferingStatus)PlayerBufferingStatusChanged;

AVPlayerItemStatusFailed callback

I want to be able to listen to AVPlayerItemStatusFailed. This should be provided as a callback and there should be an option to indicate whether the developer wants it to playNext.

if (object == audioPlayer.currentItem && [keyPath isEqualToString:@"status"]) {
        if (audioPlayer.currentItem.status == AVPlayerItemStatusFailed) {
            NSLog(@"------player item failed:%@",audioPlayer.currentItem.error);
            [self playNext];
        }

Add support for seekToTime:completionHandler

AVPlayer has a instance method called seekToTime:completionHandler

  - (void)seekToTime:(CMTime)time completionHandler:(void (^)(BOOL finished))completionHandler

This makes it way easier to keep the UI in sync. Let me know what you think.
Could submit a pull request later today.

Warning

I am getting this warning in the debug console. Any idea?

Could this be an issue when using the player in multiple view controllers?

Thanks!

An instance 0x1d894930 of class AVQueuePlayer was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:
<NSKeyValueObservationInfo 0x1c5acad0> (
<NSKeyValueObservance 0x1c5d71a0: Observer: 0x1c5cfa30, Key path: status, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x1d896220>
<NSKeyValueObservance 0x1c5d8000: Observer: 0x1c5cfa30, Key path: rate, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x1c5d8080>
<NSKeyValueObservance 0x1c5d83b0: Observer: 0x1c5cfa30, Key path: currentItem, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x1c58d260>
)

possible to do caching?

Hii,
. Thanks for giving good sample and i planned to download some audios to play on offline mode , is there any possibility please help me.

Thanks,
Narender

Playing a track From where i left.

Hi,
If i play a track till 2 min in total of 10 min and if played next track and return back to first track and should play from where i left i.e from 8th min not from beginning.
Thanks,
Shabana

Time control.

Is there any method, that could help me with track sound control. For example drag to 1m 25s of current track or something like that ?

Time Control

Is there any method, that let audio playback from a specified time when play audio for the first time .
For example,
hysteriaPlayer = [[HysteriaPlayer sharedInstance]
initWithHandlerPlayerReadyToPlay:^{
if (![hysteriaPlayer isPlaying]) {
[hysteriaPlayer play];
[self syncPlayPauseButtons];
[hysteriaPlayer seekToTime:30.0f];
}
}
PlayerRateChanged:^{
[self syncPlayPauseButtons];
}
CurrentItemChanged:^(AVPlayerItem *newItem) {
if (newItem != (id)[NSNull null]) {
[self syncPlayPauseButtons];
}
}
ItemReadyToPlay:^{
if ([hysteriaPlayer pauseReason] == HysteriaPauseReasonUnknown) {
[hysteriaPlayer play];
}
}
PlayerFailed:^{}
PlayerDidReachEnd:^{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Player did reach end." message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
[alert show];
}];

On your Samples I add seektoTime function, but it is sometimes useful, sometimes useless.
Can you help me? Tell me how to do it? Thanks.

UITableViewCell current player item

Hello, I am using the static array with a tableview and I was wondering if someone could help me. When I click on any of the tableview cells, it plays the first song on the list. How can it make it play the current song thats on that tableview cell instead of starting of from the top of the list. Thanks.

How can I play simple array of mp3 files from folder in my app?

It is not clear for me how can I just feed player with mp3 array that lay on my app folder.
For example mp3Array = @[@"1.mp3", @"2.mp3", @"3.mp3"];
I have try also mp3Array = @[
[[NSBundle mainBundle]pathForResource:@"1" ofType:@"mp3"],
[[NSBundle mainBundle]pathForResource:@"2" ofType:@"mp3"],
[[NSBundle mainBundle]pathForResource:@"3" ofType:@"mp3"]];

Playing a track dynamically after a current Track

Hi,
I have a search in my application and selected track should added to Audio Queue at current item and have to play newly added track.
As asyncSetupSourceGetter adds all track to the Audio Queue at once how can i achieve this one.
Thanks,
Shabana

NOT PLAYING FULL SONG

Hi,

The player working fine but, some times not playing full song its calling didreachend method please help me what was the problem i am not getting .

Audio playback not always resumed after audio session interruption

Within audio_session_interruption_listener, [hysteriaPlayer isPlaying] sometimes fails to detect that there's a song playing. (My guess is that this has to do with the interruption itself forcing the player to pause before isPlaying is checked in the interruption event listener.) As a result, interruptedWhilePlaying is never set to YES, and so when the interruption ends, the currently playing song isn't resumed.

moving beginReceivingRemoteControlEvents into UIViewController

Hello,
beginReceivingRemoteControlEvents seemed only reacts for UIResponder subclass. So it will be much clear let the UIViewController to implement it.

(void)viewDidLoad
{
    [super viewDidLoad];
    [self startRemoteControlEvents];
.....
}

#pragma mark - 
#pragma mark ===========  iOS7 Control Center  =========
#pragma mark -

-(BOOL)canBecomeFirstResponder {
    return YES;
}

-(void) startRemoteControlEvents {
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];
}

-(void) endRemoteControlEvents {
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
    [self resignFirstResponder];
}

-(void)remoteControlReceivedWithEvent:(UIEvent *)event {
    switch (event.subtype) {
        case UIEventSubtypeRemoteControlTogglePlayPause:
            [self play_pause:nil];
            break;
        case UIEventSubtypeRemoteControlPlay:
            [self play_pause:nil];
            break;
        case UIEventSubtypeRemoteControlPause:
            [self play_pause:nil];
            break;
        case UIEventSubtypeRemoteControlNextTrack:
            [self playNext:nil];
            break;
        case UIEventSubtypeRemoteControlPreviousTrack :
            [self playPreviouse:nil];
            break;
        default:
            break;
    }
}

Anyone can confirm ?

CocoaPods failing

[!] Invalid string representation for a Specification: `HysteriaPlayer`.String representation should include the name and the version of a pod.
# Podfile
pod 'HysteriaPlayer', :git => 'https://github.com/StreetVoice/HysteriaPlayer.git'

Using CocoaPods 0.29.0

UPDATE 2.0: callback blocks to delegation

After many times HysteriaPlayer implementing, figured out that some callback blocks were not a good pattern for Players.
I detached UI related callback blocks into delegation pattern. Make it easier and elegant for Players.

When delegation version(2.x) is out, callback block version(1.x) would be deprecated.
Would not have two versions alive at the same time.

This would be a huge update and it comes out with tutorials, good for you!

Shuffle mode playNext algorithm is rough.

Thanks @JacobSyndeo pointing this out. This should be optimized.

There doesn't appear to be any tracking of which songs have already been played in the playNext method… just a raw randomizing function:
index = arc4random() % items_count;

How to get length of all tracks in list?

Thanks for great class.

I checked documentation and couldn't find how can I get length of all tracks (e.g. mp3 files) when playing local media.

Can you help?

Thanks.

update currentTime periodically?

how to update the currentTime periodically? there is a getPlayingItemCurrentTime method, but when should I call it?

in AVPlayer, there is a function, which can add the observer to AVPlayer and perform periodic update in a time interval.

  • (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;

Thanks.

Percentage of File Buffered

It would be useful to have a delegate method that gives both the current file's total size and how much data has been loaded up to this point. This could be used to calculate the percentage of the file that has buffered, which would be nice for UI to be able to show the user how far ahead the buffer is.

How to play audio in document directory

Hi,
I have downloaded the next track and saved in document directory,but i am unable to play the downloaded audio as asyncSetupSourceGetter in createAudioPlayer is called once in the beginning.
Please help me out to solve this problem.
thanks,
Shabana

a property for bufferdTime

Hello,
Can we have a property for bufferdTime or getPlayerTime can include it ?

            CMTime bufferdTime = CMTimeAdd(timerange.start, timerange.duration);

This is need when drawing time & buffering progress bar.
Thanks for your great job!

Shuffle mode playNext algorithm is rough.

Thanks @JacobSyndeo pointing this out. This should be optimized.

There doesn't appear to be any tracking of which songs have already been played in the playNext method… just a raw randomizing function:
index = arc4random() % items_count;

Player does not play full audio when in background

Hi,
I'm feeding the player with a NSURL array of mp3 stored locally in the device documents folder. When playing in foreground everything works fine but when I send the app on background the mp3 is not fully played.

This is the initialization code for the player:

[hysteriaPlayer registerHandlerPlayerRateChanged:^{

    } CurrentItemChanged:^(AVPlayerItem *item) {
        if(!self.firstPlay){
            [self configureView];
        }

    } PlayerDidReachEnd:^{
        NSLog(@"on end");
    }];

    [hysteriaPlayer registerHandlerReadyToPlay:^(HysteriaPlayerReadyToPlay identifier) {
        switch (identifier) {
            case HysteriaPlayerReadyToPlayCurrentItem:
                if ([hysteriaPlayer getHysteriaPlayerStatus] != HysteriaPlayerStatusForcePause) {
                    [hysteriaPlayer play];
                }
                break;
            case HysteriaPlayerReadyToPlayPlayer:
                [hysteriaPlayer play];
                break;

            default:
                break;
        }
    }];

    [hysteriaPlayer registerHandlerFailed:^(HysteriaPlayerFailed identifier, NSError *error) {
        switch (identifier) {
            case HysteriaPlayerFailedPlayer:
                break;

            case HysteriaPlayerFailedCurrentItem:
                break;
            default:
                break;
        }
        NSLog(@"%@", [error localizedDescription]);
    }];

Audio background mode is selected in my info.plist as well as receiving remote events for the current controller in order to use the ios7 remote controls.

iOS VOIP call does not work in background

We are using Pjsip in TCP mode and already configured keep alive. Application running smoothly in background But after some time when App is trying to re register with SIP server registration message has been sent and app is not getting response,App is getting stuck at the time and then it won't work any more in background. After killing it works OK. can you advise what we are missing ?

Some time its work for 3-4 hours and some time it stop even in 5 minutes :(

Running This code when app is background :

  • (void)applicationDidEnterBackground:(UIApplication *)application {

    [self performSelectorOnMainThread:@selector(keepAlive) withObject:nil waitUntilDone:YES];

    [application setKeepAliveTimeout:KEEP_ALIVE_INTERVAL handler: ^{
    [self performSelectorOnMainThread:@selector(keepAlive) withObject:nil waitUntilDone:YES];
    }];
    }

  • (void)keepAlive {

    int i;

    if (!pj_thread_is_registered()) {
    pj_thread_register("ipjsua", a_thread_desc, &a_thread);
    }

    /* Since iOS requires that the minimum keep alive interval is 600s,

    • application needs to make sure that the account's registration
    • timeout is long enough.
      */

    for (i = 0; i < (int)pjsua_acc_get_count(); ++i) {
    if (pjsua_acc_is_valid(i)) {
    pjsua_acc_set_registration(i, PJ_TRUE);
    }
    }

    pj_thread_sleep(15000);

}

We already enabled background VOIP feature in App's plist and PJSIP for iOS uses the Apple's standard way of background VOIP by registering a socket to be the VOIP socket. What else we need to do could you please explain ?

SeekToTime is not working

Hello developer,

Just want to tell you what i have done. I played one song for 35 seconds, then i left that view and again when i come back to that player view , i want to start the song at 35 second, not from beginning.I think you understand it.What should i do...???

Thanks,
Nirav Patel

AFNetworking missed

Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: 'Could not instantiate class named NSLayoutConstraint
I imported AFNetWorking ,it crashed with the hints above.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.