XNA Mediaplayer.Play() starts playing at different times across computers? - xna

I'm trying to develop a rhythm game in Monogame. The notes are frame rate independent and work consistently over different computers, but the song playing does not. Right now I have it hooked up so the notes spawn and MediaPlayer.Play() do not start until I hit a key (so it's outside of loadcontent/initialize like I've seen other solutions suggest). The song does not start playing until I hit the "I" key (gets checked in Update). However, the song seems to start playing at different times across different devices. I pull down the project on both my laptop (on battery) and desktop, and hit the "I" key at the same time on both, and I get different results on my laptop. Sometimes it'll be seconds ahead of the desktop, other times it'll be a second or two behind (this is usually the case). It seems pretty consistent on desktop. I'd try more than a dozen times and everything is still synced, but not on my laptop. I'm worried this is something that works only on my PC but not on others.
I've tried enabling fixedTimeStep and setting FPS to 60 (and setting the TargetElapsedTime to the window title ensuring that they are indeed both hitting 60) and I still get inconsistent results. I've read from other answers about using PlayPosition from the MediaPlayer class, but that property is readonly so I'm not quite how I could use that.
At first, I thought my notes were simply dependent on frame rate, but after setting FPS and fixedTimeStep, and also holding my laptop up to my desktop monitor they match up perfectly. It's just the song not syncing up. I'm still a newbie to XNA but I couldn't find anyone else reporting different song starting timings like this. Any help would be greatly appreciated.

I thought of a solution the second I got out of bed the next morning. I figured there must be some overhead on MediaPlayer.Play(), but I wondered if I could start it, pause it, then resume instead. Turns out, there is a Pause() and Resume() method which is what what missing from making this work.
So! If anyone else out there is having similar issues, here's what I did. I kept a key to activate MediaPlayer.Play(), but immediately added MediaPlayer.Pause() after. Then I got another key to resume the song, and the notes spawned when the song was resumed. So pressing "I" played the song and paused it immediately. Pressing "R" resumed the song and started spawning the notes.

Related

GameKit Turn-based listener is not reliably called when matchData changes

I am using Game Center turn-based matches for my card game. It feels like a good fit because people want to check their email or write a text sometimes between turns. Some users have said that they do really want to be able to have a very asynchronous playing experience.
For the people that are keeping the game open between their turns, I want to update the screen to reflect things that the other players are doing on their turns. I have set up a listener on GKLocalPlayer that responds to player:receivedTurnEventForMatch:didBecomeActive. The documentation says that this will get called when match data is saved by another player even if it doesn't become the player's turn (the player on the current device). That doesn't appear to be true 100% of the time. In fact, it appears that it only gets called about 1 in 3 times that match data is saved by other players. It seems more reliable when it becomes the player's turn, but even that isn't 100% reliable.
I am using saveCurrentTurnWithMatchData:completionHandler: on GKTurnBasedMatch to save match data that doesn't end the current player's turn and I'm calling endTurnWithNextParticipants:turnTimeout:matchData:completionHandler: on GKTurnBasedMatch to save the data when it does end the current player's turn. There are a few scenarios where I want to call saveCurrentTurn… with updated matchData. In my game, you can have computers playing in your multiplayer game as well. So, a human player may play a card and then a computer may play a card before that GKPlayer's turn ends. There are also scenarios where an individual player may play twice. (eg. A player plays the last card on a trick. That player takes the trick and gets to lead the next trick.)
I have set up a ton of logging around this and I can see clear scenarios where one device calls saveCurrentTurn… and the completionHandler is called without an error and the other device doesn't get notified with a call to player:receivedTurnEvent… I have also added logging to verify that each time I'm calling saveCurrentTurn… that I'm calling it with new matchData. I'm not making redundant calls.
If I go to the device that didn't get the updated matchData and force it to load the matchData for the match again, it gets the updated data. So, it's definitely getting saved.
I have tried throttling the calls to saveCurrentTurn… so that they don't happen in immediate succession and that didn't help.
Both devices in my testing are running iOS 8.4. There appears to have been an issue in iOS 8.3 that is fixed now (see this question). This Apple forum post also reports this issue 2 years ago and it appears that bug reports were filed and marked fixed.
Has anyone else seen this? I would love to know that I'm doing something wrong. Any ideas are very welcome.
I do something similar. In my game, each player has multiple pieces, saving the match when each piece moves so that other players--if they're in the game--can watch what's happening in real time. Like you describe, the Game Center messaging is almost completely useless.
As you referenced, in 8.3, the "end of turn" messages were completely broken. As of 8.4, they happen most, but not all, of the time. As you're seeing, the "match has been saved" notifications are also erratic. Here are some tips I've used to increase the success rate:
Slow down the saves. If you save too fast, only the last one arrives at the recipient. I set up an NSArray queue, and each time I want to save the match, I add the new matchData to that queue. I have a timer loop running that does the actual saveCurrentTurnWithMatchData, pops the item off the stack if the save was successful, and then sets up a new timer to call itself again a little later. I'm using 2 second intervals which seems to be working well.
Append each new piece of data, don't overwrite. Put a sequence number on each piece of data. So, if you save seq numbers 1, 2, 3 and 4, but the recipient only receives a notice for #4, the records for 1, 2 and 3 are there in the match object. The recipient needs to track the last record it read, and then iterate through any new records from that point when it receives an updated matchData.
I also use the queue's NSArray writeToFile: function to maintain a list of the pending saves. If the user exits the game before the queue is flushed, I reload the queue NSArray from disk at the next startup
Note that even with this mechanism, the notifications to the recipient are erratic. Generally speaking, they arrive in batches of 4+. Then nothing happens until 3 or 4 more saves happen, which again all show up together. Making 1 save and letting the game sit for 10 minutes will probably never generate a notice on the recipient's machine. But, if you save 4 or 6 times in a row, all of them tend to show up in a burst.
Sometimes, the notifications just stop for a few hours. Not sure if this a sandbox flaw or a game-center-in-general flaw. There are no failures of any kind, the messages just stop working for a while. Sometimes, the next morning, they show up in a burst. Sometimes not. In the end, I've stopped relying on the notifications. I set up another timer loop to continuously download the match. It checks if it has become my turn or not, it checks if new updates have been added to the matchData. Then calls player:receivedTurnEventForMatch:didBecomeActive. As far a receivedTurnEventForMatch: knows, it was launched because of an event and it merrily goes on about its business.
It does seem that saving the match is pretty prompt. If you don't get an error, it seems pretty certain that the updated match is immediately available for other players to consume... they just need to know to consume it. The messaging framework, though, has to be viewed as completely unreliable and non-guaranteed. Hence, the timer loop to continuously poll the match.
Edit: arguably, once I implemented #2, #1 shouldn't really matter. Any notification received by the recipient will trigger reading all new records in the data. But, this "hardening" has evolved over the past few months as I wrestle with Game Center's shortcomings. I just haven't gotten around to removing #1.

PIC32 becomes unresponsive after a few hours

I have a PIC32MX340F512 board developed by another company for us, The board has a DS1338 RTCC and 24LC32A eeprom, and display unit on an I2C bus, on this bus i included a TSL2561 I2C light sensor, i wrote code in c to poll the light sensor continously , when the light sensor reaches a certain level i save the time and date and light sensor value on SD card. This all works fine but if i leave the system without exposure to light inside tunnel where incident light on one end of the tunnel is ought to be monitored the system becomes unresponsive no matter how much amount of light you apply and then if i switch power off and back on again everything starts to work normal. i am a one man development team and have been trying to find out the problem for months, i activated the watchdog timer to prevent the system from hanging but the problem still persisted. i then decided to find out if the problem is with the sensor by including a push button to activate light measurement but still when 4-5 hours elapse the PIC cant even detect a change in the the input pin. Under the impression that a hardware reset overrides anything going on i included a reset button and it also works ok for the first few hours after that the PIC doesn't seem to be responding to anything including a reset. I was getting convinced that there is nothing wrong with the firmware but also with all this happening the display unit (pic16f1933 and lcd) on the I2C shares power with the main unit and doesn't seem to be affected as it alternates between different messages constantly Does anybody have an idea what could be wrong (hardware/firmware or my sensor). I am using a 24v DC power supply purchased seperately. The PIC seems to go into a deep sleep although i dd not implement any kind of SLEEP mode in my code. Nb We use the same board for many other projects and i haven't come across such a problem . Thanks in advance.
I think you need to (if you haven't already) explore the wonderful world of in-circuit-debugging (such as with the ICD3 or PICkit 2/3). It allows you to run the processor in a special mode that lets you pause execution, see exactly which line of code is being executed, inspect variable values, and step through the code to see which parts are running and not running, or see exactly where execution takes a wrong turn. If the problem takes hours to reproduce, that's okay. You can just leave it overnight running in debug mode and hopefully it will be locked-up or 'sleeping' in the morning. At this point, you will be able to pause the processor and poke around to see if you got caught in some kind of infinite loop or something. This is often the only way to dig inside a running piece of code to see why things aren't working as you expect. But as you say, those bugs that take hours or days to manifest are the trickiest. Good luck!
It sounds like you can break up your design into two main parts, sd card interfacing, reading the rtc and reading the light sensor. If it were me I would upload a version of the code that mimics reading the light sensor but only returns fake data and see if that cures the problem. Additionally do the same with the other two modules separately and see if any of the three versions of your project not show this problem. From there just keep narrowing it down until you find the block of code thats causing problems.
if Two or more versions of your debug code show the same problem then my guess is it has to do with one of the communication protocols. I had a problem with a Pic32 silicon version blocking when using the DMA in conjunction with the SPI peripherals. So I would suggest checking the errata for your chip.
If you still cant find the problem, my only suggestion would be to check for memory leaks or arrays that are growing into reserved memory.
Hope that helps, good luck!

ios game gets out of sync while analysing process in Instruments - how can I avoid that?

I am building an iOS game and I notice that the game performs fine while running normally in the XCode debugger. However, when i run it from within Instruments (Product-> Profile to trace Leaks), the game freezes when Instruments displays 'Analyzing Process' in the left sidebar. After that the game messes up all its state since some parts of the game that were being analyzed froze up while other parts kept going.
Is this something I can/need to fix or is it sufficient to make sure the game runs in release?
If a fix is needed, what do I need to do to make it work?
Update 1:
So we found the issue - the same problem repros even if we are playing the game, press the home button and click on the game icon and continue playing.
The issue is that most of our work is done in the update method, and it relies on the value of the (ccTime)dt parameter. The value of dt is usually < 0.1 seconds, and occasionally somewhere upto 0.5 seconds).When we pause (either by clicking the home button, or when instruments pauses the game to take a snapshot) and resume playing, the value of dt is several seconds! And that throws all our calculations out of range.
We tried a temporary (but ugly) workaround that fixes the issue: at the beginning of the update method, we add this:
if(dt > 1)
return;
And it now works as expected - doesn't go out of sync. However, this is not a permanent solution, since sometimes, the values of dt are legitimately close to 1 second, and in resource crunched situations, this may lead to stutter (or worse).
We also considered another (equally ugly) solution of storing the previous value of dt, and then check in the update method:
if(dt > 10 * prevDt)
{
return;
}
We tried calling unscheduleUpdate in AppDelegate.m's applicationDidEnterBackground, and called scheduleUpdate in the applicationWillEnterForeground method, but that approach did not work.
What is the best way to deal with updates with erratic time values due to external pauses?
Thanks
Anand
I don't know much about how cocos2D works, but if you've run out of options, I would simply clamp the delta time to an upper range. In whatever update methods used delta time, I would do the following.
double delta = (dt > 0.5) : (0.5) ? (dt);
Use delta instead of dt from that point onward. The result is that any frame with a delta of over half a second will be limited to a delta of half a second. You don't want to skip frames, because then you could potentially skip many frames in a row which would be bad for the user; they'd probably think the app crashed or something. However, you don't want to run a frame with a large delta because then delta-dependent objects and forces will get multiplied many times for that frame, preventing you from catching collisions and stuff. So, we prevent the game from getting completely screwed over while not skipping frames by simply clamping the value downwards.
The negative is that the app will appear to move more slowly when your frame rate drops to 2 frames per second. You lose the benefit of a time-based update method, which is the ability to always make the game appear to run at a well defined speed, when the engine is overburdened.
To be honest, if you ever run at 2 frames per second for an extended period of time, you've got bigger problems to worry about. I don't think the user will notice if objects move slightly more slowly per second if the game is only rendering once every who-knows-when anyways.
Unfortunately this is a problem, for which there is no sure answer; at least not without access to your system to run a whole variety of checks.
The failure in the profile may be because your game is running tight loops the timing of which get's upset in unpredictable ways and your game is crashing due to timing or resource issues (where those timing issues don't crop up with the debugger in the same way). If that's the case, there is probably not much you can do about it. Or it may be because there is a problem in your code. The problem is it can be very difficult to figure out which of these is the case. It's probably best to assume the problem is in your code though and do some further investigation.
The first thing to do, if you haven't done it already, is run the static analysis tool (Analyse from the Product menu in Xcode). Consider each of the raised errors carefully, and work to remove all of them. Sometimes they might seem obvious and you think you can ignore them, but some prodding reveals they are a symptom of a deeper problem.
If you haven't tried already, try running the instrument to check for zombies. There's a high chance this will fail also if the allocation instrument is failing, but if there are some stale references to de-allocated objects hanging around they could be causing the problem you are experiencing. Another instrument you can try is the performance analyser, to check where your app is spending most of it's time. There may be some really significant problem with the overallocation of resources you are not aware of. If you can't run the memory profiler, it will be difficult for you to see if this is the case, but using the performance analyser, it might be possible to see if your app is getting hung up for too long somewhere it shouldn't be.
Lastly - if all else fails and this may be a sledgehammer to crack a nut - and also may not in any case provide the solution. If you aren't using ARC, consider how long it would take to convert your app to using it (definitely create a branch first before doing it though). The Apple algorithms for object allocation/deallocation are very efficient and there is a very good chance if you have subtle memory management errors, they will be eliminated by Automatic Reference Counting.

how to use GANTracker for long running iOS apps, including background audio

My App is typically run overnight as a baby monitor, either as foreground app, or with background audio running.
Goals:
Track total app startups ie. active user count.
Track total usage time in foreground vs background and total session time.
Track various page-views if they navigate the settings screens.
As recommended, I start the tracker in didFinishLaunchingWithOptions, and track my first ViewController as my first 'page-view'. My App might stay on this page then for the next 8 hours...
A couple of issues then appear:
When do I call stopTracker and what does it do? I'm hoping that it terminates the tracking session. But since google kindly hid their code in a static lib, I have no idea what's going on under the covers, and the .h doesn't say much. First instinct is to put stopTracker in applicationWillResignActive however, if the user decides to enable background audio my app is still running...
Next I read that a session can timeout after 30mins with no new pageviews, or at midnight. I could set a repeating timer to send the same page-view every 20mins, that should keep my session alive, at least until midnight, but then my page views are going to be much larger? unless it's smart enough to know I'm on the same page with every call. google analytics blog
[Update: each call seems to be counted as a new pageview, and numbers are thus skewed, so still an issue how to handle this]
If my timer above runs past midnight and the session has expired, I'm going to end up with a new session and double the actual active user count?
If I do call stopTracker in applicationWillResignActive, will the next call to track a page-view restart the tracker? or do I need to call startTrackerWithAccountID again?
If instead I start the tracker in applicationDidBecomeActive, I lose the session that might have been running in the background.
[update: this seems to be the best approach so far, but testing is very slow due to time lag on analytics reports, I will report back soon]
PS EasyTracker doesn't seem to handle this any better.
I got this working by using a pageview called 'Backgrounded', and when the user has selected no background functionality, then instead the app is calling stopTracker. I see multiple hits, with an average session of 20mins, but i can multiple pageview by time to see total time for goal 2. I found two solutions for goal one, events (which were not exposed in easy tracker), and also in my applicationDidBecomeActive (if it's not a restore of backgrounded app) then i track a pageview for AppStarted. I ended up wrapping the whole thing in a utility class and rolled it into a couple of my apps, so will be interesting too see the results. If anyone else tries this, you might want to think about using the custom variables too. I added my app version to this, so I can also monitor how many users are migrating to the latest app releases.

OpenAL randomly stops playing some sounds, can only fix with reboot

THE APPS: Two Cocos2d universal iOS games with a large customer base.
THE PROBLEM: Several months back (in 2011) reports started coming in, sounds would randomly cut out, only some of the sounds would play in the app, others wouldn’t. This problem can ONLY be fixed by a device reboot.
IMPORTANT NOTES & DETAILS:
The SAME code and SAME sound files played fine for over a year with
NO bug reports of this sort. I wish I could pinpoint a date, but I
believe the problem started with an iOS update.
The bug is incredibly hard to reproduce. I have personally seen it
once, but I have had no luck causing it again. Yet we get 1-2
support emails a day with the same issue, some of which come in the
form a bad reviews. If I had to pull a number out of the air, I’d
guess we’re looking at a 1 in 1000 incidence. It seems maybe more
common on the iPad, but I’m not sure.
Restarting the device is the ONLY way to fix the problem.
Restarting the app does nothing, deleting the app and reinstalling
does nothing, has to be a power down and turn back on.
A few weeks ago in an attempt to blindly fix I dumped the Cocos2d
Sound engine and switched one of the apps over to ObjectAL (another
openAL based sound engine), hoping it might have fixed the problem.
It did not, same issue is occurring. As you'd note, both of these
are just interfaces for OpenAL.
The sound files themselves were converted from wavs to cafs using
Apple’s recommend method (
https://developer.apple.com/library/ios/#codinghowtos/AudioAndVideo/_index.html
), although we also used the -c 1 flag to make them single channel.
Just to be clear, the bug has nothing to do with the usual sound
issues (mute switch, volume). A portion of the sounds continue
playing fine, but they will never all play again until the device is
powered down and restarted.
If anyone has any ideas I’d all, I’d be very grateful for the help. I’m at wits end here trying to fix a persistent bug I can’t recreate and that appears to be caused by something outside my control.
I've had similar problems with OpenAL, as the commenters stated. We had spurious problems on different hardware and on different OS releases. Really, it was nearly impossible to reproduce. The only reason we even found out about the problem was the significant percentage of users who experienced crashes or other severe audio problems. We tried for months trying to make it work, but in the end the stability problems we experienced just weren't manageable. We ended up going with another library and took OpenAL completely out of the picture. I certainly would not recommend it for new projects.

Resources