OpenAL on iPhone suddenly becomes really quiet - iphone

As the title states, sounds will just play at ridiculously quiet volumes. I thought it wasn't playing at all until I heard sounds barely audible at max volume.
It's been fine for weeks. Not a problem. Suddenly it started doing this out of nowhere. I've tried cleaning/rebuilding, restarting Xcode, restarting device, etc. Nothing fixes it. It'll just suddenly come back again in a random build. This is really starting to frustrate me and I'm disappointed I went with OpenAL, as this isn't the first problem I've had with it in just a few weeks of using it. I can't release anything with sound that MIGHT work sometimes.
I'm using AVAudioPlayer simultaneously to play background music, and have not had a single problem with that.
Anyone have any idea what could be causing this?
In response to user1260708:
My init method looks like this
bool D2DSoundController::init(Map<D2DSound> *sounds) {
if (!_initialzed) {
OSStatus result = AudioSessionInitialize(NULL, NULL, &_interruptionListener, (void*)_context);
ulong cat = kAudioSessionCategory_MediaPlayback;
result |= AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(cat), &cat);
_sounds = sounds;
_device = alcOpenDevice(0);
if (_device != 0) {
_context = alcCreateContext(_device, 0);
if (_context != 0) {
alcMakeContextCurrent(_context);
alGenSources(_numSources, _sources);
//alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
//alListener3f(AL_POSITION, 300.0f, 200.0f, 0.0f); --- I think this was the problem?
_initialzed = true;
return (alGetError() == 0 && result == 0);
}
return false;
}
return false;
}
return false;
}
However, I think I found the issue. After commenting out the alListener3f call (just noticed it as the line above had been commented out for a while), it seems to be working again. I don't see why this suddenly became an issue though, as it's been there the whole time; distance attentuation wasn't working right for me either (reason that call was there in the first place, for testing), so I decided overall not to use it, but I guess I forgot to remove that line.
See this question: Distance Attenuation with OpenAL on iPhone/iPod
Any input on the attentuation issue (which seems to be the root of this as well) would be great though!
As I side note, since I dropped attentuation, I've been using stereo as well, which shouldn't be affecting that, so I'm still confused.

Related

Accurately reading of iPhone signal strength

There are a few questions on this already, but nothing in them seems to provide accurate results. I need to determine simply if the phone is connected to a cell network at a given moment.
http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Reference/CTCarrier/Reference/Reference.html
This class seems to be documented incorrectly, returning values for mobileCountryCode, isoCountryCode and mobileNetworkCode where no SIM is installed to the phone. carrierName indicates a 'home' network or a previous home network if the phone has been unlocked.
I also looked up and found some people claiming the following to work, which uses an undocumented method of the CoreTelephony framework, but the results have been useless to me, reporting seemingly random figures, where perhaps it is not itself updating consistently.
-(int) getSignalStrength
{
void *libHandle = dlopen("/System/Library/Frameworks/CoreTelephony.framework/CoreTelephony", RTLD_LAZY);
int (*CTGetSignalStrength)();
CTGetSignalStrength = dlsym(libHandle, "CTGetSignalStrength");
if( CTGetSignalStrength == NULL) NSLog(#"Could not find CTGetSignalStrength");
int result CTGetSignalStrength();
dlclose(libHandle);
return result;
}
Thanks.
Edit: The app is connected to an internal wifi and must remain so, making a reachability check more difficult.
I'm playing with this function and I've noticed you're calling it in an interesting way. I'm calling it by adding CoreTelephony.framework as a compile-time link. For the function itself, you'll want to declare it's prototype somewhere (perhaps immediately above the method you call from):
int CTGetSignalStrength();
This needs to be declared since it isn't in a public header for CoreTelephony.
Now, I built a simple app that prints signal strength every second.
int CTGetSignalStrength();
- (void)viewDidLoad
{
[super viewDidLoad];
while (true) {
printf("signal strength: %d\n", CTGetSignalStrength());
sleep(1);
}
}
I ran it on my iPad mini and it shows steady values until I picked it up, where the number went up. Wrapping my iPad in tin foil (tin foil is a debugging tool I have never used before) caused the number to go down. When I put my iPad in airplane mode, it kept repeating the last value, so this will not be an accurate measure for you.
If you want to test if a device currently has a cellular data network connection, you may be more interested in Reachability, specifically kSCNetworkReachabilityFlagsIsWWAN.
Ok I think I have the correct solution now, which was a bit simpler in the end.
The issue with the CTGetSignalStrength() method is that it works normally, but if you remove a sim, it reports the last signal before the removal. I found another method in the same framework called CTSIMSupportGetSIMStatus(), also undocumented, which can tell you if a SIM is currently connected. Using both as follows should confirm the current network signal.
First declare the methods:
NSString * CTSIMSupportGetSIMStatus();
int CTGetSignalStrength();
Then check connectivity to cell network like so:
NSString *status = CTSIMSupportGetSIMStatus();
int signalstrength = CTGetSignalStrength();
BOOL connected = ( [status isEqualToString: #"kCTSIMSupportSIMStatusReady"] && signalstrength > 0 );

(iphone) Is having many AVAudioPlayer instance fine?

For my small game, I'd like to play effect sound for various scenario.
Mostly it will be user-interaction related.
I may need to play multiple sounds at one time.
I'm planning to allocate AVAudioPlayer for each sound.
I wonder a viewController having about 10-20 AVAudioPlayers is fine.
(sound data itself is rather small, less than 100k in aac)
I just feel that declaring 10-20 AVAudioPlayer instance in a class seems weird.
Is there a better way of doing it or am I just over-thinking it?
I think OpenAL is a better option in such situations. Dont worry if you dont know it. There is a great video tutorial here (with source code): http://www.71squared.com/2009/05/iphone-game-programming-tutorial-9-sound-manager/
To find more you can visit:
http://benbritten.com/2008/11/06/openal-sound-on-the-iphone/comment-page-1/
Yes, it's fine to have many AVAudioPlayer instances. I don't know how many the limit is but it's definitely more than a dozen.
Here are some gotchas:
AVAudioPlayer doesn't do level mixing, so if your sounds are high volume, they may end up constructively interfering with each other and causing waveform distortion. I set a maximum volume of 0.8 to try to work around this, but it's not reliable.
If you try to start them all at the same time, using the play method may end up starting them out of sync. Instead, figure out a time soon enough that the user won't notice, but far enough away that it gives your code time to exit and AVFoundation time to get ready. Then use [player playAtTime:soon].
Here's some code that's working for me now. YMMV:
-(void)play
{
BOOL success;
AVAudioPlayer *player = self.player;
player.numberOfLoops = -1;
player.currentTime = 0;
player.volume = _volume;
// NSLog(#"deviceCurrentTime=%f", player.deviceCurrentTime);
static double soon = 0;
if (soon < player.deviceCurrentTime) {
soon = player.deviceCurrentTime + 0.5; // why so flakey???
}
success = [player playAtTime:soon]; // too flakey for now
if (!success) {
NSLog(#"player %# FAILED", player);
} else {
NSLog(#"player %# %# playing at: %f", player, [[player.url relativePath] lastPathComponent], soon);
}
}
(I'm not sure if my "soon" var is thread-safe, and you should adjust the slop until it works for you... 0.1 was too fast for me at some point or other so I bumped it up to 0.5.)

Cocos2D iPhone Effect

trying to play around with the Cocos2d effects and created to methods to display and stop the Liquid action. My application however drops from 60fps down to 30fps when the effect is applied but the fps doesnt increase again when the scheduled stop action is called.
I originally thought that while the action has been completed the effect is still being rendered but after reading through the EffectsTest.h/.m in the Cocos2D 0.8 zip I cant find any reference to how this is achieved. Can anyone shed some light on this issue?
// effects
-(void)enableLiquidEffect
{
id liquid = [Liquid actionWithWaves:6 amplitude:20 grid:ccg(15, 10) duration:3];
[self schedule:#selector(disableLiquidEffect) interval:(3.0)];
[self runAction:liquid];
}
-(void)disableLiquidEffect
{
[self unschedule:#selector(disableLiquidEffect)];
[self stopAllActions];
}
Cheers,
AntonMills
Just a little tip here i know this was asked years ago, but someone might still come here
the code is a little bit overkill, here's how to do it:
// effects
-(void)enableLiquidEffect
{
id liquid = [Liquid actionWithWaves:6 amplitude:20 grid:ccg(15, 10) duration:3];
//No need to unschedule after 3 seconds since you already set duration-^ to 3 seconds.
[self runAction:liquid];
}
-(void)disableLiquidEffect
{
[self stopAllActions];
}
besides that the code is perfect
Just a guess but since the item will still have a transform set to liquid that it is still trying to apply a more complex transform then needed after its done. Save off your transform prior to starting and then when it stops set it back. You could try just setting it to nil.

iPhone - why does AVAudioPlayer currentTime return a negative value?

When does the AVAudioPlayer's currentTime method return a negative value? The audio file is playing (I am putting in a check before getting currentTime) but making a call to currentTime returns a negative value.
Any ideas? Thanks
if(thePlayer != nil && [thePlayer isPlaying]){
double playerTime = [thePlayer currentTime];
NSLog(#"Player Time: %f", playerTime);
}
Output
Player Time: -0.019683
Are you testing this on the simulator? There are several bugs with AVAudioPlayer on the simulator. One is that the currentTime can be a very large positive or negative number. Even if you set the currentTime to a particular number, it will still often show something different. As far as I know this is only an issue on the simulator and not when running on a device.
Here is the code I use to set the currentTime property of an AVAudioPlayer instance:
- (void)safeSetCurentTime:(NSTimeInterval)newTime {
self._player.currentTime = newTime;
if (self._player.currentTime != newTime)
{
// code falls through to here all the time
// the second attempt _usually_ works.
[self prepareAudioForPlayback];
self._player.currentTime = newTime;
//NSLog(#"Set time failed");
}
}
I believe this issue is fixed the iOS4 beta 2 SDK release, so you shouldn't see it on the iPhone. See here. However, I think we're stuck with the problem on the iPad until iOS4 is available on that device.
Anyone know of a workaround? Any way to predict how the current time will be incorrectly reported, so a correction factor can be applied? What I'm seeing is that the current time is reported to be a few seconds behind the actual playback time (which could be negative, if you're near the start of he audio), and it tracks along with the correct position. So perhaps there's some offset that can be applied whenever the app is used on an earlier iOS version?
I found a workaround that fixes the problem on the iPad, which is workable until iOS4 is released for the iPad and fixes the issue.
Keep hold of the audio buffer, and when you're about to resume playback after pausing/stopping, reload the audio buffer into the AVAudioPlayer instance, set currentTime to where you want playback to resume from, and then resume playback.
Works perfectly for me, and reloading the audio buffer seems very fast.

IF Statement Seems To Work Fine On Simulator, But Not On Device!

Ok, the problem is that when my app runs on the simulator it seems to work fine. On the device, however it does not update all the labels. I think the error is somewhere here:
- (IBAction)buttonclick1 {
self.startDate = [NSDate date];
double value = [self Level];
double value2 = [self Level2];
if ((value2 - value) >= 3.0) {
ifWork.text = #"DONE!";
ifWork.textColor = [UIColor yellowColor];
float noSeconds = (float) [self.startDate timeIntervalSinceNow];
}
}
I am new to this game. What I am looking for, is when the button is pressed, it times how long it takes for an event to happen. I then would like to use this time in calculations.
I know the IF statement is correct as it works on the simulator. However on the device, when value and value2 differ by 3 and then the button is pressed, nothing happens (the label ifWork doesn't change!).
Any help would be much appreciated,
Stu
Did you run the code in the debugger to see what happens? Maybe if the values depend on anything like CPU or network performance you may experience notable differences between the simulator and the actual device, so you cannot be sure that what works on the simulator works on the device.
There could be a few reasons.
Level1 or Level2 results could be different on device (using uninitialized memory which is different on device
value2 - value1 could be very close to 3.0 but just less than (doubles are often a little imprecise)
ifWork could be improperly set on the device (i.e. nil) so nothing happens.
The best solution is to debug on the device (step over this code line by line) and check if any of these things are true.