Change AVPlayer Volume - ios

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.

Related

How to set System volume programmatically in iOS

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?

Avplayer playing a video file from document directory - volume issue

I'm playing a video file from the documents directory, but I can't change the volume.
Actually I can play a file from the music video library and change the volume, but not for the precharged ( from iTunes with File Sharing ) videos!
What can I do?
That's the slider that is used like a crossfader between the videos for manage the volume:
AVMutableAudioMixInputParameters* audioInputParams2 = [AVMutableAudioMixInputParameters audioMixInputParameters];
CMTime currentTime = [videoItemDestra currentTime];
//se il video non c'è setta il tempo a zero, almeno non crasha
if(CMTIME_IS_INVALID(currentTime)){
currentTime = kCMTimeZero;
}
//se il pulsante muto è attivo non cambiare volume
if( mutedx ==1){
[audioInputParams2 setVolume:0 atTime:currentTime];
}else{
[audioInputParams2 setVolume:(_volumeSliderAvplayer2.value/100) atTime:currentTime];
}
[audioInputParams2 setTrackID:[videoDestra.tracks[0] trackID]];
NSMutableArray * allAudioParams2= [[NSMutableArray alloc]initWithObjects:audioInputParams2, nil];
AVMutableAudioMix * audioMix2 = [AVMutableAudioMix audioMix];
[audioMix2 setInputParameters:allAudioParams2];
AVMutableAudioMixInputParameters* audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters];
CMTime currentTime2 = [videoItemSinistra currentTime];
//se il video non c'è setta il tempo a zero, almeno non crasha
if(CMTIME_IS_INVALID(currentTime2)){
currentTime2 = kCMTimeZero;
}
//se il pulsante muto è attivo non cambiare volume
if( mutesx ==1){
[audioInputParams setVolume:0 atTime:currentTime2];
}else{
[audioInputParams setVolume:(1-(_volumeSliderAvplayer2.value/100)) atTime:currentTime2];
}
[audioInputParams setTrackID:[videoSinistra.tracks[0] trackID]];
NSMutableArray *allAudioParams= [[NSMutableArray alloc]initWithObjects:audioInputParams, nil];
AVMutableAudioMix* audioMix = [AVMutableAudioMix audioMix];
[audioMix setInputParameters:allAudioParams];
[videoItemSinistra setAudioMix:audioMix];
[videoItemDestra setAudioMix:audioMix2];
I found the solution.
When I load the track in the avplayeritem, that is divided in an "array" of audio, video, timecode ( if present ).
In case of video loaded from iTunes, the file had video, sound, timecode and I must load the sound part in the audiomix.
Before I discover that I load the avplayeritem[0] but it's wrong because in the file loaded from document library the sound part is in another position.
That's the solution:
//load the sound part in an array
audioTrackssx = [videoSinistra tracksWithMediaType:AVMediaTypeAudio];
//the sound part must be only one
[audioInputParams setTrackID:[audioTrackssx[0] trackID]];

AVQueuePlayer volume not changed

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];
}

How to programmatically mute live streaming video in iPhone

I am playing live streaming video in iPhone using AVPlayer. I want to switch off the volume of the player (programmatically). I tried this http://developer.apple.com/library/ios/#qa/qa1716/_index.html. But it is not working in my case.
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[self myAssetURL] options:nil];
NSArray *audioTracks = [asset tracksWithMediaType:AVMediaTypeAudio];
// Mute all the audio tracks
NSMutableArray *allAudioParams = [NSMutableArray array];
for (AVAssetTrack *track in audioTracks) {
AVMutableAudioMixInputParameters *audioInputParams =[AVMutableAudioMixInputParameters audioMixInputParameters];
[audioInputParams setVolume:0.0 atTime:kCMTimeZero];
[audioInputParams setTrackID:[track trackID]];
[allAudioParams addObject:audioInputParams];
}
AVMutableAudioMix *audioZeroMix = [AVMutableAudioMix audioMix];
[audioZeroMix setInputParameters:allAudioParams];
// Create a player item
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
[playerItem setAudioMix:audioZeroMix]; // Mute the player item
// Create a new Player, and set the player to use the player item
// with the muted audio mix
AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
// assign player object to an instance variable
self.mPlayer = player;
// play the muted audio
[mPlayer play];
Please suggest any solution for this.
Thanks
You can use MPVolumeView class, available [here]. It has a slider for volume control, that works for HTTP Live Streams as well.(http://developer.apple.com/library/ios/#documentation/mediaplayer/reference/MPVolumeView_Class/Reference/Reference.html)

How can i set volume of AVPLayer when it's playing radio stream

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

Resources