i am getting System volume from following code
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(volumeChanged:)
name:#"AVSystemController_SystemVolumeDidChangeNotification"
object:nil];
- (void) volumeChanged:(NSNotification *)
{
float volume = [[[notification userInfo]
objectForKey:#"AVSystemController_AudioVolumeNotificationParameter"]
floatValue];
// here volume is the .....
}
but how to set system or devices volume from xcode (Objective C)
It's not possible to programmatically set the system volume without calling private methods/using private APIs.
You would have to call _commitVolumeChange which is private API and will definitely get your app rejected.
Further reading here.
Maybe this will help you (if you can get access to AVPlayer object and want to change the volume of your playing Asset), I use such code for modifying volume in my AVPlayer while playing video.
- (void)setVolume:(CGFloat)volumeToSet forPlayer:(AVPlayer *)avPlayer {
AVURLAsset *asset = (AVURLAsset *) [[avPlayer currentItem] asset];
NSArray *audioTracks = [asset tracksWithMediaType:AVMediaTypeAudio];
NSMutableArray *allAudioParams = [NSMutableArray array];
for (AVAssetTrack *track in audioTracks) {
AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters];
[audioInputParams setVolume:volumeToSet atTime:kCMTimeZero];
[audioInputParams setTrackID:[track trackID]];
[allAudioParams addObject:audioInputParams];
}
AVMutableAudioMix *audioZeroMix = [AVMutableAudioMix audioMix];
[audioZeroMix setInputParameters:allAudioParams];
[[avPlayer currentItem] setAudioMix:audioZeroMix];
}
More details about this solution here Adjusting the volume of a playing AVPlayer
If you would like to change device's volume look here, this is workaround and may broke in some iOS versions, but works now in iOS 7, iOS 8, iOS 9 (tested it).
iOS 9: How to change volume programmatically without showing system sound bar popup?
Related
I'm trying to implement a fade-in effect based on AVPlayer + AVAudioMix + AVAudioMixInputParameters. It basically works except when playing the audio for the first time after starting my app there is a click in the beginning. Subsequent plays work perfect though, but the first-time glitch is pretty stable and reproducible.
My Play button is enabled only after the AVPlayerItem's status is set to ready, so it's impossible to fire a play method while the player is not ready. In fact it doesn't matter how long I wait after loading the audio file and constructing all the objects.
This happens on OS X, I haven't tested it on iOS (yet).
Note that for this test you need an audio file that starts with sound and not silence. Here is my stripped down code without the GUI part (testFadeIn is the entry point):
static AVPlayer* player;
static void* PlayerItemStatusObserverContext = &PlayerItemStatusObserverContext;
- (void)testFadeIn
{
AVURLAsset* asset = [AVURLAsset.alloc initWithURL:[NSURL fileURLWithPath:#"Helicopter.m4a"] options:#{AVURLAssetPreferPreciseDurationAndTimingKey: #YES}];
AVPlayerItem* item = [AVPlayerItem playerItemWithAsset:asset];
player = [AVPlayer playerWithPlayerItem:item];
[item addObserver:self forKeyPath:#"status" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:PlayerItemStatusObserverContext];
}
- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
if (context == PlayerItemStatusObserverContext)
{
AVPlayerStatus status = (AVPlayerStatus)[[change objectForKey:NSKeyValueChangeNewKey] integerValue];
if (status == AVPlayerStatusReadyToPlay)
{
[self applyFadeIn];
[self performSelector:#selector(play:) withObject:nil afterDelay:1.0];
}
}
}
- (void)applyFadeIn
{
assert(player.currentItem.tracks.firstObject);
AVMutableAudioMixInputParameters* fadeIn = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:player.currentItem.tracks.firstObject];
[fadeIn setVolume:0 atTime:kCMTimeZero];
[fadeIn setVolume:1 atTime:CMTimeMake(2, 1)];
NSMutableArray* paramsArray = [NSMutableArray new];
[paramsArray addObject:fadeIn];
AVMutableAudioMix* audioMix = [AVMutableAudioMix audioMix];
audioMix.inputParameters = paramsArray;
player.currentItem.audioMix = audioMix;
}
- (void)play:(id)unused
{
[player play];
}
Click! What is wrong with this?
Edit:
An obvious workaround that I use at the moment is: when the player reports it's ready, I do a short 100ms playback with volume=0, then restore currentTime and volume and only then I report to the main app that the player is ready. This way there are no clicks. Interestingly, anything less than 100ms still gives the click.
This seems like an issue with something that's being cached by AVFoundation after the first playback. It's neither the tracks, as they are available when I set the fade in params, nor the seek status.
So I am streaming a video file with audio using AVPlayer and have a UIWebView overlayed over the video that has controls for play/pause, seek, ect. I also have a slider for volume that I am trying to implement but so far I haven't had any luck. Here is my code the change the volume:
- (void)setPlayerVolume:(float)volume
{
NSArray *tracks = [self.player.currentItem.asset tracksWithMediaType:AVMediaTypeAudio];
NSMutableArray *audio = [NSMutableArray array];
for (AVAssetTrack *track in tracks) {
AVMutableAudioMixInputParameters *input = [AVMutableAudioMixInputParameters audioMixInputParameters];
[input setVolume:volume atTime:kCMTimeZero];
[input setTrackID:track.trackID];
[audio addObject:input];
}
AVMutableAudioMix *mix = [AVMutableAudioMix audioMix];
[mix setInputParameters:audio];
[self.player.currentItem setAudioMix:mix];
}
I have been reading up, and it seems like the only solution to use MPVolumeView. Are there any other solutions?
Thanks for any help, its greatly appreciated.
I wanted to change volume settings with a UISlider.
I used currentItem inside AVQueuePlayer.
ps0 is an AVQueuePlayer.
I have no error and same sound level when I use my UISlider:
- (IBAction)volumeSliderMoved:(UISlider *)sender
{
AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters];
AVPlayerItem *av = [ps0 currentItem];
CMTime currentTime = [av currentTime];
float volume = [sender value];
[audioInputParams setVolume:volume atTime:currentTime];
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
audioMix.inputParameters = [NSArray arrayWithObject:audioInputParams];
av.audioMix = audioMix;
[ps0 replaceCurrentItemWithPlayerItem: av];
}
EDITED :
I tried another solution from Apple to change volume settings.
As you can see in this solution, it create a new playerItem and a new player.
But my playerItem is a copy of the current one because I just want to change the sound (not the item). And it is automatically related to the old player.
When I try to use their solution. I have an error message saying:
An AVPlayerItem cannot be associated with more than one instance of AVPlayer
Any suggestion?
EDITED again
To change playback with AVQueuePlayer
I have an array with every mp3 name “textMissingTab”
I have an array with AVPlayerItem “soundItems”
Creation :
textMissingTab = [[NSArray alloc] initWithObjects:#"cat",#"mouse",#"dog",#"shark",#"dolphin", #"eagle", #"fish", #"wolf", #"rabbit", #"person", #"bird", nil];
for (NSString *text in textMissingTab)
{
NSURL *soundFileURL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:text ofType:#"mp3"]];
AVPlayerItem *item = [AVPlayerItem playerItemWithURL:soundFileURL];
[soundItems addObject:item];
}
Init :
NSURL *soundFileURL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:#"dog" ofType:#"mp3"]];
ps0 = [[AVQueuePlayer alloc] initWithURL:soundFileURL];
Change playItem : text is NSString
int index = [textMissingTab indexOfObject:text];
[ps0 setActionAtItemEnd:AVPlayerActionAtItemEndNone];
CMTime newTime = CMTimeMake(0, 1);
[ps0 seekToTime:newTime];
[ps0 setRate:1.0f];
[ps0 replaceCurrentItemWithPlayerItem:[soundItems objectAtIndex:(index)]];
[ps0 play];
I had several problems using AVQueuePlayer and changing playback parameters. If your goal is to use a slider for volume adjustment, I would replace the UISlider with a blank UIView in your storyboard and then instantiate an MPVolumeView within that view. This works reliably for me. Note that MPVolumeView does not show up on the simulator.
I think you are right tigloo. MPVolumeView is the best way to manage sound level.
It is explained in this tutorial :http://www.littlereddoor.co.uk/ios/controlling-system-output-volume-by-adding-an-mpvolumeview-object-to-an-ios-application/
"Everything works exactly as we would expect until the user hits the stumbling block that is created by the current ringer volume that is set on the device. The maximum value of the AVAudioPlayer property is 1.0, where 1.0 is equal to the current ringer volume setting of the device. Simply put, if the device ringer volume is set to 50% volume, then 100% of the AVAudioPlayer volume still only equates to the already set 50% ringer. The limitations of using this method speak for themselves."
I edited again my post to show how I manage some songs with AVQueuePlayer. This part of code is working.
AVAsset *asset;
NSArray *playerTracks;
NSMutableArray *playerParams;
AVMutableAudioMix *muteAudioMix;
for (int k=0; k<[[audio items] count]; k++)
{
//disable audio (this is the version when you have more than one video in the playlist: i write this version so it should be more useful)
asset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[soundfile objectAtIndex:k+([soundfile count]-[[audio items] count])] ofType:#"mp3"]] options:nil];
playerTracks = [asset tracksWithMediaType:AVMediaTypeAudio];
playerParams = [NSMutableArray array];
for (AVAssetTrack *track in playerTracks) {
AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters];
[audioInputParams setVolume:1.0 atTime:kCMTimeZero];
[audioInputParams setTrackID:[track trackID]];
[playerParams addObject:audioInputParams];
}
muteAudioMix = [AVMutableAudioMix audioMix];
[muteAudioMix setInputParameters:playerParams];
[[[audio items] objectAtIndex:k] setAudioMix:muteAudioMix];
}
I'm using AVPlayer for playing radio stream.
For initializing player i'm using next code:
self.asset = [AVAsset assetWithURL:self.url];
self.item = [AVPlayerItem playerItemWithAsset:self.asset];
self.player = [AVPlayer playerWithPlayerItem:self.item];
I've read this question Adjusting the volume of a playing AVPlayer
and i'm trying to set volume with slider value
- (void)setVolume:(float )volume
{
_volume = volume;
NSArray *audioTracks = self.asset.tracks;
NSMutableArray *allAudioParams = [NSMutableArray array];
for (AVAssetTrack *track in audioTracks) {
AVMutableAudioMixInputParameters *audioInputParams =
[AVMutableAudioMixInputParameters audioMixInputParameters];
[audioInputParams setVolume:volume atTime:kCMTimeZero];
[allAudioParams addObject:audioInputParams];
[audioInputParams setTrackID:[track trackID]];
}
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
[audioMix setInputParameters:allAudioParams];
NSLog(#"%#", self.player.currentItem);
NSLog(#"%f", volume);
[self.player.currentItem setAudioMix:audioMix];
}
I'm also trying to set
[audioInputParams setVolume:volume atTime:self.player.currentTime];
but there are not any tracks in that array (self.asset.tracks),
and its have not any effect on volume. (also i can't get any metadata),
I can't use AVAudioPlayer for playing audio stream by url
An instance of the AVAudioPlayer class, called an audio player,
provides playback of audio data from a file or memory.
Apple recommends that you use this class for audio playback unless you
are playing audio captured from a network stream or require very low
I/O latency.
I'm thinking about using that code https://github.com/DigitalDJ/AudioStreamer/downloads
for playing radio stream, but i don't know how set volume with Audiotoolbox.
Please, help me! Thanks!
i have tried lots of solutions, but the best way to do that is to implement an instance ov MPVolumeVIew:
self.myViewVolume = [[MPVolumeView alloc] initWithFrame:CGRectMake(20, 330, 280, 50)];
[self.myViewVolume sizeToFit];
[self.view addSubview:self.myViewVolume];
You can add this to any UIView you want, just change the class to MPVolumeView
Do not forget to add MediaPlayer framework.
Here is what you have to do if you want to get metadata from your stream:
[playerItem addObserver:self forKeyPath:#"timedMetadata" options:NSKeyValueObservingOptionNew context:NULL];
With this you can simply add the information to any UILabel
I'm working on an app that plays two different tracks from the users iPod library.
I need to be able to adjust the volume of the two tracks independently.
Looking around online I found a suggestion to adjust the AVMutableAudioMix on the playerItems that are active in each of the two AVPlayers.
I've subclassed AVPlayer to include some functionality that I need to emulate a musicPlayer like the iPod.
Below is the method inside my AVPlayer subclass that I would like to use to adjust that players playerItem volume.
This method is being called by my viewController when a sliderValue is changed.
My result is that the volume does not change.
Does anyone know if this approach can work?
It seems to me that if it doesn't my only choice is to dig into Core Audio.
Thanks.
-(void)setPlayerItemVolume:(float)itemVolume
{
self.volume = itemVolume;
AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters];
AVPlayerItem *currentPlayerItem = [self currentItem];
CMTime currentTime = [currentPlayerItem currentTime];
[audioInputParams setVolume:itemVolume atTime:currentTime];
//[audioInputParams setTrackID:[currentPlayerItem trackID]];
//[allAudioParams addObject:audioInputParams];
NSArray *allAudioParams = [[NSArray alloc]initWithObjects:audioInputParams, nil];
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
[audioMix setInputParameters:allAudioParams];
[currentPlayerItem setAudioMix:audioMix];
}
iOS 7 introduces 2 new properties on AVPlayer: 'volume' and 'muted'. You should be able to use those to independently change audio levels.