my goal is to call a function after background music ends in cocos2dx.
playing background music using this code
CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("shortSound.wav",false);
and need to call my Function
void GamePlay::gameLevelEnds()
when the background sound ends.
There are no direct interfaces to do in cocos2dx but you can just find the duration of sound file and run an action with delay of duration followed by callback function.
This is possible.
General Solution
float duration = 10.0f;
CCSequence *soundSequence = CCSequence::create(CCDelayTime::create(duration),CCCallFunc::create(this, callfunc_selector(GamePlay::soundEndedAction)),NULL);
this->runAction(soundSequence);
method to monitor sound end action
void GamePlay::soundEndedAction(){
CCLOG("+++sound ended+++%s",__PRETTY_FUNCTION__);
}
//======== For only iOS Platform below solution can be applied.=====//
I created a method in "AppController.h"
-(void)backgroundFinished;
and in "AppController.mm"
-(void)backgroundFinished
{
NSLog(#"+++Music ended....+++");
CocosDenshion::SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();
}
and added below lines in init method of "SimpleAudioEngine_objc.m" file
-(id) init
{
if((self=[super init])) {
am = [CDAudioManager sharedManager];
//=======added this line=========//
[am setBackgroundMusicCompletionListener:[[UIApplication sharedApplication]delegate] selector:#selector(backgroundFinished)];//28 Aug 2014
//===============================//
soundEngine = am.soundEngine;
bufferManager = [[CDBufferManager alloc] initWithEngine:soundEngine];
mute_ = NO;
enabled_ = YES;
}
return self;
}
now in my "GamePlay.cpp" class I scheduled update method
void GamePlay::update(float dt)
{
if(!CocosDenshion::SimpleAudioEngine::sharedEngine()->isBackgroundMusicPlaying())
{
CCLOG("+++Background Music Ended+++ :%d",CocosDenshion::SimpleAudioEngine::sharedEngine()->isBackgroundMusicPlaying());
//Take neccessory actions
}
}
Related
I use ZXing for an app, this is mainly the same code than the ZXing original code except that I allow to scan several time in a row (ie., the ZXingWidgetController is not necesseraly dismissed as soon as something is detected).
I experience a long long freeze (sometimes it never ends) when I press the dismiss button that call
- (void)cancelled {
// if (!self.isStatusBarHidden) {
// [[UIApplication sharedApplication] setStatusBarHidden:NO];
// }
[self stopCapture];
wasCancelled = YES;
if (delegate != nil) {
[delegate zxingControllerDidCancel:self];
}
}
with
- (void)stopCapture {
decoding = NO;
#if HAS_AVFF
if([captureSession isRunning])[captureSession stopRunning];
AVCaptureInput* input = [captureSession.inputs objectAtIndex:0];
[captureSession removeInput:input];
AVCaptureVideoDataOutput* output = (AVCaptureVideoDataOutput*)[captureSession.outputs objectAtIndex:0];
[captureSession removeOutput:output];
[self.prevLayer removeFromSuperlayer];
/*
// heebee jeebees here ... is iOS still writing into the layer?
if (self.prevLayer) {
layer.session = nil;
AVCaptureVideoPreviewLayer* layer = prevLayer;
[self.prevLayer retain];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 12000000000), dispatch_get_main_queue(), ^{
[layer release];
});
}
*/
self.prevLayer = nil;
self.captureSession = nil;
#endif
}
(please notice that the dismissModalViewController that remove the view is within the delegate method)
I experience the freeze only while dismissing only if I made several scans in a row, and only with an iPhone 4 (no freeze with a 4S)
Any idea ?
Cheers
Rom
According to the AV Cam View Controller Example calling startRunning or stopRunning does not return until the session completes the requested operation. Since you are sending these messages to the session on the main thread, it freezes all the UI until the requested operation completes. What I would recommend is that you wrap your calls in an Asynchronous dispatch so that the view does not lock-up.
- (void)cancelled
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self stopCapture];
});
//You might want to think about putting the following in another method
//and calling it when the stop capture method finishes
wasCancelled = YES;
if (delegate != nil) {
[delegate zxingControllerDidCancel:self];
}
}
In my app I am using AudioStreamer to play a song through server,
I am refering this tutorial,
http://cocoawithlove.com/2008/09/streaming-and-playing-live-mp3-stream.html
How to play next song Automatically when using AudioStreamer?
In the tutorial is mentioned callback function which is triggered when a song finish playing. Your goal is to write functionality for your list of songs to move on the next one when this function is called.
void MyAudioQueueIsRunningCallback( void * inClientData,
AudioSessionPropertyID inID,
UInt32 inDataSize,
const void * inData)
{
move to the next song
}
I got answer,
In that tutorial there isplaybackStateChanged:(NSNotification *)aNotification method,
- (void)playbackStateChanged:(NSNotification *)aNotification
{
if ([songStreamer isWaiting])
{
}
if ([songStreamer isPlaying])
{
}
else if ([songStreamer isIdle])
{
[self playnextsong];
}
else if ([songStreamer isPaused])
{
}
}
When song completes through streaming,
It going to idle state.
So in idle state i call a method of playing next song.
And it Runs.
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 am creating a music player application and it need that 2 actions to be called from a single button, one to skip to next track by touch up inside event and other to fast forward the curenttrack incase of a 'long press'. I don't know which event is pointing to this long press, i thought it to be touch down, but it worked only while holding the button. When i released the button, the track was skipped to next item. pls help
AVAudioPlayer *appSoundPlayer;// declared in .h file
In m file, the method:
-(void)seekForwards{
NSTimeInterval timex;
timex = appSoundPlayer.currentTime;
timex = timex+5; // forward 5 secs
appSoundPlayer.currentTime = timex;
timex = 0;
}
Personally I'd just track the button's state with an integer on your view controller or within a button subclass. If you track what the button is doing you can control what each of the actions do. In your .h file put in some stuff like this:
enum {
MyButtonScanning,
MyButtonStalling,
MyButtonIdle
};
#interface YourClass : UIViewController {
NSInteger buttonModeAt;
}
#property (nonatomic) NSInteger buttonModeAt;
-(IBAction)buttonPushedDown:(id)sender;
-(void)tryScanForward:(id)sender;
-(IBAction)buttonReleasedOutside:(id)sender;
-(IBAction)buttonReleasedInside:(id)sender;
#end
And then in your .m file throw in some of this stuff:
#implementation YourClass
///in your .m file
#synthesize buttonModeAt;
///link this to your button's touch down
-(IBAction)buttonPushedDown:(id)sender {
buttonModeAt = MyButtonStalling;
[self performSelector:#selector(tryScanForward:) withObject:nil afterDelay:1.0];
}
-(void)tryScanForward:(id)sender {
if (buttonModeAt == MyButtonStalling) {
///the button was not released so let's start scanning
buttonModeAt = MyButtonScanning;
////your actual scanning code or a call to it can go here
[self startScanForward];
}
}
////you will link this to the button's touch up outside
-(IBAction)buttonReleasedOutside:(id)sender {
if (buttonModeAt == MyButtonScanning) {
///they released the button and stopped scanning forward
[self stopScanForward];
} else if (buttonModeAt == MyButtonStalling) {
///they released the button before the delay period finished
///but it was outside, so we do nothing
}
self.buttonModeAt = MyButtonIdle;
}
////you will link this to the button's touch up inside
-(IBAction)buttonReleasedInside:(id)sender {
if (buttonModeAt == MyButtonScanning) {
///they released the button and stopped scanning forward
[self stopScanForward];
} else if (buttonModeAt == MyButtonStalling) {
///they released the button before the delay period finished so we skip forward
[self skipForward];
}
self.buttonModeAt = MyButtonIdle;
}
After that just link the button's actions to what I've noted in the comments before the IBactions. I haven't tested this but it should work.
you can subclass your button's class and play a bit around UIResponder's methods. For example, in touchesBegan method you can fire some timer and call method which will move throw your file and invalidate this timer in the toucesEnded method
I am currently using the cocos2d Director for controlling my animation with the pause, resume, and stopAnimation methods. Is it also possible to use the Director to return the time that the animation has played?
I am currently using this method:
-(void)stopAnimation:(id)sender {
//Timer initialized elsewhere: startTimer = [NSDate timeIntervalSinceReferenceDate];
//Do other method stuff here
[[Director sharedDirector] stopAnimation];
stopTimer = [NSDate timeIntervalSinceReferenceDate];
elapsedTime = (stopTimer - startTimer);
NSLog(#"elapsedTime = %f", elapsedTime);
}
I looked through the Director source and didn't see anything that would help you. I did notice that your code, as written, doesn't take into account the time your animation was paused or when other scenes were playing.
If that is a concern you can keep track of the elapsed time in a tick method that you schedule in your Scene or Layer.
MyLayer.h
#interface MyLayer : Layer {
ccTime totalTime;
}
#property (nonatomic, assign) ccTime totalTime;
MyLayer.m
-(id)init
{
if( (self = [super init]) )
{
[self schedule:#selector(update:)];
}
return self;
}
// deltaTime is the amount of running time that has passed
// since the last time update was called
// Will only be called when the director is not paused
// and when it is part of the active scene
-(void)update:(ccTime)deltaTime
{
totalTime += deltaTime;
}