Making this run while other views are in 'use' - iphone

Hello
Okay right I have a view called 'RecordViewController' this has the voice recorder function so once the user presses 'record', it records their voice, I have also created a 'back' button. But once that back button is tapped the voice recording also stops. I want it so once the user goes back, its still recording their voice.
Here is the code I used:
.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreAudio/CoreAudioTypes.h>
#interface RecordViewController : UIViewController <AVAudioRecorderDelegate> {
IBOutlet UIButton * btnStart;
IBOutlet UIButton * btnPlay;
IBOutlet UIActivityIndicatorView * actSpinner;
BOOL toggle;
NSURL * recordedTmpFile;
AVAudioRecorder * recorder;
NSError * error;
NSTimer *theTimer;
IBOutlet UILabel *seconds;
int mainInt;
NSString *timeRemainingString;
}
#property (nonatomic,retain)IBOutlet UIActivityIndicatorView * actSpinner;
#property (nonatomic,retain)IBOutlet UIButton * btnStart;
#property (nonatomic,retain)IBOutlet UIButton * btnPlay;
- (IBAction) start_button_pressed;
- (IBAction) play_button_pressed;
-(IBAction)goBack:(id)sender;
-(void)countUp;
#end
.m
#import "RecordViewController.h"
#implementation RecordViewController
#synthesize actSpinner, btnStart, btnPlay;
-(void)countUp {
mainInt += 1;
seconds.text = [NSString stringWithFormat:#"%02d", mainInt];
}
-(IBAction)goBack:(id)sender; {
[self dismissModalViewControllerAnimated:YES];
}
/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
//Start the toggle in true mode.
toggle = YES;
btnPlay.hidden = YES;
//Instanciate an instance of the AVAudioSession object.
AVAudioSession * audioSession = [AVAudioSession sharedInstance];
//Setup the audioSession for playback and record.
//We could just use record and then switch it to playback leter, but
//since we are going to do both lets set it up once.
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error: &error];
//Activate the session
[audioSession setActive:YES error: &error];
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (IBAction) start_button_pressed{
if(toggle)
{
toggle = NO;
[actSpinner startAnimating];
[btnStart setImage:[UIImage imageNamed:#"stoprecording.png"] forState:UIControlStateNormal];
mainInt = 0;
theTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countUp) userInfo:nil repeats:YES];
btnPlay.enabled = toggle;
btnPlay.hidden = !toggle;
//Begin the recording session.
//Error handling removed. Please add to your own code.
//Setup the dictionary object with all the recording settings that this
//Recording sessoin will use
//Its not clear to me which of these are required and which are the bare minimum.
//This is a good resource: http://www.totodotnet.net/tag/avaudiorecorder/
NSMutableDictionary* recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatAppleIMA4] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];
//Now that we have our settings we are going to instanciate an instance of our recorder instance.
//Generate a temp file for use by the recording.
//This sample was one I found online and seems to be a good choice for making a tmp file that
//will not overwrite an existing one.
//I know this is a mess of collapsed things into 1 call. I can break it out if need be.
recordedTmpFile = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent: [NSString stringWithFormat: #"%.0f.%#", [NSDate timeIntervalSinceReferenceDate] * 1000.0, #"caf"]]];
NSLog(#"Using File called: %#",recordedTmpFile);
//Setup the recorder to use this file and record to it.
recorder = [[ AVAudioRecorder alloc] initWithURL:recordedTmpFile settings:recordSetting error:&error];
//Use the recorder to start the recording.
//Im not sure why we set the delegate to self yet.
//Found this in antother example, but Im fuzzy on this still.
[recorder setDelegate:self];
//We call this to start the recording process and initialize
//the subsstems so that when we actually say "record" it starts right away.
[recorder prepareToRecord];
//Start the actual Recording
[recorder record];
//There is an optional method for doing the recording for a limited time see
//[recorder recordForDuration:(NSTimeInterval) 10]
}
else
{
toggle = YES;
[actSpinner stopAnimating];
[btnStart setImage:[UIImage imageNamed:#"recordrecord.png"] forState:UIControlStateNormal];
btnPlay.enabled = toggle;
btnPlay.hidden = !toggle;
[theTimer invalidate];
NSLog(#"Using File called: %#",recordedTmpFile);
//Stop the recorder.
[recorder stop];
}
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
-(IBAction) play_button_pressed{
//The play button was pressed...
//Setup the AVAudioPlayer to play the file that we just recorded.
AVAudioPlayer * avPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:recordedTmpFile error:&error];
[avPlayer prepareToPlay];
[avPlayer play];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
//Clean up the temp file.
NSFileManager * fm = [NSFileManager defaultManager];
[fm removeItemAtPath:[recordedTmpFile path] error:&error];
//Call the dealloc on the remaining objects.
[recorder dealloc];
recorder = nil;
recordedTmpFile = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
Thanks

You are in need of a shared object that your application can access during the recording process. Something along the lines of
#interface UserRecording : NSObject
+(UserRecording*)currentRecording;
#end
You will want to take into account all of the fun threading principles as well as delegation and/or notifications if you would like to properly implement this.

Since you are creating the AudioSession inside of the modal dialog, it will be dealloc'ed when you dismiss that modal dialog. Try instantiating the AudioSession in the main VC, pass that into the modal VC and just start it there.

Related

When using storyboards, and changing a view, sound will not stop playing in new view

I am trying to do something similar to what was requested in this question:
Playing audio with controls in iOS
I am using Storyboards with XCode 4.2. On my initial view page, I just have buttons that call other views, and no sounds are played there. These other views contain a UINavigationController with a BarButtonItem to allow you to go back. Other view pages will have buttons that allow one to play a sound. Each sound has its own play button, and there are resume, pause and stop buttons.
All sounds play fine, but if I hit the back button to the main page, the sound keeps playing. The desired behavior is for the sound to stop when navigating back to the main page via the back button.
Before storyboards, I could easily code a back button to stop the audio, but storyboards appear not that simple. It appears that I have to implement the method prepareForSegue. Okay, I can set the Segue identifier can be set in the Attributes Inspector, and referring back to the earlier post, I will use showPlayer.
But I was thinking I could code the prepareForSegue in one of my sound views, as seen in this cool example:
http://www.scott-sherwood.com/?p=219
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"showPlayer"]){
SoundPageController *theAudio = (SoundPageController *)[segue ViewController];
theAudio.delegate = self;
}
}
In the main page ViewController.m, I tried adding:
#property (strong, nonatomic) AVAudioPlayer *theAudio;
And I tried adding something like:
- (void)viewDidLoad {
[super viewDidLoad];
// this is the important part: if we already have something playing, stop it!
if (audioPlayer != nil)
{
[audioPlayer stop];
}
// everything else should happen as normal.
audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:url
error:&error];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
I wasn't able to get this to work, so I reverted the changes back to original. I will put my simplified code below, and if you have suggestions how to do it right, please let me know!
ViewController.h:
#interface ViewController : UIViewController {
}
ViewController.m (pretty much default):
#import "ViewController.h"
#import "AppDelegate.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
SoundPage1.h:
#import
#import <AVFoundation/AVAudioPlayer.h>
#interface occupy : UIViewController <AVAudioPlayerDelegate> {
AVAudioPlayer* theAudio;
}
//-(IBAction)PressBack:(id)sender; now the back button is linked up through storyboard
-(IBAction)pushButton1;
-(IBAction)pushButton2;
-(IBAction)play;
-(IBAction)stop;
-(IBAction)pause;
#end
SoundPage1.m
#import "SoundPage1.h"
#import "AppDelegate.h"
#import "ViewController.h"
#implementation SoundPage1
-(IBAction)pushButton {
NSString *path = [[NSBundle mainBundle] pathForResource:#"sound1" ofType:#"mp3"];
if(theAudio)[theAudio release];
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
theAudio.volume = 1.0;
[theAudio play];
}
-(IBAction)pushButton2 {
NSString *path = [[NSBundle mainBundle] pathForResource:#"sound2" ofType:#"mp3"];
if(theAudio)[theAudio release];
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
theAudio.volume = 1.0;
[theAudio play];
}
// Old code from XCode 3.x when creating a back button that could stop the audio was easy
//-(IBAction)PressBack:(id)sender{
// [theAudio stop];
// ViewController* myappname = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
// [self.navigationController pushViewController:myappname animated:NO];
// }
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
Add in the code for play, stop and pause for the buttons.
I tried to format this, sorry in advance if it is hard to read.
Thanks for any suggestions!
Rob
You should stop the AVAudioPlayer in viewWillDisappear.
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if(theAudio && theAudio.isPlaying) {
[theAudio stop];
}
}
ViewDidUnload is only called by the program when the device is reaching the end of memory capacity, not when you change views. Only just found this out myself this week, while struggling with the same problem.
Hope that clears things up.

Songs not getting played by setQueueWithItemCollection api

I am testing the following simple code on my iphone 4 with iOS 5.0 on it. I implemented the following sample code to play a user selected song. The user clicks on the a button on the page, its shows his playlist/songs .... but once the song is selected and picker is dismissed, the song doesnt play. What gives?
From my *.h file
#interface MusicPlayerDemoViewController : UIViewController <MPMediaPickerControllerDelegate> {
MPMusicPlayerController *musicPlayer;
}
#property (nonatomic, retain) MPMusicPlayerController *musicPlayer;
- (IBAction)selectMusic:(id)sender;
from my *.m file
- (IBAction)selectMusic:(id)sender
{
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = NO; // this is the default
[self presentModalViewController:mediaPicker animated:YES];
[mediaPicker release];
}
// Media picker delegate methods
- (void)mediaPicker: (MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection {
// We need to dismiss the picker
[self dismissModalViewControllerAnimated:YES];
[musicPlayer setQueueWithItemCollection:mediaItemCollection];
[musicPlayer play];
}
- (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker {
[self dismissModalViewControllerAnimated:YES];
}
SOLUTION:
Add the following code in ViewDidLoad. I wasn't instantiating the player. All works
[self setMusicPlayer: [MPMusicPlayerController applicationMusicPlayer]];
// By default, an application music player takes on the shuffle and repeat modes
// of the built-in iPod app. Here they are both turned off.
[musicPlayer setShuffleMode: MPMusicShuffleModeOff];
[musicPlayer setRepeatMode: MPMusicRepeatModeNone];

AVplayer not showing in ScrollView after 2-3 times

I am adding multiple AVPlayer objects in a scrollview. For the first time this is working fine but as i go back to my previous view and come back again i am not able to see AVPlayer objects in scrollView.
I need as matrix of multiple AVPlayer to show thumbnails of my videos.
Please help me asap
Thanks in advance.
I had a similar problem and after a lot of searching discovered that the AVPLayerItem object causes this issue.
Basically when the AVPlayer items go offscreen you need to make sure everything is released properly, and then recreate everything when they come back on screen.
As part of the release process, include the line:
[AVPlayer replaceCurrentItemWithPlayerItem:nil];
That sorted a very similar issue for me.
[AVPlayer replaceCurrentItemWithPlayerItem:nil];
also solves my problem of cannot releasing current player item immediately. (can't manually do that because it's retained by the class..)
Here's how you get 10 AVPlayers to play simultaneously, inside the same scrollView, each and every time you scroll it:
//
// ViewController.m
// VideoWall
//
// Created by James Alan Bush on 6/13/16.
// Copyright © 2016 James Alan Bush. All rights reserved.
//
#import "ViewController.h"
#import "AppDelegate.h"
static NSString *kCellIdentifier = #"Cell Identifier";
#interface ViewController () {
dispatch_queue_t dispatchQueueLocal;
}
#end
#implementation ViewController
- (id)initWithCollectionViewLayout:(UICollectionViewFlowLayout *)layout
{
if (self = [super initWithCollectionViewLayout:layout])
{
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kCellIdentifier];
dispatchQueueLocal = dispatch_queue_create( "local session queue", DISPATCH_QUEUE_CONCURRENT );
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.collectionView setDataSource:self];
[self.collectionView setContentSize:CGSizeMake(AppDelegate.sharedAppDelegate.width, AppDelegate.sharedAppDelegate.height)];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[super dealloc];
}
#pragma mark <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
#pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return AppDelegate.sharedAppDelegate.assetsFetchResults.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = (UICollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier forIndexPath:indexPath];
[CATransaction begin];
[CATransaction setCompletionBlock:^{
cell.contentView.layer.sublayers = nil;
dispatch_release(dispatchQueueLocal);
}];
dispatch_retain(dispatchQueueLocal);
dispatch_async( dispatchQueueLocal, ^{
[self drawPlayerLayerForCell:cell atIndexPath:indexPath];
});
[CATransaction commit];
return cell;
}
- (void)drawPlayerLayerForCell:(UICollectionViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
void (^drawPlayerLayer)(UICollectionViewCell*, NSIndexPath*) = ^(UICollectionViewCell* cell, NSIndexPath* indexPath) {
[AppDelegate.sharedAppDelegate.imageManager requestPlayerItemForVideo:AppDelegate.sharedAppDelegate.assetsFetchResults[indexPath.item] options:nil resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
dispatch_async(dispatch_get_main_queue(), ^{
if(![[info objectForKey:PHImageResultIsInCloudKey] boolValue]) {
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:[AVPlayer playerWithPlayerItem:playerItem]];
[playerLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[playerLayer setBorderColor:[UIColor whiteColor].CGColor];
[playerLayer setBorderWidth:1.0f];
[playerLayer setFrame:cell.contentView.bounds];
[cell.contentView.layer addSublayer:playerLayer];
[(AVPlayer *)playerLayer.player play];
} else {
[AppDelegate.sharedAppDelegate.imageManager requestImageForAsset:AppDelegate.sharedAppDelegate.assetsFetchResults[indexPath.item]
targetSize:CGSizeMake(AppDelegate.sharedAppDelegate.flowLayout.itemSize.width, AppDelegate.sharedAppDelegate.flowLayout.itemSize.height)
contentMode:PHImageContentModeAspectFill
options:nil
resultHandler:^(UIImage *result, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
cell.contentView.layer.contents = (__bridge id)result.CGImage;
});
}];
}
});
}];
};
drawPlayerLayer(cell, indexPath);
}
#end
Here's the AppDelegate implementation file:
//
// AppDelegate.m
// VideoWall
//
// Created by James Alan Bush on 6/13/16.
// Copyright © 2016 James Alan Bush. All rights reserved.
//
#import "AppDelegate.h"
#import "ViewController.h"
#implementation AppDelegate
+ (AppDelegate *)sharedAppDelegate
{
return (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch
self.width = [[UIScreen mainScreen] bounds].size.width / 2.0;
self.height = [[UIScreen mainScreen] bounds].size.height / 4.0;
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = [self viewController];
self.window.rootViewController.view = self.viewController.view;
[self.window makeKeyAndVisible];
return YES;
}
- (ViewController *)viewController {
ViewController *c = self->_viewController;
if (!c) {
c = [[ViewController alloc] initWithCollectionViewLayout:[self flowLayout]];
[c.view setFrame:[[UIScreen mainScreen] bounds]];
self->_viewController = c;
}
return c;
}
- (UICollectionViewFlowLayout *)flowLayout {
UICollectionViewFlowLayout *v = self->_flowLayout;
if (!v) {
v = [UICollectionViewFlowLayout new];
[v setItemSize:CGSizeMake(AppDelegate.sharedAppDelegate.width, AppDelegate.sharedAppDelegate.height)];
[v setSectionInset:UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)];
[v setMinimumLineSpacing:0.0];
[v setMinimumInteritemSpacing:0.0];
[v setEstimatedItemSize:CGSizeMake(AppDelegate.sharedAppDelegate.width, AppDelegate.sharedAppDelegate.height)];
self->_flowLayout = v;
}
return v;
}
- (PHCachingImageManager *)imageManager {
PHCachingImageManager *i = self->_imageManager;
if (!i) {
i = [[PHCachingImageManager alloc] init];
self->_imageManager = i;
}
return i;
}
- (PHFetchResult *)assetsFetchResults {
PHFetchResult *i = self->_assetsFetchResults;
if (!i) {
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumVideos options:nil];
PHAssetCollection *collection = smartAlbums.firstObject;
if (![collection isKindOfClass:[PHAssetCollection class]])
return nil;
PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
allPhotosOptions.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:NO]];
i = [PHAsset fetchAssetsInAssetCollection:collection options:allPhotosOptions];
self->_assetsFetchResults = i;
}
return i;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
#end
These are the only two files you need; no NIB/XIB.

viewDidUnload - stopping a method when the view is changed

I'm looking to stop an audio file from playing when the view is changed.
I'm using a tabController and I would like the audio that's playing to stop when the user moves to a different view. I'm not sure where and how I would do this. in the viewDidUnload perhaps?
here's the method I'm using to play the audio file:
-(void)startPlaying {
[NSTimer scheduledTimerWithTimeInterval:15 target:self selector:#selector(startPlaying) userInfo:nil repeats:NO];
NSString *audioSoundPath = [[ NSBundle mainBundle] pathForResource:#"audio_file" ofType:#"caf"];
CFURLRef audioURL = (CFURLRef) [NSURL fileURLWithPath:audioSoundPath];
AudioServicesCreateSystemSoundID(audioURL, &audioID);
AudioServicesPlaySystemSound(audioID);
}
thanks for any help
Something like this in your view controller (untested):
- (void)viewDidLoad
{
[super viewDidLoad];
// Load sample
NSString *audioSoundPath = [[NSBundle mainBundle] pathForResource:#"audio_file"
ofType:#"caf"];
CFURLRef audioURL = (CFURLRef)[NSURL fileURLWithPath:audioSoundPath];
AudioServicesCreateSystemSoundID(audioURL, &audioID)
}
- (void)viewDidUnload
{
// Dispose sample when view is unloaded
AudioServicesDisposeSystemSoundID(audioID);
[super viewDidUnload];
}
// Lets play when view is visible (could also be changed to viewWillAppear:)
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self startPlaying];
}
// Stop audio when view is gone (could also be changed to viewDidDisappear:)
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if([self.audioTimer isValid]) {
[self.audioTimer invalidate];
}
self.timer = nil;
}
// Start playing sound and reschedule in 15 seconds.
-(void)startPlaying
{
self.audioTimer = [NSTimer scheduledTimerWithTimeInterval:15 target:self
selector:#selector(startPlaying)
userInfo:nil
repeats:NO];
AudioServicesPlaySystemSound(audioID);
}
Missing:
Error checking
Property or ivar for audioTimer.
Could also keep the same timer, with repeats YES.
Freeing resources in dealloc.
Testing

Volume control in iPhone OS from another view controller?

If I am playing a sound in one view, does anyone know if it is possible to control the volume from another, if it is can someone explain how? I can't figure it out, I have no code to show for the volume.
The sound is called from one view and the volume slider is on another. I have coded both.
The code for the sound is
#import `<AVFoundation/AVAudioPlayer.h`>
#import "LeftViewController.h"
#implementation LeftViewController
- (IBAction)buttonrm:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)playl {
[theAudio play];
}
- (IBAction)pausel {
[theAudio pause];
}
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
NSString *path =[[NSBundle mainBundle] pathForResource:#"The Noisettes - Never Forget You" ofType:#"mp3"];
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
//[theAudio play];
[super viewDidLoad];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
the code for the slider is
- (void)viewDidLoad {
[super viewDidLoad];
CGRect sliderRect = CGRectMake(46,124,169,0);
UISlider *VolumeL = [[UISlider alloc] initWithFrame:sliderRect];
VolumeL.minimumValue = 0;
VolumeL.maximumValue = 100;
VolumeL.continuous = YES;
UIImage *sliderctrl = [UIImage imageNamed:#"VolumeL.png"];
//UIImage *stetchLeftTrack = [[UIImage imageNamed:#"volumel12.png"]
//stretchableImageWithLeftCapWidth:5.0 topCapHeight:0.0];
[VolumeL setThumbImage:sliderctrl forState:UIControlStateNormal];
//[VolumeL setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal];
[VolumeL addTarget:self action:#selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
VolumeL.transform = CGAffineTransformRotate(VolumeL.transform, 270.0/180*M_PI);
[self.view addSubview:VolumeL];
[VolumeL release];
}
Use the delegate pattern
In the second view controller create a protocol called MyProtocol for example with one method:
- (void)didUpdateVolume:(NSUInteger)volume;
Also create a delegate instance variable to hold the delegate reference
#property (nonatomic, assign) id<MyProtocol> delegate;
And don't forget to synthesize it in the implementation.
When the volume value is updated you would send the value to the delegate
[self.delegate didUpdateVolume:newValue];
Back in the first controller adopt the MyProtocol protocol, implement didUpdateVolume, and set the value in your player.
Try using the Notification center.
http://blog.grio.com/2009/04/broadcasting-information-how-to-use-the-iphone-notification-center.html