Objective c - Display buffering progress when playing audio from remote server - iphone

I'm using AVPlayer to play audio from remote server.
I want to display a progress bar showing the buffering progress and the "time played" progress, like the MPMoviePlayerController does when you play a movie.
Does the AVPlayer has any UI component that display this info? If not, how can I get this info (buffering state)?
Thanks

Does the AVPlayer has any UI component that display this info?
No, there's no UI component for AVPlayer.
If not, how can I get this info (buffering state)?
You should observer AVPlayerItem.loadedTimeRanges
[yourPlayerItem addObserver:self forKeyPath:#"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
then using KVO to watch
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
if(object == player.currentItem && [keyPath isEqualToString:#"loadedTimeRanges"]){
NSArray *timeRanges = (NSArray*)[change objectForKey:NSKeyValueChangeNewKey];
if (timeRanges && [timeRanges count]) {
CMTimeRange timerange=[[timeRanges objectAtIndex:0]CMTimeRangeValue];
}
}
}
timerange.duration is what you expect for.
And you have to draw buffer progress manually.
Refs here.

Related

Get ID3 tags from stream on iPhone

I can not get title of song and name of composer on iPhone from HTTP Live Stream (using m3u, m3u8 playlist files). I've tried get it from this site tempomix radio. this is link to streaming - http://stream21.group-network.net:9012
I'm trying use next code:
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:url];
_player = [[AVPlayer playerWithPlayerItem:playerItem] retain];
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[_player addObserver:self forKeyPath:#"status" options:NSKeyValueObservingOptionNew context:NULL];
[_player addObserver:self forKeyPath:#"currentItem" options:NSKeyValueObservingOptionNew context:NULL];
[_player addObserver:self forKeyPath:#"timedMetadata" options:NSKeyValueObservingOptionNew context:NULL];
And then waiting for callback here:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
When callback comes - I check AVPlayerStatus and run play.
Radio plays fine - but never comes to observeValueForKeyPath.
I know this question looks similar to this question but described methods don't work for me.
Any ideas? Thanks.
ID3 tags have nothing to do with the stream that you linked to. SHOUTcast/Icecast doesn't use ID3 tags.
You will have to parse the SHOUTcast metadata protocol. I've answered this question for PHP here: https://stackoverflow.com/a/4914538/362536 The principals are identical, no matter what the language.
See also http://www.smackfu.com/stuff/programming/shoutcast.html

Asynchronous download an object property

I'm programming a feed reader on the iOS platform and, when parsing the json result, i create an array with objects that represent every feed. These object'll be successively push to a NSTableView or to a map (they havgeolocated information). Sometimes happen that the feed does not return the location information, but return the foursquare Id of the place, so I have to contact the foursquare server and get the information.
Wath's the best way to do this? (I so want to know when all the feed in the array has retrieved their information, so I can push all on a map and in the tableview)
Thanks
You could create an NSOperationQueue and add the operations to fetch the information from the server, then observe the "operations" key path of the queue. When operations.count == 0, then do your push to the map and tableview.
Edit:
You aren't polling, per se - you are observing the property and receiving notification of any changes.
Add yourself as an observer of your queue's operations property.
[self.runningQueue addObserver:self forKeyPath:#"operations" options:0 context:NULL];
Then implement the following:
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
{
if (object == self.runningQueue && [keyPath isEqualToString:#"operations"]) {
if ([self.runningQueue.operations count] == 0) {
// push to table view and map view
}
}
else {
[super observeValueForKeyPath:keyPath ofObject:object
change:change context:context];
}
}
See this thread.

iOS Camera focus value

Is there any way to get the focus value from iPhone camera with autofocus?
I want to use this data to calculate the distance from iPhone to an object in focus.
Obviously this is an old question, but as there is an option to get a "lense value" since iOS8 it should appear here.
Since iOS8 you can get the focus value from the lense by key-value observing lensPosition. It is a property of the AVCaptureDevice class which is part of the AVFoundation framework.
So somewhere in your camera class set the observer:
// Assuming _device is an object of the `AVCaptureDevice` class
[_device addObserver:self forKeyPath:#"lensPosition" options:NSKeyValueObservingOptionNew context:nil];
And in the class you used as observer:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:#"lensPosition"]) {
NSLog(#"change: %#", change);
NSLog(#"lens position: %f", [change[#"new"] floatValue]);
}
}
The position of the lens will be displayed as a scalar value from 0 to 1.
Also you can set the lens position manually. You can find out more about managing the lens position in the Apple Documentation.
Finally as with all key-value observer don't forget to remove the observer.
NOTE: The lens is a mechanical part in the device and focusing is done by moving the lens via a spring. So values differ depending on the device and situation.
I do not think there is such a thing as a focus value.

AVQueuePlayer stream status?

I really new to Obj-C and iOS development, i found very much useful information here, but here is a question I didn't find the answer.
I got instance of AVQueuePlayer which plays audio stream from url.
How can I know that audio stream is loaded? For example when I press "Play" button, there is couple of seconds delay between a button press and actual start of streaming.
I looked at developer.apple.com library and didn't find any method that I can use to check status of AVQueuePlayer. There is one in AVPLayer, but AVPlayer is not supporting stream over http as far as i know.
Thank you.
I am not sure what you mean by "loaded": do you mean when the item is fully loaded or when the item is ready to play?
AVQueuePlayer supports http streams (HTTP Live and files) in the same way as AVPlayer. You should review the AVFoundation Programming Guide, Handling Different Types of Asset.
The most common case is when an item is ready to play, so I'll answer that one. If you are working with iOS with AVQueuePlayer < 4.3, you need to check the status of AVPlayerItem by observing the value of the AVPlayerItem status key:
static int LoadingItemContext = 1;
- (void)loadExampleItem
{
NSURL *remoteURL = [NSURL URLWithString:#"http://media.example.com/file.mp3"];
AVPlayerItem *item = [AVPlayerItem playerItemWithURL:remoteURL];
// insert the new item at the end
if (item) {
[self registerAVItemObserver:item];
if ([self.player canInsertItem:item afterItem:nil]) {
[self.player insertItem:item afterItem:nil];
// now observe item.status for when it is ready to play
}
}
}
- (void)registerAVItemObserver:(AVPlayerItem *)playerItem
{
[playerItem addObserver:self forKeyPath:#"status" options:NSKeyValueObservingOptionNew context:(void*)&LoadingItemContext];
}
- (void)removeAVItemObserver:(AVPlayerItem *)playerItem
{
#try {
[playerItem removeObserver:self forKeyPath:#"status"];
}
#catch (...) { }
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == &LoadingItemContext) {
AVPlayerItem *item = (AVPlayerItem*)object;
AVPlayerItemStatus status = item.status;
if (status == AVPlayerItemStatusReadyToPlay) {
// now you know you can set your player to play, update your UI...
} else if (status == AVPlayerItemStatusFailed) {
// handle error here, i.e., skip to next item
}
}
}
That is just a pre-4.3 example. After 4.3 you can load a remote file (or HTTP Live playlist) using the code example in AVFoundation Programming Guide, Preparing an Asset For Use, with loadValuesAsynchronouslyForKeys:completionHandler. If you are using loadValuesAsynchronouslyForKeys for a HTTP Live stream you should observe the #"tracks" property.

How to stream a remote mp3 without using a full screen player? e.g. shoutcast

how do I play a remote .mp3 in an iPhone app with full control over the playback controls and visuals shown? I know MPMoviePlayerController can stream .mp3s but it takes over the whole screen.
If you could just point me in the direction of an appropriate guide or class reference that would be great.
I dont think AVAudioPlayer supports streaming mp3s. From my experience, i am reasonably confident in saying that it only plays local files.
I have played remote mp3s using AVPlayer.
self.player = [[AVPlayer alloc] initWithURL:fileURL];
//inits the AVPlayer object.
[player addObserver:self forKeyPath:#"status" options:0 context:nil];
// You need to watch for for when the player obeject becomes ready to play, using key-value observation
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if(object == player && [keyPath isEqualToString:#"status"])
{
playButton.enabled = YES;
playButton.titleLabel.text = #"Play";
.....
//do whatever you need to do here to get the object ready to play.
}
}
a simple [player play] will start playing the file.
//metadata is available at
player.currentItem.asset.commonMetadata
//and time played can be calculated by dividing x by y
UInt64 x = self.player.currentTime.value;
int32_t y = self.player.currentTime.timescale;
int secs = x/y;
You might want to use AVAudioPlayer and create your own controls.
I don't know if MPMediaPlayer can play a streamed mp3, but it can play local media in an "app" player instead of an "ipod" player (which takes over the screen). MPMediaPlayer is similar to AVAudioPlayer in that you can play with or without any UI, which you can create. Play, pause, stop, rewind, forward, etc.