UISlider following sound volume, not working - core-audio

I am having an issue in my iPhone app with sound.
I have a UISlider object that I use to adjust the sound volume.
When it appears I use code based on the following line, to set the initial value of the slider:
AudioSessionGetProperty ('chov',&dataSize,&volume);
and that works fine. Then I would like the slider to move accordingly when I activate the hardware sound volume buttons of the device.
But this part based on this kind of code:
AudioSessionPropertyID volumeChangeID=kAudioSessionProperty_CurrentHardwareOutputVolume;
AudioSessionAddPropertyListener(volumeChangeID,handleSoundVolume,self);
does not work so well.
What I can see is that the callback function:handleSoundVolume is only called when some sound is playing and not otherwise.
On the other hand the value provided by AudioSessionGetProperty is always correct independently of sound playing or not.
Why is that?
I thought AudioSessionGetProperty and AudioSessionAddPropertyListener were working "together", but it does not seem so.
Looking at the default Music app on iPod touch, it seems that what I want to do is quite possible.
Thanks for any piece of information.

I have seen the same problem, the callback did not work at all for me.
The best solution is to add an observer to the NSNotificationCenter, for property AVSystemController_SystemVolumeDidChangeNotification.
NSNotificationCenter * center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:#selector(volumeChanged:)
name:#"AVSystemController_SystemVolumeDidChangeNotification"
object:nil];
and you have the method
- (void)volumeChanged:(NSNotification*)notification
{
float volume = [[[notification userInfo]
objectForKey:#"AVSystemController_AudioVolumeNotificationParameter"]
floatValue];
}
by the way I recommend instead of using 'chov' you should use the constant
kAudioSessionProperty_CurrentHardwareOutputVolume

Related

Xcode- Alert if iPhone not charging [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How to know when the device is charging?
I am kind of a noob at Xcode so sorry if I make I fool out of my self. I am trying to make an app and one of the functions is to check if the iphone/ipod/ipad is charging or not. If not charging I want it to play a sound perhaps and flash LEDs. Also if it is charging, I want to make it display text such as "Device Charging :) " . By the way I am using the method with the FlipsideViewController, but these features will be in the MainView. I have looked at various examples and have seen the one below as well as many test applications, but I don't know how to use it. Thank you in advance!!
Code:
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
if ([[UIDevice currentDevice] batteryState] != UIDeviceBatteryStateUnplugged) {
//Device is connected (charging or fully charged)
}
It sounds like you might want to start with some tutorials on writing iPhone apps because the code above looks ok (though I haven't tried this specifically). If you don't understand how to do some of the things I describe below (or some of the terms are unfamiliar), I'd recommend getting a good book or checking out some tutorials:
Book: iOS 6 SDK Development (Amazon)
Tutorials: Ray Wenderlich has many good tutorials on his site
Apple Documentation is quite good
There's no point in just writing the code for you because you presumably want to learn how to program and you won't learn much if someone just does it for you.
Here are some pointers on how to think about this, though the behavior you desire isn't completely obvious from what you've said.
If I understand you you want two different actions to happen when the main view is displayed.
To start with, why not get it to set the text string in a field to match the state of charging / not charging?
So you'd add a UILabel to the main view .xib file in Xcode and add an outlet to it in the view controller so that you can set it's text at runtime.
Then you'll want to call the first line above somewhere once to start monitoring (parameter is: YES) and again with NO to stop monitoring once the view goes away. If you look at the documentation for UIViewController at developer.apple.com near the top you'll see a list of methods that UIViewController implements. In this case you probably want to override (create your own version of) viewWillAppear and viewWillDisappear and put the setBatteryMonitoringEnabled call with YES and NO into these two methods respectively.
So that takes care of enabling / disabling battery status monitoring. Now you need to test the state and take action (this is call to batteryState in your code above).
One question about design which isn't obvious from your description is if you want to do this once when the view appears or if you want it to continually monitor the state.
If you want to do it once, you could put the call to the above in viewDidAppear, say, and then use the outlet to the UILabel to set the message in the label to "Charging" or "Not Charging" based on the result from the batteryState method.
If you want something that watches for changes in the state of charging then you need to subscribe to the notification and put your code to change the UILabel (or whatever you finally do in response to a change) in the handler for that notification.
You figure this out by reading the documentation for UIDevice at developer.apple.com or in Xcode's Organizer window's Documentation section. If you read the documentation for the UIDevice method batteryMonitoringEnabled you can see that the "See Also" section includes two entries for the notifications you can subscribe to to find out when the Level or the State changes: UIDeviceBatteryLevelDidChangeNotification and UIDeviceBatteryStateDidChangeNotification. To learn how to subscribe to notifications you'll want to look at NSNotificationCenter documentation.
Then once you get this working you can add your fancier alerts (be careful about putting them up repeatedly!) and sounds (though playing a sound when the battery isn't charging will use battery which is somewhat questionable.. just make sure not to do it repeatedly perhaps).
good luck!
Add this to the appDelegate.m
- (void)applicationDidBecomeActive:(UIApplication *)application{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryStateDidChange:) name:UIDeviceBatteryStateDidChangeNotification object:nil];
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
}
- (void)applicationWillResignActive:(UIApplication *)application {
[[UIDevice currentDevice] setBatteryMonitoringEnabled:NO];
}
- (void)batteryStateDidChange(NSNotification*)notif {
// check the status here.
// See if it is charging, or not and respond to the change.
}
(edited to make code more explicit)

Hide Volume Level Pop Up MPMusicPlayerController Xcode

I'm using MPMusicPlayerController to play a list of mp3 in my app.
The only problem is when I set the volume level, according with app configuration, appears a Volume Level pop up.
I tried to find any property in order to hide it, but I didn't find.
The code I'm using is:
if (audioPlayer)
if ([audioPlayer isPlaying])
[audioPlayer stop];
self.musicPlayer = [MPMusicPlayerController applicationMusicPlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handlePlaybackStateChanged:) name:MPMusicPlayerControllerPlaybackStateDidChangeNotification object:self.musicPlayer];
[self.musicPlayer beginGeneratingPlaybackNotifications];
[self.musicPlayer setAccessibilityElementsHidden:YES];
self.musicPlayer.volume = volume;
[self.musicPlayer setQueueWithItemCollection:mediaItemCollection];
self.musicPlayer.repeatMode = MPMusicRepeatModeAll;
[self.musicPlayer play];
My question is, Any way to avoid this pop up?
Thanks.
I found a workaround for this problem in other post
But, there is not a direct way to perform that without using MPVolumeView "invisible"?
Sorry :)

CALayer Live Resize Poor Performance

I have a UI where the content of an NSCollectionViewItem's View is drawn programmatically through CALayers. I am using a CAConstraintLayoutManager to keep the layot of the sublayers consistent when resizing, but I am getting very poor performance when doing so. It seems that resizing the window, which causes the resize of two CATextLayers so that they fit the root layer's width, and the repositioning of one CATextLayer so that it stays right-aligned, is causing the application to spend most of its time executing the CGSScanConvolveAndIntegrateRGB function (I have used the Time Profiler instrument).
The most "expensive" layer (the one that causes the most stuttering even if it's the only one displayed) is a wrapped multiline CATextLayer. I have absolutely no idea how to get better performance (I have tried not using a CAConstraintLayoutManager and going with layer alignments but I'm getting the same thing). Has anyone had this problem? Is there a way around it?
PS: I have subclassed the layout manager and disabled all the animations during the execution of - (void)layoutSublayersOfLayer:(CALayer *)layer by setting YES to kCATransactionDisableActions in the CATransaction but it doesn't seems to help.
Edit: I have disabled Font Smoothing for the Text Layers and performance has increased a little bit (very little), but it spends an awful amount of time in _ZL9view_drawP7_CAViewdPK11CVTimeStampb (which is something that gets called by a thread of the ATI Radeon driver, I suppose).
I solved it. Kind of. It still seems like a dirty hack to me, but I couldn't find out how to make setNeedsDisplayInRect work so I ended up doing it like this:
In the NSWindow delegate:
-(void)windowWillStartLiveResize:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"beginResize" object:nil];
}
-(void)windowDidEndLiveResize:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"endResize" object:nil];
}
In my Custom View those two notifications call, respectively, the -(void)beginResize and -(void)endResize selectors. The first one sets a BOOL inLiveResize variable to YES, while the second one sets it to NO and calls setFrameSize again with the new frame size.
I overrode (overridden? Not native english speaker, sorry) the -(void)setFrameSize:(NSSize)newSize method like this:
-(void)setFrameSize:(NSSize)newSize
{
if (inLiveResize) {
NSRect scrollFrame = [[[self superview] enclosingScrollView] documentVisibleRect];
BOOL condition1 = (self.frame.origin.y > (scrollFrame.origin.y - self.frame.size.height));
BOOL condition2 = (self.frame.origin.y < (scrollFrame.origin.y + scrollFrame.size.height + self.frame.size.height));
if (condition1 && condition2)
[super setFrameSize:newSize];
}
else {
[super setFrameSize:newSize]; }}
That's it. This way, only the visible views resize live with the window, while the others get redrawn at the end of the operation. It works, but I don't like how 'dirty' it is, I'm sure there is a more elegant, built-in(ish) way to do this by using the setNeedsDisplayInRect method. I will research more.

How can I make a label smoothly disappear after a certain time in my app?

I am using Xcode to create a Cocoa app for Mac OSX written in Objective-C. I was wondering if I could use an NSTimer to make a label Smoothly disappear after a certain time after I have clicked a button.
Or I thought I could use this code:
- (IBAction)clickToLoadAppButtonClicked:(id)sender; {
[self performSelector:#selector(delayedLoad) withObject:nil afterDelay:3.0]
}
All I would need to do would be to add a void function called delayedLoad. I just need to know the code to make the label smoothly disappear so I can put it in the void...
Please help and thanks guys :D
You can do it using core animation:
[[myLabel animator] setAlphaValue:0.0];
This animates to transparent over a default period of 0.25 seconds.
See here for some further explanation or here for the full docs.

UIImageView/AVAudioPlayer synchronization

I have an UIView that possess an UIImageView as a subview. This image view is intended to display an animation (basically, with the startAnimating method). When the animation start, I also need to play a sound. For this purpose, I use AVAudioPlayer's prepareToPlay and play methods.
Problem I encounter is that the FIRST TIME the global animation (image animation itself + sound) is launched, the sound is systematically played before the image animation is actually started. Not weird at all considering there is no synchronisation whatsoever.
But how could this synchronization be achieved? Is there some sort of callback which could be used know when the image animation is playing and launch the sound play from there...
Or maybe coupling UIImageView and AVAudioPlayer is not a good idea at all?
Here is my current implementation :
- (void)playSample {
previewView_ = [[[PreviewView alloc] initWithFrame:topView.bounds
backgroundImages:backgroundAnimationImages
characterImages:characterAnimationImages] autorelease];
[previewView_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[topView addSubview:previewView_];
[audioPlayer_ setDelegate:self];
[audioPlayer_ setVolume:1.0];
[previewView_ startPreview]; // This calls startAnimating on the UIImageView of previewView_
[audioPlayer_ playSound];
}
Maybe you could use:
[audioPlayer playAtTime:[audioPlayer
deviceCurrentTime] + someDelayTimeInterval]
I found the the audioPlayer (or prepareToPlay) was messing up with my display updates, so what I ended up doing was to create the audioPlayer for each sound in viewDidLoad: and play it in a method called in a background thread:
[self performSelectorInBackground:#selector(playAudioPlayer:)
withObject:self.audioPlayer];

Resources