Monday, 15 March 2010

How to play YouTube videos in your iPhone app

So I was trying to launch a YouTube video from my game, without the game switching to the YouTube app. To do this, I ran into a few issues.

Here I'll describe how to set up the playing of a YouTube video and how to tackle the issues you will encounter.

So first you must create a UIWebView and add it to your main view.
In the following I create a webview pointing to where I have embedding the YouTube clip I want to play, I set it hidden because I'll later want to launch the video full screen.
      htmlView = [[UIWebView alloc] initWithFrame:CGRectMake( 55.0f, 105.0f, 369.0f, 178.0f) ];  
[htmlView setBackgroundColor:[UIColor blackColor]];  
htmlView.hidden = YES;  
htmlView.delegate = self;  
[self addSubview:htmlView];  
[htmlView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@""]]];  

So now in the background the webview starts seeking the website
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
<title>Trailer Page</title>  
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />  
<object width="369" height="178">  
<param name="movie" value="">  
</param><param name="allowFullScreen" value="true">  
</param><param name="allowscriptaccess" value="always"><param name="wmode" value="transparent" />  
<embed src="" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="369" height="178">  

Once it's loaded it'll call the delegate function which you music implement in your class. Notice I set htmlView.delgate = self. I do this because I want to launch the video once the page is loaded, because by default YouTube video's need to have the play button clicked before they launch in the MPMoviePlayerController object.

So here I scan through all the buttons in the webview and select the first button found using the sendActionsForControlEvents function.
 UIButton* findButtonInView(UIView* view)  
UIButton *button = nil;  
if( [view isMemberOfClass:[UIButton class]] )  
return (UIButton*)view;  

if( view.subviews && [view.subviews count] > 0 )  
for( UIView *subview in view.subviews )  
button = findButtonInView( subview );  
if( button )   
return button;  

return button;  

UIButton *button = findButtonInView( webView );  
if( button != nil )  
[button sendActionsForControlEvents:UIControlEventTouchUpInside];  

Great so far huh? But on return if you're using OpenAL, the sound no longer works. Eek. So what you have to do is, before launching the video you must make sure you call AudioSessionSetActive( NO ) and then AudioSessionSetActive( YES ) once the video has finished. I also found I had to destroy and recreate my OpenAL context and samples loaded, but I haven't looked too much into it, so if you find a way to reuse your OpenAL context and device, let me know.
 if( stoppingAudio )  
[audioManager destroy];  
AudioSessionSetActive( NO );  
else if( restartingAudio )  
AudioSessionSetActive( YES );  
[audioManager load:YES];  

That's it, you now can launch a YouTube video fullscreen in your app, without losing audio or having the YouTube application take over. Enjoy.