AVPlayer got the metadata but not playing - objective-c

I'm trying to do a very simple application, the purpose is listening an audio stream (AAC 64 kbps). To do so I'm using AVPlayer from the Apple AVFoundation has follow :
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize playerItem, player;
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
playerItem = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:#"http://stream.myjungly.fr/MYJUNGLY2"]];
[playerItem addObserver:self forKeyPath:#"timedMetadata" options:NSKeyValueObservingOptionNew context:nil];
player = [AVPlayer playerWithPlayerItem:playerItem];
[player play];
NSLog(#"player item error : %#", playerItem.error.description);
NSLog(#"player error : %#", player.error.description);
}
- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object
change:(NSDictionary*)change context:(void*)context {
if ([keyPath isEqualToString:#"timedMetadata"])
{
AVPlayerItem* _playerItem = object;
for (AVMetadataItem* metadata in _playerItem.timedMetadata)
{
NSLog(#"\nkey: %#\nkeySpace: %#\ncommonKey: %#\nvalue: %#", [metadata.key description], metadata.keySpace, metadata.commonKey, metadata.stringValue);
}
}
}
#end
My object player and playerItem are strong properties :
ViewController.h
#interface ViewController : UIViewController
#property (nonatomic, strong) AVPlayerItem* playerItem;
#property (nonatomic, strong) AVPlayer* player;
#end
The Key Value Observer is working great, here is my log :
2013-05-14 11:18:03.725 MusicAvPlayer[6494:907] player item error : (null)
2013-05-14 11:18:03.728 MusicAvPlayer[6494:907] player error : (null)
2013-05-14 11:18:08.140 MusicAvPlayer[6494:907]
key: title
keySpace: comn
commonKey: title
value: Alabama Shakes - Be Mine
But the audio is not played, I've go no sound ! Any idea why ?
EDIT: I already look at this questions :
No sound coming from AVPlayer
AVAudioPlayer, No Sound
AVAudioPlayer not playing any sound
That's why I'm using a strong property, so I guess my problem is not ARC related

I found problem : the iphone was in silent mode ... so no sound can go out on the speaker, the the sound was played when I was using the head phone.
But I've got a new question now : how can you play sound on the speaker when the phone is in silent mode ? (like the official Music application)
EDIT : ... and the answer is there :
Play sound on iPhone even in silent mode

// Init PlayerItem
playerItem = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:#"http://stream.myjungly.fr/MYJUNGLY2"]];
// Init Player Obj
player = [AVPlayer playerWithPlayerItem:playerItem];
// Add objserver on Player
[player addObserver:self forKeyPath:#"status" options:0 context:nil];
Add Observer Method your Class
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
if (object == player && [keyPath isEqualToString:#"status"]) {
if (player.status == AVPlayerStatusReadyToPlay) {
// Start playing...
[player play];
} else if (player.status == AVPlayerStatusFailed) {
// something went wrong. player.error should contain some information
}
}
if ([keyPath isEqualToString:#"timedMetadata"])
{
AVPlayerItem* _playerItem = object;
for (AVMetadataItem* metadata in _playerItem.timedMetadata)
{
NSLog(#"\nkey: %#\nkeySpace: %#\ncommonKey: %#\nvalue: %#", [metadata.key description], metadata.keySpace, metadata.commonKey, metadata.stringValue);
}
}
}

Related

Key-Value Observing adjustingFocus no notification

I'm not familiar with iOS but I'm trying to find when the default, built-in camera application is focusing. To do this I create my own separate Objective-C application and following this answer here [iPhone : camera autofocus observer? but I'm not getting anything from observeValueForKeyPath in the NSLog.
#import "ViewController.h"
#import "AVFoundation/AVCaptureDevice.h"
#import "AVFoundation/AVMediaFormat.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(#"viewDidLoad");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// callback
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSLog(#"observeValueForKeyPath");
if( [keyPath isEqualToString:#"adjustingFocus"] ){
BOOL adjustingFocus = [ [change objectForKey:NSKeyValueChangeNewKey] isEqualToNumber:[NSNumber numberWithInt:1] ];
NSLog(#"Is adjusting focus? %#", adjustingFocus ? #"YES" : #"NO" );
NSLog(#"Change dictionary: %#", change);
}
if( [keyPath isEqualToString:#"focusMode"] ){
AVCaptureFocusMode focusMode = [ [change objectForKey:NSKeyValueChangeNewKey] isEqualToNumber:[NSNumber numberWithInt:1] ];
NSLog(#"focusMode? %ld", focusMode);
}
}
// register observer
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear: animated];
NSLog(#"viewWillAppear");
AVCaptureDevice *camDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
int flags = NSKeyValueObservingOptionNew;
[camDevice addObserver:self forKeyPath:#"adjustingFocus" options:flags context:nil];
[camDevice addObserver:self forKeyPath:#"focusMode" options:flags context:nil];
}
#end
Any help much appreciated.
For anyone who visits this question, the answer is what Bluewings wrote as a comment. I was trying to use KVO to observe one application from another which is not possible since only one lock on a capture device is possible at one time.

Watch Connectivity not working

I am trying to create an app where I can send information from an apple watch to my ios Parent App. I have written the code for it but when I run the WatchConnectivity App, the information does not transfer between the apple watch and the parent ios app. This may be a problem with my code or it may be because for some reason the watch does not start with the app. I have to go to the simulator and click on the app to get it started. Is this why my code is not working?
InterfaceController.m
#import "InterfaceController.h"
#import <WatchConnectivity/WatchConnectivity.h>
#interface InterfaceController() <WCSessionDelegate>
#property (strong, nonatomic) WCSession *session;
#end
#implementation InterfaceController
-(instancetype)init {
self = [super init];
if (self) {
if ([WCSession isSupported]) {
self.session = [WCSession defaultSession];
self.session.delegate = self;
[self.session activateSession];
}
}
return self;
}
- (IBAction)catPressed {
[self sendText:#"cat"];
}
- (IBAction)dogPressed {
[self sendText:#"dog"];
}
- (IBAction)pandaPressed {
[self sendText:#"panda"];
}
- (IBAction)bunnyPressed {
[self sendText:#"bunny"];
}
-(void)sendText:(NSString *)text {
NSDictionary *applicationDict = #{#"emoji":text};
[self.session updateApplicationContext:applicationDict error:nil];
}
ViewController.m
#import "ViewController.h"
#import <WatchConnectivity/WatchConnectivity.h>
#interface ViewController () <WCSessionDelegate>
#property (weak, nonatomic) IBOutlet UILabel *textLabel;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
if ([WCSession isSupported]) {
WCSession *session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
NSLog(#"HIIII");
}
}
- (void)session:(nonnull WCSession *)session didReceiveApplicationContext:(nonnull NSDictionary<NSString *,id> *)applicationContext {
NSString *text = [applicationContext objectForKey:#"text"];
dispatch_async(dispatch_get_main_queue(), ^{
[self.textLabel setText:[NSString stringWithFormat:#"Text: %#", text]];
});
}
It turns out that I needed to open the parent app on the iPhone first to start sharing information between the iPhone and Watch. Thanks to MSU_Bulldog for suggesting this idea.

Unrecognized Selector in AVplayer setNumberOfLoops Method

When calling the numberOfLoops method like so:
[_player setNumberOfLoops:-1];
I get the following error:
-[AVPlayer setNumberOfLoops:]: unrecognized selector sent to instance 0x7d52d30
How can this be fixed?
Code:
Header:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface ViewController : UIViewController {
}
#property (strong, nonatomic) AVAudioPlayer *player;
- (IBAction)playMusic:(id)sender;
#end
Implementation:
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)playMusic:(id)sender {
_player = [AVPlayer playerWithURL:[NSURL URLWithString:#"http://urlpath.wav"]];
[_player setNumberOfLoops:-1];
[_player prepareToPlay];
[_player play];
}
#end
Thank you for your time,
Yoni201.
You've created an instance of AVPlayer, not an instance of AVAudioPlayer. It looks like you want to be creating an AVAudioPlayer instead (as is indicated by your choice of that class for the actual player property on your class. AVAudioPlayer actually has the numberOfLoops property, while AVPlayer does not. For more information, see the documentation for AVAudioPlayer and AVPlayer.
AVPlayer doesn't have a numberOfLoops property. That is a property of `AVAudioPlayer. Don't ignore compiler warnings when you build your app.
Also, you defined _player to be an AVAudioPlayer but you alloc/init AVPlayer.
Change your code to:
NSError *error = nil;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://urlpath.wav"] error:&error];
if (player) {
[player setNumberOfLoops:-1];
[player prepareToPlay];
[player play];
self.player = player;
} else {
NSLog(#"Error create audio player: %#", error);
}
I think that the method you are calling doesn't exist (acceosing to your error).
Try: _player.numberOfLoops=-1

Play video in Mac OS X 10.7

What is the simplest way to play a video programmatically with Objective-C in Mac OS X 10.7 (Lion)? And if I want to support OS X 10.6 (Snow Leopard) too?
I noticed that iOS AV Foundation was introduced to OS X 10.7. Unfortunately the documentation seems to be written for iOS and I found it confusing.
Here's a NSView subclass that plays a video given a URL, using AV Foundation (thus Mac OS X 10.7 upwards only). Based on the AVSimplePlayer sample code.
Header:
#interface RMVideoView : NSView
#property (nonatomic, readonly, strong) AVPlayer* player;
#property (nonatomic, readonly, strong) AVPlayerLayer* playerLayer;
#property (nonatomic, retain) NSURL* videoURL;
- (void) play;
#end
Implementation:
static void *RMVideoViewPlayerLayerReadyForDisplay = &RMVideoViewPlayerLayerReadyForDisplay;
static void *RMVideoViewPlayerItemStatusContext = &RMVideoViewPlayerItemStatusContext;
#interface RMVideoView()
- (void)onError:(NSError*)error;
- (void)onReadyToPlay;
- (void)setUpPlaybackOfAsset:(AVAsset *)asset withKeys:(NSArray *)keys;
#end
#implementation RMVideoView
#synthesize player = _player;
#synthesize playerLayer = _playerLayer;
#synthesize videoURL = _videoURL;
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.wantsLayer = YES;
_player = [[AVPlayer alloc] init];
[self addObserver:self forKeyPath:#"player.currentItem.status" options:NSKeyValueObservingOptionNew context:RMVideoViewPlayerItemStatusContext];
}
return self;
}
- (void) dealloc {
[self.player pause];
[self removeObserver:self forKeyPath:#"player.currentItem.status"];
[self removeObserver:self forKeyPath:#"playerLayer.readyForDisplay"];
[_player release];
[_playerLayer release];
[_videoURL release];
[super dealloc];
}
- (void) setVideoURL:(NSURL *)videoURL {
_videoURL = videoURL;
[self.player pause];
[self.playerLayer removeFromSuperlayer];
AVURLAsset *asset = [AVAsset assetWithURL:self.videoURL];
NSArray *assetKeysToLoadAndTest = [NSArray arrayWithObjects:#"playable", #"hasProtectedContent", #"tracks", #"duration", nil];
[asset loadValuesAsynchronouslyForKeys:assetKeysToLoadAndTest completionHandler:^(void) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self setUpPlaybackOfAsset:asset withKeys:assetKeysToLoadAndTest];
});
}];
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == RMVideoViewPlayerItemStatusContext) {
AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
switch (status) {
case AVPlayerItemStatusUnknown:
break;
case AVPlayerItemStatusReadyToPlay:
[self onReadyToPlay];
break;
case AVPlayerItemStatusFailed:
[self onError:nil];
break;
}
} else if (context == RMVideoViewPlayerLayerReadyForDisplay) {
if ([[change objectForKey:NSKeyValueChangeNewKey] boolValue]) {
self.playerLayer.hidden = NO;
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark - Private
- (void)onError:(NSError*)error {
// Notify delegate
}
- (void)onReadyToPlay {
// Notify delegate
}
- (void)setUpPlaybackOfAsset:(AVAsset *)asset withKeys:(NSArray *)keys {
for (NSString *key in keys) {
NSError *error = nil;
if ([asset statusOfValueForKey:key error:&error] == AVKeyValueStatusFailed) {
[self onError:error];
return;
}
}
if (!asset.isPlayable || asset.hasProtectedContent) {
[self onError:nil];
return;
}
if ([[asset tracksWithMediaType:AVMediaTypeVideo] count] != 0) { // Asset has video tracks
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.playerLayer.frame = self.layer.bounds;
self.playerLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
self.playerLayer.hidden = YES;
[self.layer addSublayer:self.playerLayer];
[self addObserver:self forKeyPath:#"playerLayer.readyForDisplay" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:RMVideoViewPlayerLayerReadyForDisplay];
}
// Create a new AVPlayerItem and make it our player's current item.
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
[self.player replaceCurrentItemWithPlayerItem:playerItem];
}
#pragma mark - Public
- (void) play {
[self.player play];
}
#end
"Simplest" depends on exactly what you're trying to do. If you want more control (e.g., rendering the movie as an OpenGL texture) or less (e.g., a completely independent window that you can just pop up and ignore), there might be different answers.
But for most use cases, if you want 10.6+ support, the simplest way to show a movie is QTKit. See the article "Using QTKit for Media Playback" in the Xcode documentation for a good starting point.

AVAudioPlayer not playing iPad2

New to IOS dev, I'm testing AVAudioplayer to play sound on iPad2 (Xcode 4.2 project, ARC/storyboard enabled). Sound plays ok in simulator and no error. No error on device either but no sound.
Been browsing this fine resource temple, but nothing I've tried based on feedback here has produced anything but deafening iPad silence. Could someone help? My .h:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface ViewController : UIViewController
<AVAudioPlayerDelegate>
{
AVAudioPlayer *audioPlayer;
UISlider *volumeControl;
UILabel *timerLabel;
NSTimer *playbackTimer;
}
#property (nonatomic, retain) IBOutlet UISlider *volumeControl;
#property (nonatomic, retain) IBOutlet UILabel *timerLabel;
#property (nonatomic, retain) NSTimer *playbackTimer;
#property (nonatomic, strong) AVAudioPlayer *audioPlayer;
-(IBAction) playAudio;
-(IBAction) stopAudio;
-(IBAction) adjustVolume;
#end
My .m:
#import "ViewController.h"
#implementation ViewController
#synthesize volumeControl, timerLabel, playbackTimer, audioPlayer;
-(void)playAudio
{
playbackTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateTime)
userInfo:nil
repeats:YES];
[audioPlayer play];
}
-(void)stopAudio
{
[playbackTimer invalidate];
[audioPlayer stop];
}
-(void)adjustVolume
{
if (audioPlayer != nil)
{
audioPlayer.volume = volumeControl.value;
}
}
-(void)updateTime
{
float minutes = floor(audioPlayer.currentTime/60);
float seconds = audioPlayer.currentTime - (minutes * 60);
float duration_minutes = floor(audioPlayer.duration/60);
float duration_seconds =
audioPlayer.duration - (duration_minutes * 60);
NSString *timeInfoString = [[NSString alloc]
initWithFormat:#"%0.0f.%0.0f / %0.0f.%0.0f",
minutes, seconds,
duration_minutes, duration_seconds];
timerLabel.text = timeInfoString;
}
-(void)audioPlayerDidFinishPlaying:
(AVAudioPlayer *)player successfully:(BOOL)flag
{
}
-(void)audioPlayerDecodeErrorDidOccur:
(AVAudioPlayer *)player error:(NSError *)error
{
}
-(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
}
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player
{
}
my viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"song"
ofType:#"mp3"]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:url
error:&error];
if (error)
{
NSLog(#"Error in audioPlayer: %#",
[error localizedDescription]);
} else {
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
}
[super viewDidLoad];
}
Make sure that the file is indeed an mp3 format. Make sure that you are copying the file into the bundle, and not playing off of local path on your desktop. Check the device volume. Check the return BOOL from the play call. all of these are possible explanations.
Is it not playing sounds at all? No sounds even with headphones plugged in? If it's just no sound through the built-in speaker, but sounds through headphones, make sure that your device ring/sounds volume isn't muted. Check the toggle switch on the side (if you have that set to mute vs orientation lock). The bell shouldn't be crossed out. Just because you press the volume up button doesn't mean it's unmuted from the speaker. Have you tested YouTube videos or music files to ensure your iPad isn't having hardware issues?