AVAudioPlayer plays in iOS Simulator but not on the iPhone [closed] - iphone

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm building an app which has to play a mp3 file. For that issue, I'm using AVAudioPlayer following the indications I have been reading from others post.
But my problem is, the code (I have attached bellow) works on the iOS Simulator, but when I try to use it in my iPhone, it doesn't work...
I hope any of you could help me with this issue.
File .h:
#import "UIKit/UIKit.h"
#import "AVFoundation/AVFoundation.h"
#interface ViewController : UIViewController <AVAudioPlayerDelegate>
#property (strong, nonatomic) AVAudioPlayer *player;
#end
File .m:
#import "ViewController.h"
#implementation ViewController
#synthesize player;
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"beep_7" ofType:#"mp3"];
NSLog(#"Audio path: %#", soundFilePath);
NSError *error;
self.player =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:soundFilePath] error:&error];
if (error) {
NSLog(#"Error in audioPlayer: %#",[error localizedDescription]);
}
else {
[self.player setDelegate:self];
[self.player setNumberOfLoops:3]; //just to make sure it is playing my file several times
self.player.volume = 1.0f;
if([self.player prepareToPlay]) //It is always ready to play
NSLog(#"It is ready to play");
else
NSLog(#"It is NOT ready to play ");
if([self.player play]) //It is always playing
NSLog(#"It should be playing");
else
NSLog(#"An error happened");
}
}
-(void)audioPlayerDecodeErrorDidOccur: (AVAudioPlayer *)player error:(NSError *)error {
NSLog(#"audioPlayerDecodeErrorDidOccur -> Error in audioPlayer: %#",[error localizedDescription]);
}
-(void)audioPlayerDidFinishPlaying: (AVAudioPlayer *)player successfully:(BOOL)flag{
NSLog(#"audioPlayerDidFinishPlaying");
}
-(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player{
NSLog(#"audioPlayerBeginInterruption");
}
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player{
NSLog(#"audioPlayerEndInterruption");
}
#end

The first thing to check when the audio (or image) is working (shown) in the simulator and not on the device is the spelling of the audio - file you are trying to access.
Since Mac OSX is NOT case sensitive but iOS is this means that an image spelled iMage.png and accessed as image.png in your code will show in the simulator but NOT on your iPhone.
The other thing to check could be that you have accidentally hit the physical mute button on your iPhone. (Happened to me last week)
Hope it helps!

Related

How does my app recognize that a song finished?

I´m working on my first app. It plays an mp3 song. Everything works fine, but I need the app to recognize that the sound finished, then change the button “pause” image to the “play” one. I can already do that, but just when the button is pressed, not when song ends.
Another issue is that when the song restarts after stop->play, it doesn´t continue playing at the previous volume setting (got a slider). The player starts at maximum volume. I can change the volume slider position, but I am not able to make the app respect the set volume when restarts.
Any help will be very appreciated!
Thnx a lot.
When using "AVAudioPlayerDelegate protocol delegate", please do not forget to set delegate (for example) as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"33fr" ofType:#"mp3"];
NSURL *fileURL = [NSURL fileURLWithPath:path];
NSError *error = nil;
myPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];
if (error) {
NSLog(#"error = %#", error);
return;
}
[myPlayer setDelegate:self]; <<=== HERE!
}
I uploaded sample code here. Please check it. ->
http://yahoo.jp/box/X7Hxfk
I have not done much of Objective-C but it looks like you need to implement a delegate.
I quote: "You implement a delegate to handle interruptions (such as an incoming phone call) and to update the user interface when a sound has finished playing."
I am just reading the AVAudioPlayer Class Reference here:
https://developer.apple.com/library/mac/#documentation/AVFoundation/Reference/AVAudioPlayerClassReference/Reference/Reference.html#//apple_ref/doc/uid/TP40008067
you can use the AVAudioPlayerDelegate protocol delegate
After the audio player is finished playing the song (if it does so
successfully), the audio PlayerDidFinishPlaying:successfully: delegate
method will be called in the delegate object of the audio player. We
can implement this method like below (this method is defined in the
AVAudioPlayerDelegate protocol):
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
if (flag)
{
NSLog(#"Audio player stopped correctly.");
}
else
{ NSLog(#"Audio player did not stop correctly.");
}
if ([player isEqual:self.audioPlayer])
{ self.audioPlayer = nil;
}
else
{ /* This is not the player */ }
}
in .h file add delegate like below code
#interface yourViewController : UIViewController <AVAudioPlayerDelegate>

Record and send/stream sound from iOS device to a server continuously

I am developing an iOS app that has a button with a microphone on it (along with other features). When the user presses the microphone, it gets highlighted and the app should now start recording sound from the device´s microphone and send to a server (a server dedicated to the app, developed by people that I know, so I can affect its design).
I am looking for the simplest yet sturdiest approach to do this, i.e. I have no need to develop a complicated streaming solution or VoIP functionality, unless it is as simple to do as anything else.
The main problem is that we have no idea for how long the user will be recording sound, but we want to make sure that sounds are sent to the server continuously, we do not wish to wait until the user has finished recording. It is okay if the data arrives to the server in chunks however we do not wish to miss any information that the user may be recording, so one chunk must continue where the previous one ended and so on.
Our first thought was to create "chunks" of sound clips of for example 10 seconds and send them continuously to the server. Is there any streaming solution that is better/simpler that I am missing out on?
My question is, what would be the most simple but still reliable approach on solving this task on iOS?
Is there a way to extract chunks of sound from a running recording by AVAudioRecorder, without actually stopping the recording?
look at this
in this tutorial, the sound recorded will be saved at soundFileURL, then you will just have to create an nsdata with that content, and then send it to your server.
hope this helped.
EDIT :
I just created a version that contain 3 buttons, REC, SEND and Stop :
REC : will start recording into a file.
SEND : will save what was recorded on that file in a NSData, and send it to a server, then will restart recording.
and STOP : will stop recording.
here is the code :
in your .h file :
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface ViewController : UIViewController <AVAudioRecorderDelegate>
#property (nonatomic, retain) AVAudioRecorder *audioRecorder;
#property (nonatomic, retain) IBOutlet UIButton *recordButton;
#property (nonatomic, retain) IBOutlet UIButton *stopButton;
#property (nonatomic, retain) IBOutlet UIButton *sendButton;
#property BOOL stoped;
- (IBAction)startRec:(id)sender;
- (IBAction)sendToServer:(id)sender;
- (IBAction)stop:(id)sender;
#end
and in the .m file :
#import "ViewController.h"
#implementation ViewController
#synthesize audioRecorder;
#synthesize recordButton,sendButton,stopButton;
#synthesize stoped;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
sendButton.enabled = NO;
stopButton.enabled = NO;
stoped = YES;
NSArray *dirPaths;
NSString *docsDir;
dirPaths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *soundFilePath = [docsDir
stringByAppendingPathComponent:#"tempsound.caf"];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
NSDictionary *recordSettings = [NSDictionary
dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:AVAudioQualityMin],
AVEncoderAudioQualityKey,
[NSNumber numberWithInt:16],
AVEncoderBitRateKey,
[NSNumber numberWithInt: 2],
AVNumberOfChannelsKey,
[NSNumber numberWithFloat:44100.0],
AVSampleRateKey,
nil];
NSError *error = nil;
audioRecorder = [[AVAudioRecorder alloc]
initWithURL:soundFileURL
settings:recordSettings
error:&error];
audioRecorder.delegate = self;
if (error)
{
NSLog(#"error: %#", [error localizedDescription]);
} else {
[audioRecorder prepareToRecord];
}
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (BOOL) sendAudioToServer :(NSData *)data {
NSData *d = [NSData dataWithData:data];
//now you'll just have to send that NSData to your server
return YES;
}
-(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag
{
NSLog(#"stoped");
if (!stoped) {
NSData *data = [NSData dataWithContentsOfURL:recorder.url];
[self sendAudioToServer:data];
[recorder record];
NSLog(#"stoped sent and restarted");
}
}
- (IBAction)startRec:(id)sender {
if (!audioRecorder.recording)
{
sendButton.enabled = YES;
stopButton.enabled = YES;
[audioRecorder record];
}
}
- (IBAction)sendToServer:(id)sender {
stoped = NO;
[audioRecorder stop];
}
- (IBAction)stop:(id)sender {
stopButton.enabled = NO;
sendButton.enabled = NO;
recordButton.enabled = YES;
stoped = YES;
if (audioRecorder.recording)
{
[audioRecorder stop];
}
}
#end
Good Luck.
It might actually be easier to have fixed-size chunks, instead of fixed-time. Then you can have two buffers, one that you currently fill with sample data. When the active buffer is full, then switch to fill the other buffer, while sending a signal to a sender-thread that takes the first buffer and sends it to the server.
You can of course use fixed-time instead, but then you need to make sure that the buffer is large enough to keep all samples, or use a dynamic buffer that can increase in size when needed. The double-buffering and sending thread can still be the same though.

Storing recorded video URL for saving to library later

I have an application where I recording a video. But when the recording is finished, I can't save the video immediately. I need to show an agreement first. So I try to save the URL i get from the image picker. And save the video to the library later.
This worked fine in iOS4, but not in iOS5.
I'm new to iOS and Objective-C so I probably made some totally wrong declaration of the property that is supposed to hold the URL.
This is some of the code:
.h
#import <UIKit/UIKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#interface Video_recViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIActionSheetDelegate> {
NSURL *tempMoviePath;
}
#property (nonatomic, retain) NSURL *tempMoviePath;
.m
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSURL *moviePath = [info objectForKey:UIImagePickerControllerMediaURL];
[self dismissModalViewControllerAnimated: YES];
NSLog(#"path from image picker: %#", moviePath);
tempMoviePath = moviePath;
NSLog(#"temp movie path: %#", tempMoviePath);
//
[self performSelector:#selector(showAgree) withObject:nil afterDelay:0.5];
}
- (void)userAgreed {
NSLog(#"user agreed");
//NSLog(#"temp movie path: %#", tempMoviePath);
[self saveMyVideo:tempMoviePath];
//[self performSelector:#selector(showSurvey) withObject:nil afterDelay:0.5];
}
- (void)saveMyVideo:(NSURL *)videoURL {
NSLog(#"saving movie at: %#", videoURL);
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:videoURL])
{
[library writeVideoAtPathToSavedPhotosAlbum:videoURL
completionBlock:^(NSURL *assetURL, NSError *error){}
];
}
[library release];
}
Output from log when didFinishPickingMediaWithInfo is:
temp movie path: file://localhost/private/var/mobile/Applications/8CFD1CB7-70A0-465C-B730-817ACE5A4F78/tmp/capture-T0x119660.tmp.hNFzkY/capturedvideo.MOV
Output from the log when doing "saveMyVideo". The URL has suddenly turn into this!! :
saving movie at: (
"0.31269",
"0.32899",
"0.63999",
"0.33001",
"0.3",
"0.6",
"0.15",
"0.05999"
)
(Answered by the OP in a question edit. See Question with no answers, but issue solved in the comments (or extended in chat) )
The OP wrote:
The wrong code was:
tempMoviePath = moviePath;
Because I'm setting a declared property I must use the set & get methods. It should be:
[self setTempMoviePath:moviePath];
Apparently iOS 4 wasn't so hard on this, but iOS5 can't handle it. But, anyway, it was wrong writing like that. I admit my mistake. :)

Iphone audio only working in Simulator NOT in Device

I have set up part of my app to play a sound. Simple - but only is working in Simulator.
Initing audio session this way:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
AudioSessionInitialize(NULL,NULL,NULL,NULL);
AudioSessionSetActive(YES);
return self;
}
Playing sound, setting completion calback, and checking for file this way:
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:#"mp3"];
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path], &soundID);
AudioServicesAddSystemSoundCompletion (soundID,NULL,NULL,
completionCallback,
(void*) self);
if([[NSFileManager defaultManager] fileExistsAtPath:path])
{
NSLog(#"Playing Sound" );
AudioServicesPlaySystemSound(soundID);
}
else {
NSLog(#"NO SOUND");
}
In Simulator, the file is found, sound plays, and completion happens. In device, file is found, sound does not play, and completion is never called.
Any ideas? Thank you very much, both my forehead and my desk appreciate any replies...:)
OK,
So there were a few things I changed to get this working. DOn't have the code in front of me, will try to add later.
I stopped using the system sound and started using AVAudioPlayer instead.
I didn't have my UIView set up as the audio delegate
Was not starting the audio session. Now am starting the audio session in the initNib function(I saw tutrorials that said to use awakeFromNib, but the awakeFromNib never fired...)

Can you see anything wrong in this code?

NSString *path = [[NSBundle mainBundle] pathForResource:[arraySub objectAtIndex:indexPathHere.row] ofType:#"mp3"];
NSURL *file = [[NSURL alloc] initFileURLWithPath:path];
AVAudioPlayer *myPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:file error:nil];
self.player = myPlayer;
[player prepareToPlay];
[player setDelegate:self];
[self.player play];
NSTimeInterval lenghtMusic = player.duration;
if (player.currentTime == lenghtMusic) {
NSLog(#"It worked");
[tableThing deselectRowAtIndexPath:indexPathHere animated:YES];
[myPlayer autorelease];
[file autorelease];
}
Can you see anything wrong?
Apparently, the "if"-statement never gets called...
If I read your code correctly you are trying to find out when the player has finished playing and then you want to deselect the current rode and release the player. Your problem is that you start the player and then immediately checks where it is currently playing. Unless you have an almost 0 length file the currentTime and length will NEVER be equal.
If that is what you are trying to do you should use the AVAudioPlayerDelegate Protocol and especially the:
– audioPlayerDidFinishPlaying:successfully:
method that is called when the player is finished.
So you need to change your class that controls the player by editing the .h file to use the AVAudioPlayerDelegate Protocol. Obviously keep extending whatever you were before.
#interface YourClass <AVAudioPlayerDelegate>
#end
In your .m file:
Then when you have created and assigned your player instance:
[player setDelegate:self];
In the .m file also add the method
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
// Your success code goes here
}
You are comparing double's with ==, which is almost always false due to round-off errors.
Compare with a range e.g.
if (fabs(player.currentTime - lenghtMusic) < 0.0001) {
...
}
I'm a noob iPhone dev, but are you sure that player.currentTime is a NSTimeInterval? That looks like the most obvious candidate.
Also, I'd log out what your player.currentTime is and what lenghtMusic is before your if and that'll probably let you know what's going on.