In my project I am using an AVAudioPlayer to play my saved audio.I am showing the slider for playing audio. The value of the slider is set using the current time property of the player.
playSlider.value = avAudioPlayer.currentTime;
This is the timer code
updateTimer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:#selector(updateCurrentTime) userInfo:p repeats:YES];
//Calls the update current time function
- (void)updateCurrentTime
{
[self updateCurrentTimeForPlayer:self.player];
}
//Updates the current time while the audio is playing
-(void)updateCurrentTimeForPlayer:(AVAudioPlayer *)avAudioPlayer
{
currentTimeLabel.text = [NSString stringWithFormat:#"%d:%02d", (int)avAudioPlayer.currentTime / 60, (int)avAudioPlayer.currentTime % 60, nil];
playSlider.value = avAudioPlayer.currentTime;
if (playSlider.value==playSlider.minimumValue)
{
moveToBeginningButton.enabled = NO;
rewindButton.enabled = NO;
NSLog(#"PlaySliderMaxValue1 === %f",playSlider.maximumValue);
NSLog(#"PlaySliderValue1 === %f",playSlider.value);
}
else
{
moveToBeginningButton.enabled = YES;
rewindButton.enabled = YES;
NSLog(#"PlaySliderMaxValue2 === %f",playSlider.maximumValue);
NSLog(#"PlaySliderValue2 === %f",playSlider.value);
}
}
The maximum value of slider is set as follows
playSlider.maximumValue = audioPlayer.duration;
The problem that I am experiencing is that the slider point will always return to the beginning of the audio after playing.Is this a bug? How can I change this? Please provide your suggestion.
I cannot say whether this is a bug or not, But try using delegate methods of AVAudioPlayer. In didFinishPlaying method set Slider value to maximumValue. This could be one of the solution.
Print the value of avAudioPlayer.currentTime before assigning it to playslider.value
I think at the end it will become zero. and it will assign zero to playslider.value
Related
I am making a game with a boost button. Of course, just leaving it as enabled would allow the player to tap it constantly. So, I need a 20 second delay before it is possible to push the button again. Also, would it be possible to show this progression on the button, preferably on the button itself?
In the future please try to show what you have tried to solve your problem. However, since you are new I'm going to let it slide once!
This code uses a NSTimer that is called once per second. It will fire what ever code you specify for "Boost". It will also disable user interaction on your button until it has been 20 seconds from when the button was pressed at which point it will allow the user to press the button again, and finally, this code displays how many seconds remain until "Boost" can be used again on the titleLabel property of your button.
- (IBAction)buttonPressed:(id)sender
{
myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(activateBoost) userInfo:nil repeats:YES];
}
- (void)activateBoost
{
if (myButton.userInteractionEnabled == YES) {
//Put your Boost code here!
}
if ([myButton.titleLabel.text intValue] == 0) {
[myTimer invalidate];
[myButton setTitle:#"20" forState:UIControlStateNormal];
myButton.userInteractionEnabled = YES;
}else{
myButton.userInteractionEnabled = NO;
int currentTime = [myButton.titleLabel.text intValue];
int newTime = currentTime - 1;
myButton.titleLabel.text = [NSString stringWithFormat:#"%d",newTime];
}
}
In order for the above code to work, you will need the declare a NSTimer named "myTimer" and a UIButton "myButton". You will also need to set the buttons initial text to "20".
I'm implementing a UISlider that allows users to select a position on a football field. The idea of the slider is for the field to scroll forward when the slider value is above a certain value (the section with the arrow).
My issue is that I can only respond to the slider on UIControlEventValueChanged - so the field will only scroll forward when the user is actually moving the slider. I'd like it to move forward as long as the value is above a certain amount.
Any idea how I can do this? (I'm open to any suggestion, including an implementation that does not use a UISlider, composite implementations, etc.).
Here's the implementation:
The easiest way to handle this is with a timer. Add an NSTimer instance variable to your class, named—for the sake of the example below—moveTimer, then set up something like this:
- (void)sliderChanged:(UISlider *)slider
{
if(slider.value > 5)
{
if(moveTimer == nil)
{
moveTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self action:#selector(move) repeats:YES];
}
}
else
{
if(moveTimer != nil)
{
[moveTimer invalidate];
moveTimer = nil;
}
}
}
- (void)move
{
// update the background behind your slider
}
I found a solution that works for me:
[self performSelector:#selector(sliderMoved) withObject:nil afterDelay:0.5];
I call the sliderMoved method after every 0.5 seconds when slider.value > 0.5.
Try setting the continuous property of the slider to YES.
I'm using AVPlayer for play my video using slider and Some Buttons.
Here is my methods for moving forward and backward using buttons.
-(IBAction)MoveForward
{
//int value = timeSlider.value*36000 + 10;
//CMTime newTime = CMTimeMakeWithSeconds(value, playspeed);
//CMTime newTime = CMTimeMake(value,(playspeed*timeSlider.maximumValue));
CMTime newTime = CMTimeMakeWithSeconds(timeSlider.value, playspeed);
newTime.value += 60;
[player seekToTime: newTime];
}
-(IBAction)MoveBackward
{
CMTime newTime = CMTimeMakeWithSeconds(timeSlider.value-1, playspeed);
[player seekToTime: newTime];
}
My Problem on this is the time to Seek is not working properly. That navigate to next frame based on seconds. I need to move next frame minutely. Help me...
I don't really understand your code, you don't really need separate methods to move forwards and backwards, you can use the same one for both. I've got a working AVPlayer Movie Player, I'll show you how I did the slider part.
-(IBAction)sliding:(id)sender {
CMTime newTime = CMTimeMakeWithSeconds(seeker.value, 1);
[self.player seekToTime:newTime];
}
-(void)setSlider {
sliderTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateSlider) userInfo:nil repeats:YES] retain];
self.seeker.maximumValue = [self durationInSeconds];
[seeker addTarget:self action:#selector(sliding:) forControlEvents:UIControlEventValueChanged];
seeker.minimumValue = 0.0;
seeker.continuous = YES;
}
- (void)updateSlider {
self.seeker.maximumValue = [self durationInSeconds];
self.seeker.value = [self currentTimeInSeconds];
}
- (Float64)durationInSeconds {
Float64 dur = CMTimeGetSeconds(duration);
return dur;
}
- (Float64)currentTimeInSeconds {
Float64 dur = CMTimeGetSeconds([self.player currentTime]);
return dur;
}
And that's it, there are two gotchas in this code, first, the duration property returns a CMTime variable, you have to convert it to a float, also, this returns the raw number of seconds, you have to convert it to h:mm:ss if you want to display time labels. Second, the updateSlider method is triggered by a timer every second.
Good Luck.
The following snippet of code worked for me:
CMTime videoLength = self.mPlayer.currentItem.asset.duration; // Gets the video duration
float videoLengthInSeconds = videoLength.value/videoLength.timescale; // Transfers the CMTime duration into seconds
[self.mPlayer seekToTime:CMTimeMakeWithSeconds(videoLengthInSeconds * [slider value], 1)
completionHandler:^(BOOL finished)
{
dispatch_async(dispatch_get_main_queue(), ^{
isSeeking = NO;
// Do some stuff
});
}];
I am facing a strange issue with videoMaximumDuration property in Video recorder API. I am trying to fix this issue more than a week, but couldn't. I posted in several forums, but no help yet.
I am using the following code to launch Camera from my application and start recording the video. As per my requirement, i should set the time duration for recording the video to stop. So, i use "videoMaximumDuration" property to set the time duration for recording the video.
if ([types containsObject:(id)kUTTypeMovie])
{
appDelegate.pickerController = [[UIImagePickerController alloc] init];
appDelegate.pickerController.delegate = self;
appDelegate.pickerController.videoQuality = setVideoQuality;
appDelegate.pickerController.allowsEditing = NO;
appDelegate.pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
appDelegate.pickerController.showsCameraControls = YES;
appDelegate.pickerController.navigationBarHidden = YES;
appDelegate.pickerController.toolbarHidden = YES;
appDelegate.pickerController.wantsFullScreenLayout = YES;
appDelegate.pickerController.cameraViewTransform =
CGAffineTransformScale(appDelegate.pickerController.cameraViewTransform,
CAMERA_TRANSFORM_X,
CAMERA_TRANSFORM_Y);
appDelegate.pickerController.mediaTypes = [NSArray arrayWithObject:(id)kUTTypeMovie];
appDelegate.pickerController.videoMaximumDuration = maxDuration;
[self presentModalViewController:appDelegate.pickerController animated:YES];
}
Here is the issue:
If if i set videoQuality as UIImagePickerControllerQualityTypeHigh, then the time duration(videoMaximumDuration) works as expected, i.e exactly after the time duration it stops recording the video automatically. If i go and see that recorded video in Photo album to make sure that, it is recorded well as per the time.
If i change the videoQuality to UIImagePickerControllerQualityTypeMedium (or) UIImagePickerControllerQualityTypeLow like that, then the time duration(videoMaximumDuration) for video recording is not working as expected,
i.e. it is able to automatically stop the video recording at the time duration set, no issues, But if i go and see that recorded video in Photo album to make sure, it is NOT as per the time taken, rather i can see the smaller video than what i recorded. For example, if i set the videoMaximumDuration for 30 seconds, after recording the video, if i go and see that recorded video in Photo album, it could able to record= only unto 22 seconds. Seems to be issue with the API itself. This is not happening when i use video quality as UIImagePickerControllerQualityTypeHigh.
I tried even using Custom overlay view and do start and stop recording video through code like below by setting timer(NStimer). But still i see the same issue has observed.
overlay = [[OverlayView alloc]initWithFrame:CGRectMake(0, 0, 768, 1024)];
if ([types containsObject:(id)kUTTypeMovie])
{
appDelegate.pickerController = [[UIImagePickerController alloc] init];
appDelegate.pickerController.delegate = self;
appDelegate.pickerController.videoQuality = setVideoQuality;
appDelegate.pickerController.allowsEditing = NO;
appDelegate.pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
appDelegate.pickerController.showsCameraControls = NO;
appDelegate.pickerController.navigationBarHidden = YES;
appDelegate.pickerController.toolbarHidden = YES;
appDelegate.pickerController.wantsFullScreenLayout = YES;
appDelegate.mTimerSelectionForVideo = maxDuration; // TIME SET HERE IN VARIABLE
appDelegate.pickerController.cameraViewTransform =
CGAffineTransformScale(appDelegate.pickerController.cameraViewTransform,
CAMERA_TRANSFORM_X,
CAMERA_TRANSFORM_Y);
appDelegate.pickerController.mediaTypes = [NSArray arrayWithObject:(id)kUTTypeMovie];
appDelegate.pickerController.videoMaximumDuration = maxDuration;
[self presentModalViewController:appDelegate.pickerController animated:YES];
appDelegate.pickerController.cameraOverlayView =overlay;
}
OverlayView.m
-(void)startAction:(id)sender
{
BOOL bStop = TRUE;
void (^hideControls)(void);
hideControls = ^(void) {
cameraSelectionButton.alpha = 0;
startButton.enabled = NO;
lbl.hidden = NO;
};
void (^recordMovie)(BOOL finished);
recordMovie = ^(BOOL finished) {
stopButton.enabled = YES;
[appDelegate.pickerController startVideoCapture];
};
// Hide controls
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:hideControls completion:recordMovie];
if ( appDelegate.mTimerSelectionForVideo==0 )
{
bStop = FALSE;
}
if ( bStop )
timer = [NSTimer scheduledTimerWithTimeInterval:(appDelegate.mTimerSelectionForVideo)+1
target:self selector:#selector(stopCamera:) userInfo:nil repeats:NO];
}
- (void)stopCamera:(NSTimer *)theTimer
{
startButton.enabled = YES;
if ( timer )
{
[timer invalidate];
timer = nil;
}
[appDelegate.pickerController stopVideoCapture];
[appDelegate.pickerController dismissModalViewControllerAnimated:YES];
}
But still i see the same issue observed. Why does other video quality settings not working as per the videoMaximumDuration set?
I tested on iPhone 4.1 and iPad 4.3, the same issue has been observed. Looks like, issue with the API or video recorder hardware itself to support it.
Could someone please guild me to fix this issue if there is any possibility (or) through your experience?
Thank you in Advance!
Fixed it by creating an overlay view on top of the camera view and handle start/stop thru code.
I have an int which defines the objectAtIndex, which gives it to the string, which then displays it in the UILabel, HOWEVER, when I modify the array (add a word to it in this case) when I have the UILabel go through the array it only displays the odd ones. I have done an NSLog and found out that it DOES PASS EVERY SINGLE THING to the string, but the Label isn't displaying every single one, it only does it the first time, then I modify the array, and it only does odd
edit: the code:
- (void) stuff {
NSArray *indivwords = [sentence componentsSeparatedByString:#" "];
count = [indivwords count]; //count=int
if (i < count) {
NSString *chunk = [indivwords objectAtIndex:i];
[word setText:chunk];
NSLog(chunk);
i++;
} else {
word.textColor = [UIColor greenColor];
[word setText:#"DONE"];
}
}
All of this is being controlled by an NSTimer, which sets it off based on a slider value. Also i is set to 0 in the IBAction
The IBAction code:
word.textColor = [UIColor whiteColor];
[timer invalidate];
i = 0;
speedd = (1/speed.value)*60;
timer = [NSTimer scheduledTimerWithTimeInterval:(speedd) target:self selector:#selector(stuff) userInfo:nil repeats:YES];
EDIT:
I fixed it! What I did was call this after i reached the count
-(void)stoptimer
{
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval:(.01) target:self selector:#selector(empty) userInfo:nil repeats:YES];
}
empty is just a void with nothing in it, well, all I did was add a comment,
//don't look over here, nothing to see here, oh look at that
Somebody can close this if they want
You said the time interval of your NSTimer is controlled by a slider. Perhaps you are starting a new timer instance every time you change the slider value, so after a change you would have two timers running. The first one updates the label and increments i. The second one comes right after the first and finds i's value incremented, so it displays the next chunk instead of the current one.
Count the instances of your timer - NSLog the timer in the timer callback and compare the results - it may be that you're firing more than one.
My guess is that you have two different actions calling this method, when you think there should be one. I'd put a break point in there, and see if it stops where you think it should.