Audio Route Button - AirPlay - ios

I am currently playing audio through AudioQueues. I would like to allow users to connect to Airplay devices.
If I create an MPVolumeView and use the 'showsRouteButton' to display the route button I can successfully connect.
Is there a way to change the Audio Route to Airplay without using the MPVolumeView? Or a simpler Apple view that is just the route button?

1 hide MPVolumeView and make it as global var
CGRect frame = CGRectZero;
frame.origin.y = 0;
frame.origin.x = 410; // out of the screen
_volumeView = [[MPVolumeView alloc] initWithFrame:frame];
[_volumeView setShowsVolumeSlider:NO];
[_volumeView setShowsRouteButton:YES];
[self.view addSubview:_volumeView];
2 simulate button tapes
- (IBAction)handleAirPlay:(id)sender {
for (UIButton *button in _volumeView.subviews)
{
if ([button isKindOfClass:[UIButton class]])
{
[button sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
}

I don't think there is any other way to show the airplay route button (at least in current SDK iOS 5.1).. If you want to show AirPlay options you have to use MPVolumeView..

Since iOS 11 you can use AVRoutePicker :
import AVKit
let rpv = AVRoutePickerView()
view.addSubview(rpv)

Related

How to differentiate apple tv and other devices in airplay?

I am trying to connect apple tv through airplay, but the issue is some time if i connect any other external device like bluetooth or some other device it shows like device connected in window. So i want to identify which device is connected i have to enable only when apple tv is connected.
How can i identify whether it is apple tv or some other device?
This how i create airplay custom button
for (UIButton *button in volumeView.subviews) {
if ([button isKindOfClass:[UIButton class]]) {
self.airplayButton = (UIButton*)button;
button.frame = CGRectMake(0, 0, 30, 23);
button.backgroundColor = [UIColor clearColor];
[self.airplayButton addObserver:self forKeyPath:#"alpha" options:NSKeyValueObservingOptionNew context:nil];
}
}
So the alpha always changes for button even some other devices gets connected.
I've had a look into this before, there's no easily provided way of determining whether the attached device is an Apple TV, there is a Airplay Picker which does this but the code/functions behind it don't seem to be available.
The best you can do it monitor for additional screens being added/removed and then showing your external content only when the screen has the capabilities to do what you need.
I have read somewhere previously that you can get the capabilities of an airplay device and use this information to detect an Apple TV but unfortunately I cannot find it at the moment. If I do find it I'll add a comment.
For now, your best option would be to use the concepts described in this guide
The code provided is in objective-c but its very easily converted to swift, here is the main part you should be looking at
- (void)checkForExistingScreenAndInitializeIfPresent
{
if ([[UIScreen screens] count] > 1)
{
// Get the screen object that represents the external display.
UIScreen *secondScreen = [[UIScreen screens] objectAtIndex:1];
// Get the screen's bounds so that you can create a window of the correct size.
CGRect screenBounds = secondScreen.bounds;
self.secondWindow = [[UIWindow alloc] initWithFrame:screenBounds];
self.secondWindow.screen = secondScreen;
// Set up initial content to display...
// Show the window.
self.secondWindow.hidden = NO;
}
}
Like I said you can code this so that it checks the device supports certain resolutions so you can rule out devices that wont support your UI
Some additional resources: https://developer.apple.com/airplay/

How to show Airplay button in MPMoviePlayerController iOS 8

I have an app in which I am playing a video using MPMoviePlayerController with custom controls. I'm adding a feature so that users can mirror the play back in Apple TV for this i have implemented the following code.
MPVolumeView *volumeButton = [[MPVolumeView alloc] initWithFrame:CGRectMake(80.0, 210.0, 160.0, 40.0)];
volumeButton.showsVolumeSlider = NO;
volumeButton.showsRouteButton = YES;
[self.view addSubview:volumeButton];
But Airplay button is not visible in iOS 8. Is there any way to show Airplay button in MPMoviePlayerController?
Please provide your suggestions and valuable inputs.

Re-enable mirroring on iOS

In my iOS app I need to display custom content on external display (using AirPlay) as well as mirroring some screens on TV.
For presenting custom content I use code from Multiple Display Programming Guide for iOS and it works well: while my iPad is in 'mirror' AirPlay mode I'm able to show some stuff on the TV. However, documentation says6
To re-enable mirroring after displaying unique content, simply remove the window you created from the appropriate screen object.
And this part isn't working at all. I just cannot destroy my window that I use to display content on external screen. Here's the code:
- (void) destroySecondWindow{
if (secondWindow){
for( UIView* view in secondWindow.subviews ){
[view removeFromSuperview];
}
secondWindow.backgroundColor = [UIColor clearColor];
secondWindow.hidden = YES;
// Hide and then delete the window.
[secondWindow removeFromSuperview];
secondWindow = nil;
}
}
As far as unique content should be displayed only when one particular view controller is visible, I'm trying to destroy external window like this:
- (void) viewWillDisappear:(BOOL)animated{
[self destroySecondWindow];
}
Here's how I create second window:
- (void) createSecondWindowForScreen:(UIScreen*)screen{
if( screen == nil || secondWindow != nil ){
return;
}
CGRect screenBounds = screen.bounds;
secondWindow = [[UIWindow alloc] initWithFrame:screenBounds];
secondWindow.backgroundColor = [UIColor blueColor];
secondWindow.screen = screen;
[secondWindow setHidden:NO];
}
So the question is: does anybody know how to re-enable screen mirroring after displaying unique content on TV?
Thanks in advance!

ios6 moviePlayer first frame not appearing upon creation

I have methods inside my open class controller that instantiates a moviePlayer, which is set to 'autoPlay = NO';
I have added the movieplayer.view as a subview of the controllers view, configured it and created a full screen button on top for starting the video. Since iOS4.3, this has been working fine. The button is transparent and the first frame of the video showed through ( which was a picture of a custom Automoble Auto-Start button).
Since iOS6, I only get a black screen.
Clicking the image-button does start the video as it should; calls [moviePlayer play]
Has something changed that I have not taken into consideration?
I have provided the two sections of code I think are necessary.
#define INTRO_MOVIE #"Intro.mov"
-(void)viewDidLoad
{
if(SHOULD_PLAY_INTRO_VIDEO)//Debug switch to ignore the intro video
{
// Prepare the movie and player
[self configureIntroMoviePlayer];
[self.view addSubview:moviePlayer.view];
[self.view bringSubviewToFront:moviePlayer.view];
// Add and Show the Start Button to start the App
[self configureStartButton];
[self.view addSubview:startButton];
}
}
-(void)configureIntroMoviePlayer
{
LOGINFO
// Prepare the Intro Video
NSString *pathToIntroVideo = [ mainFilePath_ stringByAppendingPathComponent: INTRO_MOVIE];
NSURL *URLToIntroVideo = [NSURL fileURLWithPath:pathToIntroVideo];
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:URLToIntroVideo];
[moviePlayer setShouldAutoplay:NO];
moviePlayer.view.frame = CGRectMake(0, -20, 1024, 768);
[moviePlayer setControlStyle:MPMovieControlStyleNone];
//fixing video brightness Difference with iPad2
if(isIpad2)
{
moviePlayer.backgroundView.backgroundColor = [UIColor blackColor];
moviePlayer.view.alpha = .99;
}
// Create the sKip button for cancelling the Intro Video
skipIntro = [UIButton buttonWithType:UIButtonTypeCustom];
[skipIntro showsTouchWhenHighlighted];
skipIntro.frame = CGRectMake(900, 20, 111, 57);
[skipIntro addTarget:self action:#selector(skipIntroWasPressed) forControlEvents:UIControlEventTouchUpInside];
}
I am not sure why I got a -1 rating for this question for lack of research or clarity?
Maybe I do not know the proper usage of this forum.
I apologize.
I did find that adding [moviePlayer prepareToPlay] solved the problem. Like I said, it was odd that the first frame always showed up prior to iOS 6.
Have you tried:
[moviePlayer.view addSubView:startButton];

AirPlay button on custom view - problems

I am developing an iPhone application that supports AirPlay using MPMoviePlayerController. But, I need to display this AirPlay button in my custom-view. So, I took MPVolumeView and added it to my custom view; removed all the subviews from MPVolumeView except AirPlay button.
The problem is:
Can I change the frame of Volume view so that it fits in corner of my custom view with the size of AirPlay button? I know it is possible to handle this programmatically; Is it valid to do like this? The link Customize the Airplay button's appearance mentions that we should not change shape, position of AirPlay button.
I need to set the customized image to AirPlay button so that it matches my Custom View aesthetically. How do I do this?
Whenever device with AirPlay is not present, AirPlay button just disappears from MPVolumeView. Is there any notification available when button disappears? I need to adjust my custom view when AirPlay button is not present. Is there any method to identify if AirPlay button is present or not? The MPVolumeView subviews array has this button and it is not in hidden state even if it is not displayed in MPVolumeView.
You should take a look at this answer: Customize the Airplay button's appearance
It's basically the same as my answer, but with more detail. I think it answers most of your question.
Pasting it here, for your convenience:
After accepting #Erik B's answer and awarding the bounty to him, I found that there was more tweaking necessary to get it to work. I am posting here for the benefit of future SO searchers.
The problem I was seeing was that the internal mechanisms of the buttons would assign the image based on the current airplay state. Thus any customizations I made during init would not stick if the Airplay receiver went away, or the state was changed somehow. To solve this, I setup a KVO observation on the button's alpha key. I noticed that the button is always faded in/out which is an animation on alpha.
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectZero];
[volumeView setShowsVolumeSlider:NO];
for (UIButton *button in volumeView.subviews) {
if ([button isKindOfClass:[UIButton class]]) {
self.airplayButton = button; // #property retain
[self.airplayButton setImage:[UIImage imageNamed:#"airplay.png"] forState:UIControlStateNormal];
[self.airplayButton setBounds:CGRectMake(0, 0, kDefaultIconSize, kDefaultIconSize)];
[self.airplayButton addObserver:self forKeyPath:#"alpha" options:NSKeyValueObservingOptionNew context:nil];
}
}
[volumeView sizeToFit];
Then I observe the changed value of the buttons alpha.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([object isKindOfClass:[UIButton class]] && [[change valueForKey:NSKeyValueChangeNewKey] intValue] == 1) {
[(UIButton *)object setImage:[UIImage imageNamed:#"airplay.png"] forState:UIControlStateNormal];
[(UIButton *)object setBounds:CGRectMake(0, 0, kDefaultIconSize, kDefaultIconSize)];
}
}
Don't forget to remove the observer if you destroy the button
- (void)dealloc {
[self.airplayButton removeObserver:self forKeyPath:#"alpha"];
…
}
Based on code observation, the button will break if Apple changes the internal view hierarchy of the MPVolumeView to add/remove/alter the views such that a different button comes up. This makes it kind of fragile, so use at your own risk, or come up with a plan b in case this happens. I have been using it for over a year in production with no issues. If you want to see it in action, check out the main player screen in Ambiance
I have done it more simpler by adding the MPVolumeView to UIBarButtonItem
- (void) initAirPlayPicker {
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(0,0,44,44)];
volumeView.tintColor = [UIColor blueColor];
volumeView.backgroundColor = [UIColor clearColor];
UIImage *imgAirPlay = nil;
for( UIView *wnd in volumeView.subviews ) {
if( [wnd isKindOfClass:[UIButton class] ]) {
self.airPlayWindow = (UIButton*) wnd;
UIImage *img = _airPlayWindow.currentImage;
imgAirPlay = [img imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[volumeView setRouteButtonImage: imgAirPlay forState:UIControlStateNormal];
break;
}
}
volumeView.showsRouteButton = YES;
volumeView.showsVolumeSlider = NO;
[volumeView sizeToFit];
self.airPlayButton = [[UIBarButtonItem alloc] initWithCustomView:volumeView];
}
By adding the MPVolumeView to the view hierarchy its gets the notification about the Airplay state and is workling properly.

Resources